diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..8c05fbd --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,38 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Emulator configuration** + - Machine: [e.g. IBM AT, AMI 486 clone etc] + - CPU: + - Graphics/sound cards: + - Installed OS + +**Host machine** + - OS: [e.g. Windows 10, Ubuntu 18.04 etc] + - Emulator version + - Any other relevant information + +**Additional context** +Add any other context about the problem here. diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml new file mode 100644 index 0000000..80c06f5 --- /dev/null +++ b/.github/workflows/c-cpp.yml @@ -0,0 +1,201 @@ +name: C/C++ CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + - name: Ubuntu 64bit (gcc) + os: ubuntu-latest + args: --enable-networking --enable-release-build CFLAGS="-DPCEM_BUILD_VERSION=${GITHUB_SHA::8}" + artifacts_name: PCem-Ubuntu-${{ github.head_ref }}-${{ github.run_number }} + artifacts_path: PCem-${{ github.sha }}.tar.bz2 + installdeps: >- + libsdl2-dev + libopenal-dev + libwxgtk3.0-gtk3-dev + libncap-dev + - name: Windows 32bits (MSYS2) + os: windows-latest + compiler: MINGW32 + args: --enable-networking --enable-release-build CFLAGS="-DPCEM_BUILD_VERSION=${GITHUB_SHA::8}" + artifacts_name: PCem-Windows-MINGW32-${{ github.head_ref }}-${{ github.run_number }} + artifacts_path: PCem-${{ github.sha }}.zip + installdeps: >- + base-devel + zip + unzip + mingw-w64-i686-ntldd-git + mingw-w64-i686-toolchain + mingw-w64-i686-SDL2 + mingw-w64-i686-openal + mingw-w64-i686-wxWidgets + - name: Windows 64bits (MSYS2) + os: windows-latest + compiler: MINGW64 + args: --enable-networking --enable-release-build CFLAGS="-DPCEM_BUILD_VERSION=${GITHUB_SHA::8}" + artifacts_name: PCem-Windows-MINGW64-${{ github.head_ref }}-${{ github.run_number }} + artifacts_path: PCem-${{ github.sha }}.zip + installdeps: >- + base-devel + zip + unzip + mingw-w64-x86_64-ntldd-git + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-SDL2 + mingw-w64-x86_64-openal + mingw-w64-x86_64-wxWidgets + + runs-on: ${{ matrix.os }} + name: ${{ matrix.name }} + + steps: + - uses: actions/checkout@v2 + with: + path: temp + fetch-depth: 0 + + - name: Setup MSYS2 (Windows) + if: runner.os == 'Windows' + # You may pin to the exact commit or the version. + # uses: msys2/setup-msys2@a43b8403533fffe0c157dd8498f021ddec66bff7 + uses: msys2/setup-msys2@v2 + with: + # Variant of the environment to set by default: MSYS, MINGW32, MINGW64, UCRT64 or CLANG64 + msystem: ${{ matrix.compiler }} + # Retrieve and extract base installation from upstream GitHub Releases + release: false # optional, default is true + # Update MSYS2 installation through pacman + update: false + # Install packages after installation through pacman + install: ${{ matrix.installdeps }} + - name: npcap download (Windows) + if: runner.os == 'Windows' + shell: msys2 {0} + run: | + wget https://nmap.org/npcap/dist/npcap-sdk-1.05.zip + unzip -d npcap-sdk-1.05/ npcap-sdk-1.05.zip + cd npcap-sdk-1.05 + cp -r Include/* /mingw32/include/ + cp -r Include/* /mingw64/include/ + cp -r Lib/*.lib /mingw32/lib/ + cp -r Lib/x64/*.lib /mingw64/lib/ + - name: Setup ubuntu dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install ${{ matrix.installdeps }} + + # Copy all the sources to the dist folder, before we start generating intermediate files. + - name: prepare-package (Windows32) + if: runner.os == 'Windows' && matrix.compiler == 'MINGW32' + shell: msys2 {0} + run: | + mkdir dist + cp -R ./temp/* dist + rm -Rf ./dist/.git + cp /mingw32/bin/libdeflate.dll dist + cp /mingw32/bin/libexpat-1.dll dist + cp /mingw32/bin/libgcc_s_dw2-1.dll dist + cp /mingw32/bin/libjpeg-8.dll dist + cp /mingw32/bin/liblzma-5.dll dist + cp /mingw32/bin/libopenal-1.dll dist + cp /mingw32/bin/libpng16-16.dll dist + cp /mingw32/bin/libstdc++-6.dll dist + cp /mingw32/bin/libtiff-5.dll dist + cp /mingw32/bin/libwebp-7.dll dist + cp /mingw32/bin/libwinpthread-1.dll dist + cp /mingw32/bin/libzstd.dll dist + cp /mingw32/bin/SDL2.dll dist + cp /mingw32/bin/wxbase30u_gcc_custom.dll dist + cp /mingw32/bin/wxbase30u_xml_gcc_custom.dll dist + cp /mingw32/bin/wxmsw30u_adv_gcc_custom.dll dist + cp /mingw32/bin/wxmsw30u_core_gcc_custom.dll dist + cp /mingw32/bin/wxmsw30u_html_gcc_custom.dll dist + cp /mingw32/bin/wxmsw30u_xrc_gcc_custom.dll dist + cp /mingw32/bin/zlib1.dll dist + - name: prepare-package (Windows64) + if: runner.os == 'Windows' && matrix.compiler == 'MINGW64' + shell: msys2 {0} + run: | + mkdir dist + cp -R ./temp/* dist + rm -Rf ./dist/.git + cp /mingw64/bin/libdeflate.dll dist + cp /mingw64/bin/libexpat-1.dll dist + cp /mingw64/bin/libgcc_s_seh-1.dll dist + cp /mingw64/bin/libjpeg-8.dll dist + cp /mingw64/bin/liblzma-5.dll dist + cp /mingw64/bin/libopenal-1.dll dist + cp /mingw64/bin/libpng16-16.dll dist + cp /mingw64/bin/libstdc++-6.dll dist + cp /mingw64/bin/libtiff-5.dll dist + cp /mingw64/bin/libwebp-7.dll dist + cp /mingw64/bin/libwinpthread-1.dll dist + cp /mingw64/bin/libzstd.dll dist + cp /mingw64/bin/SDL2.dll dist + cp /mingw64/bin/wxbase30u_gcc_custom.dll dist + cp /mingw64/bin/wxbase30u_xml_gcc_custom.dll dist + cp /mingw64/bin/wxmsw30u_adv_gcc_custom.dll dist + cp /mingw64/bin/wxmsw30u_core_gcc_custom.dll dist + cp /mingw64/bin/wxmsw30u_html_gcc_custom.dll dist + cp /mingw64/bin/wxmsw30u_xrc_gcc_custom.dll dist + cp /mingw64/bin/zlib1.dll dist + - name: configure (Windows) + if: runner.os == 'Windows' + shell: msys2 {0} + run: | + cd temp + autoreconf -i + ./configure ${{ matrix.args }} + - name: make (Windows) + if: runner.os == 'Windows' + shell: msys2 {0} + run: | + cd temp + make -j + - name: package (Windows) + if: runner.os == 'Windows' + shell: msys2 {0} + run: | + cp ./temp/src/pcem.exe dist + cd dist + zip -r -9 ${{ matrix.artifacts_path }} * + + - name: prepare-package (Linux) + if: runner.os == 'Linux' + run: | + mkdir dist + cp -R ./temp/* dist + rm -Rf ./dist/.git + - name: configure (Linux) + if: runner.os == 'Linux' + run: | + cd temp + autoreconf -i + ./configure ${{ matrix.args }} + - name: make (Linux) + if: runner.os == 'Linux' + run: | + cd temp + make -j + - name: package (Linux) + if: runner.os == 'Linux' + run: | + cp ./temp/src/pcem dist + cd dist + tar -cjf ${{ matrix.artifacts_path }} * + + - name: "Upload GitHub Actions artifacts" + uses: actions/upload-artifact@v2 + with: + name: ${{ matrix.artifacts_name }} + path: ./dist/${{ matrix.artifacts_path }} + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b4c77b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +*.o +*.swp +/Makefile +/src/Makefile +autom4te.cache +config.log +config.status +.deps +.dirstamp +/pcem +/src/pcem diff --git a/Makefile.in b/Makefile.in index 78e714f..fa42541 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,7 +1,7 @@ -# Makefile.in generated by automake 1.15 from Makefile.am. +# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ -# Copyright (C) 1994-2014 Free Software Foundation, Inc. +# Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -89,8 +89,7 @@ build_triplet = @build@ host_triplet = @host@ subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/allegro.m4 \ - $(top_srcdir)/configure.ac +am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ @@ -134,7 +133,7 @@ am__recursive_targets = \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - cscope distdir dist dist-all distcheck + cscope distdir distdir-am dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is @@ -197,12 +196,13 @@ am__relativize = \ DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip +# Exists only to be overridden by the user if desired. +AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ -ALLEGRO_CONFIG = @ALLEGRO_CONFIG@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ @@ -243,18 +243,36 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +SDL2_CONFIG = @SDL2_CONFIG@ +SDL2_FRAMEWORK = @SDL2_FRAMEWORK@ +SDL_CFLAGS = @SDL_CFLAGS@ +SDL_LIBS = @SDL_LIBS@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ +WX_CFLAGS = @WX_CFLAGS@ +WX_CFLAGS_ONLY = @WX_CFLAGS_ONLY@ +WX_CONFIG_PATH = @WX_CONFIG_PATH@ +WX_CPPFLAGS = @WX_CPPFLAGS@ +WX_CXXFLAGS = @WX_CXXFLAGS@ +WX_CXXFLAGS_ONLY = @WX_CXXFLAGS_ONLY@ +WX_LIBS = @WX_LIBS@ +WX_LIBS_STATIC = @WX_LIBS_STATIC@ +WX_RESCOMP = @WX_RESCOMP@ +WX_VERSION = @WX_VERSION@ +WX_VERSION_MAJOR = @WX_VERSION_MAJOR@ +WX_VERSION_MICRO = @WX_VERSION_MICRO@ +WX_VERSION_MINOR = @WX_VERSION_MINOR@ 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@ @@ -326,8 +344,8 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/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);; \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) @@ -445,7 +463,10 @@ distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files -distdir: $(DISTFILES) +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ @@ -510,7 +531,7 @@ distdir: $(DISTFILES) ! -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 + tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir @@ -525,6 +546,10 @@ dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) +dist-zstd: distdir + tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst + $(am__post_remove_distdir) + dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @@ -536,7 +561,7 @@ dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 - shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir @@ -554,7 +579,7 @@ dist dist-all: distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ @@ -564,9 +589,11 @@ distcheck: dist *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ - GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ + *.tar.zst*) \ + zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) @@ -582,7 +609,7 @@ distcheck: dist $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ - && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ @@ -743,7 +770,7 @@ uninstall-am: am--refresh check check-am clean clean-cscope clean-generic \ cscope cscopelist-am ctags ctags-am dist dist-all dist-bzip2 \ dist-gzip dist-lzip dist-shar dist-tarZ dist-xz dist-zip \ - distcheck distclean distclean-generic distclean-tags \ + dist-zstd 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 \ diff --git a/README.md b/README.md new file mode 100644 index 0000000..e2dba29 --- /dev/null +++ b/README.md @@ -0,0 +1,397 @@ +# [PCem](https://pcem-emulator.co.uk/) +## Download: [Windows](https://pcem-emulator.co.uk/files/PCemV17Win.zip)/[Linux](https://pcem-emulator.co.uk/files/PCemV17Linux.tar.gz) + +Latest version: v17 [Changelog](https://pcem-emulator.co.uk/index.html) + +PCem is licensed under GPL v2.0, see [COPYING](COPYING) for more details. + +You can submit patches on our [forum](https://pcem-emulator.co.uk/phpBB3). Before you do, please note the [guidelines](https://pcem-emulator.co.uk/phpBB3/viewtopic.php?f=3&t=5) for submitting patches. + +:exclamation: Note: NO COPYRIGHTED ROM FILES ARE INCLUDED NOR WILL THEY BE. PLEASE DO NOT ASK FOR THEM. + +## BSD and Linux supplement (v17) + +You will need the following libraries (and their dependencies): +- SDL2 +- wxWidgets 3.x +- OpenAL + +Open a terminal window, navigate to the PCem directory then enter: +### Linux +``` +./configure --enable-release-build +make +``` +### BSD +``` +./configure --enable-release-build +gmake +``` + +then `./pcem` to run. + +The Linux/BSD versions store BIOS ROM images, configuration files, and other data in `~/.pcem` + +configure options are : +``` + --enable-release-build : Generate release build. Recommended for regular use. + --enable-debug : Compile with debugging enabled. + --enable-networking : Build with networking support. + --enable-alsa : Build with support for MIDI output through ALSA. Requires libasound. +``` + +The menu is a pop-up menu in the Linux/BSD port. Right-click on the main window when mouse is not +captured. + +CD-ROM support currently only accesses `/dev/cdrom`. It has not been heavily tested. + +## Links + +### PCem emulates the following hardware (as of v17): + +Hardware | Links +--- | --- +Systems | [8088](#8088-based)
[8086](#8086-based)
[286](#286-based)
[386](#386-based)
[486](#486-based)
[Pentium](#pentium-based)
[Super Socket 7](#super-socket-7-based) +Graphics | [Basic](#basic-cards)
[Unaccelerated (S)VGA cards](#unaccelerated-svga-cards)
[2D accelerated SVGA cards](#2d-accelerated-svga-cards)
[3D accelerated SVGA cards](#3d-accelerated-svga-cards)
[3D only cards](#3d-only-cards) +Sound | [Cards](#sound-cards) +HDD Controller | [Cards](#hdd-controller-cards) +Misc | [Cards](#misc-cards) + +### [Software Tested](TESTED.md) (list) +- [DOS](TESTED.md#dos)
+- [Windows](TESTED.md#windows)
+- [Windows NT](TESTED.md#windows-nt)
+- [OS/2](TESTED.md#os2)
+- [Linux](TESTED.md#linux)
+- [Applications](TESTED.md#applications)
+- [Games](TESTED.md#games)
+- [Demos](TESTED.md#demos)
+- [Emulators](TESTED.md#emulators)
+ +
+ +## Systems + +### 8088 based +Release | Machine | ROM file needed
(within ./roms/ folder) +:-: | --- | --- +1981 | IBM PC
8088 at 4.77 MHz
16KB - 640KB RAM (min. 64KB) | ibmpc/pc102782.bin
ibmpc/basicc11.f6
ibmpc/basicc11.f8
ibmpc/basicc11.fa
ibmpc/basicc11.fc +1983 | Compaq Portable Plus
8088 at 4.77 MHz
128KB - 640KB RAM | compaq_pip/Compaq Portable Plus 100666-001 Rev C.bin +1983 | IBM XT
8088 at 4.77 MHz
64KB - 640KB RAM | ibmxt/5000027.u19
ibmxt/1501512.u18 +1983 | Leading Edge Model M
8088 at 7.16 MHz
128KB - 704KB RAM | leadingedge_modelm/Leading Edge - Model M - BIOS ROM - Version 4.71.bin +1984 | IBM PCjr [[5]](#system-note-5)
8088 at 4.77 MHz
64KB - 640KB RAM (min. 128KB)
Built-in 16 colour graphics
3 voice sound
Not generally PC compatible. | ibmpcjr/bios.rom +1984 | Tandy 1000 [[5]](#system-note-5)
8088 at 4.77 MHz
128KB - 640KB RAM
Built-in 16 colour graphics
3 voice sound | tandy/tandy1t1.020 +1985 | NCR PC4i
8088 at 4.77 MHz
256KB - 640KB RAM | ncr_pc4i/NCR_PC4i_BIOSROM_1985.BIN +1986 | DTK Clone XT
8088 at 8/10 MHz
64KB - 640KB RAM | dtk/dtk_erso_2.42_2764.bin +1986 | Phoenix XT clone
8088 at 8/10 MHz
64KB - 640KB RAM | pxxt/000p001.bin +1987 | Tandy 1000HX
8088 at 7.16 MHz
256KB - 640KB RAM
Built-in 16 colour graphics
3 voice sound
Has DOS 2.11 in ROM | tandy1000hx/v020000.u12 +1987 | Thomson TO16 PC
8088 at 9.54 MHz
512KB - 640KB RAM | to16_pc/TO16_103.bin +1987 | Toshiba T1000 [[1]](#system-note-1) [[5]](#system-note-5)
8088 at 4.77 MHz
512KB - 1024KB RAM
CGA on built-in LCD | t1000/t1000.rom
t1000/t1000font.rom +1987 | VTech Laser Turbo XT
8088 at 10 MHz
640KB RAM | ltxt/27c64.bin +1987 | Zenith Data SupersPort
8088 at 8 MHz
128KB - 640KB RAM
Built-in LCD video is not currently emulated | zdsupers/z184m v3.1d.10d +1988? | ©Anonymous Generic Turbo XT BIOS
8088 at 8+ MHz
64KB - 640KB RAM | genxt/pcxt.rom +1988 | Atari PC3
8088 at 8 MHz
640KB RAM | ataripc3/AWARD_ATARI_PC_BIOS_3.08.BIN +1988 | Juko XT clone | jukopc/000o001.bin +1988 | Schneider Euro PC
8088 at 9.54 MHz
512KB - 640KB RAM | europc/50145
europc/50146 +1989 | AMI XT clone
8088 at 8+ MHz
64KB - 640KB RAM | amixt/ami_8088_bios_31jan89.bin +2015 | Xi8088
8088 at 4.77-13.33 MHz
640KB RAM | xi8088/bios-xi8088.bin + +### 8086 based +Release | Machine | ROM file needed
(within ./roms/ folder) +:-: | --- | --- +1984 | Compaq Deskpro
8086 at 8 MHz
128KB - 640KB RAM | deskpro/Compaq - BIOS - Revision J - 106265-002.bin +1984 | Olivetti M24 [[5]](#system-note-5)
8086 at 8 MHz
128KB - 640KB RAM
Built-in enhanced CGA (supports 640x400x2) | olivetti_m24/olivetti_m24_version_1.43_low.bin
olivetti_m24/olivetti_m24_version_1.43_high.bin +1986 | Amstrad PC1512 [[5]](#system-note-5)
8086 at 8 MHz
512KB - 640KB RAM
Enhanced CGA (supports 640x200x16)
Custom mouse port | pc1512/40043.v1
pc1512/40044.v2
pc1512/40078.ic127 +1987 | Amstrad PC1640 [[5]](#system-note-5)
8086 at 8 MHz
640KB RAM
Built-in Paradise EGA
Custom mouse port | pc1640/40043.v3
pc1640/40044.v3
pc1640/40100 +1987 | Toshiba T1200 [[1]](#system-note-1) [[5]](#system-note-5)
8086 at 9.54 MHz
1MB - 2MB RAM
CGA on built-in LCD | t1200/t1200_019e.ic15.bin
t1200/t1000font.rom +1988 | Amstrad PPC512/640 [[5]](#system-note-5)
8086 at 8 MHz
512KB - 640KB RAM
Built-in CGA w/ plasma display | ppc512/40107.v2
ppc512/40108.v2
ppc512/40109.bin +1988 | Sinclair PC200/Amstrad PC20 [[5]](#system-note-5)
8086 at 8 MHz
512KB - 640KB RAM
Built-in CGA (supports TV-out 50hz PAL) | pc200/pc20v2.0
pc200/pc20v2.1
pc200/40109.bin +1988 | VTech Laser XT3
8086 at 10 MHz
512KB - 1152KB RAM | lxt3/27c64d.bin +1989 | Amstrad PC2086 [[5]](#system-note-5)
8086 at 8 MHz
640KB RAM
Built-in VGA | pc2086/40179.ic129
pc2086/40180.ic132
pc2086/40186.ic171 +1989 | Tandy 1000SL/2 [[5]](#system-note-5)
8086 at 9.54 MHz
512KB - 768KB RAM
Built-in 16 colour graphics
4 voice sound | tandy1000sl2/8079047.hu1
tandy1000sl2/8079048.hu2 +1990 | Amstrad PC3086 [[5]](#system-note-5)
8086 at 8 MHz
640KB RAM
Built-in VGA | pc3086/fc00.bin
pc3086/c000.bin +1991 | Amstrad PC5086
8086 at 8 MHz
640KB RAM | pc5086/sys_rom.bin + +### 286 based +Release | Machine | ROM file needed
(within ./roms/ folder) +:-: | --- | --- +1984 | IBM AT
286 at 6 or 8 MHz
256KB - 16MB RAM | ibmat/at111585.0
ibmat/at111585.1 +1986 | Compaq Portable II
286 at 8 MHz
256KB - 15MB RAM | compaq_pii/109739-001.rom
compaq_pii/109740-001.rom +1986 | IBM XT Model 286
286 at 6 MHz
256KB - 16MB RAM | ibmxt286/BIOS_5162_21APR86_U34_78X7460_27256.BIN
ibmxt286/BIOS_5162_21APR86_U35_78X7461_27256.BIN +1986 | Toshiba T3100e [[1]](#system-note-1) [[5]](#system-note-5)
286 at 12 MHz
1MB - 5MB RAM
CGA on gas-plasma display | t3100e/t3100e_font.bin
t3100e/t3100e.rom +1987 | IBM PS/2 Model 50 [[5]](#system-note-5)
286 at 10 MHz
1MB - 16MB RAM
Built-in VGA
MCA bus | i8550021/90x7420.zm13
i8550021/90x7423.zm14
i8550021/90x7426.zm16
i8550021/90x7429.zm18 +1988 | Bull Micral 45
286 at 12 MHz
1MB - 6MB RAM | bull_micral_45/even.fil
bull_micral_45/odd.fil +1988 | Commodore PC30-III
286 at 12 MHz
512KB - 16MB RAM | cmdpc30/commodore pc 30 iii even.bin
cmdpc30/commodore pc 30 iii odd.bin +1988 | IBM PS/2 Model 30-286
286 at 10 MHz
1MB - 16MB RAM
Built-in VGA
MCA bus | ibmps2_m30_286/33f5381a.bin +1989 | Epson PC AX
286
256KB - 16MB RAM | epson_pcax/EVAX
epson_pcax/ODAX +1989 | Epson PC AX2e
286 at 12 MHz
256KB - 16MB RAM | epson_pcax2e/EVAX
epson_pcax2e/ODAX +1990 | AMI 286 clone
286 at 8+ MHz
512KB - 16MB RAM | ami286/amic206.bin +1990 | Award 286 clone
286 at 8+ MHz
512KB - 16MB RAM | award286/award.bin +1990 | Dell System 200
286 at 12 MHz
640KB - 16MB RAM | dells200/dell0.bin
dells200/dell1.bin +1990 | IBM PS/1 Model 2011 [[5]](#system-note-5)
286 at 10 MHz
512KB - 16MB RAM
Built-in VGA
DOS 4.01 + GUI menu system in ROM | ibmps1/f80000.bin +? | Goldstar GDC-212M
286 at 12 MHz
512KB - 4MB RAM | gdc212m/gdc212m_72h.bin +? | GW-286CT GEAR
286 at 8+ MHz
512KB - 16MB RAM | gw286ct/2ctc001.bin +? | Hyundai Super-286TR
286 at 12 MHz
1MB - 4MB RAM | super286tr/award.bin +? | Samsung SPC-4200P
286 at 12 MHz
512KB - 2MB RAM | spc4200p/u8.01 +? | Samsung SPC-4216P
286 at 12 MHz
1MB - 5MB RAM | spc4216p/phoenix.bin
   or
spc4216p/7101.u8
spc4216p/ac64.u10 +? | Samsung SPC-4620P
286 at 12 MHz
1MB - 5MB RAM
Built-in Korean ATI-28800 | spc4620p/31005h.u8
spc4620p/31005h.u10
spc4620p/svb6120a_font.rom
spc4620p/31005h.u8
spc4620p/31005h.u10 +? | Tulip AT Compact
286
640KB - 16MB RAM | tulip_tc7/tc7be.bin
tulip_tc7/tc7bo.bin + +### 386 based +Release | Machine | ROM file needed
(within ./roms/ folder) +:-: | --- | --- +1987 | IBM PS/2 Model 80 [[5]](#system-note-5)
386DX at 20 MHz
1MB - 12MB RAM
Built-in VGA
MCA bus | i8580111/15f6637.bin
i8580111/15f6639.bin +1988 | ECS 386/32
386DX at 20 MHz
1MB - 16MB RAM | ecs386_32/386_32_even.bin
ecs386_32/386_32_odd.bin +1989 | IBM PS/2 Model 70 (type 3) [[5]](#system-note-5)
386DX at 25 MHz
2MB - 16MB RAM
Built-in VGA
MCA bus | ibmps2_m70_type3/70-a_even.bin
ibmps2_m70_type3/70-a_odd.bin +1989 | Compaq Deskpro 386
386DX at 20 MHz
1MB - 15MB RAM | deskpro386/109592-005.u11.bin
deskpro386/109591-005.u13.bin +1989 | Epson PC AX3
386SX at 16 MHz
256KB - 16MB RAM | epson_pcax3/EVAX3
epson_pcax3/ODAX3 +1989 | IBM PS/2 Model 55SX
386SX at 16 MHz
1MB - 8MB RAM
Built-in VGA
MCA bus | i8555081/33f8146.zm41
i8555081/33f8145.zm40 +1990 | DTK 386SX clone
386SX
512KB - 16MB RAM | dtk386/3cto001.bin +1990 | IBM PS/1 Model 2121 [[5]](#system-note-5)
386SX at 20 MHz
1MB - 16MB RAM
Built-in VGA | ibmps1_2121/fc0000.bin +1990 | Samsung SPC-6000A
386DX
1MB - 32 MB RAM | spc6000a/3c80.u27
spc6000a/9f80.u26 +1992 | Acermate 386SX/25N [[5]](#system-note-5)
386SX at 25 MHz
2MB - 16MB RAM
Built-in Oak SVGA | acer386/acer386.bin
acer386/oti067.bin +1992 | Amstrad MegaPC [[2]](#system-note-2) [[5]](#system-note-5)
386SX at 25 MHz
1MB - 16MB RAM
Built-in VGA
| megapc/41651-bios lo.u18
megapc/211253-bios hi.u19 +1992 | Commodore SL386SX-25 [[5]](#system-note-5)
386SX at 25 MHz
1MB - 16MB RAM
Built-in AVGA2 | cbm_sl386sx25/f000.bin
cbm_sl386sx25/c000.bin +1992 | Packard Bell Legend 300SX
386SX at 16 MHz
1MB - 16MB RAM | pb_l300sx/pb_l300sx.bin +1992 | Samsung SPC-6033P
386SX at 33 MHz
2MB - 12 MB RAM | spc6033p/phoenix.bin
spc6033p/svb6120a_font.rom +1994 | AMI 386DX clone
386DX at 40 MHz
1MB - 32MB RAM | ami386dx/opt495sx.ami +1994 | AMI 386SX clone
386SX at 25 MHz
1MB - 16MB RAM | ami386/ami386.bin +1994 | MR 386DX clone
This is a generic 386DX clone with an MR BIOS | mr386dx/opt495sx.mr +? | KMX-C-02
386SX
512KB - 16MB RAM | kmxc02/3ctm005.bin + +### 486 based +Release | Machine
(+ addl. hardware) | CPU(s) Supported | ROM file needed
(within ./roms/ folder) +:-: | --- | --- | --- +1990 | IBM PS/2 Model 70 (type 4) [[3]](#system-note-3)
2MB - 16MB RAM
Built-in VGA
MCA bus | 486DX at 25 MHz | ibmps2_m70_type3/70-a_even.bin
ibmps2_m70_type3/70-a_odd.bin +1993 | AMI 486 clone
1MB - 32MB RAM | 486 at 16-66 MHz | ami486/ami486.bin +1993 | Elonex PC-425X [[5]](#system-note-5)
1MB - 256MB RAM
Built-in Trident TGUI9440CXi | 486SX at 25 MHz | elx_pc425x/elx_pc425x.bin
   or
elx_pc425x/elx_pc425x_bios.bin
elx_pc425x/elx_pc425x_vbios.bin +1993 | IBM PS/1 Model 2133 (EMEA 451)
2MB - 64MB RAM
Built-in Cirrus Logic GD5426 | 486SX at 25 MHz | ibmps1_2133/PS1_2133_52G2974_ROM.bin +1993 | Packard Bell PB410A [[5]](#system-note-5)
1MB - 64MB RAM
Built-in HT-216 video | 486 at 25-120 MHz
Am5x86 at 133-160 MHz
Cx5x86 at 100-133 MHz
Pentium Overdrive at 63-83 MHz | pb410a/PB410A.080337.4ABF.U25.bin +1994 | AMI WinBIOS 486 clone
1MB - 32MB RAM | 486 at 16-66 MHz | win486/ali1429g.amw +1995 | Award SiS 496/497
1MB - 64MB RAM | 486 at 16-120 MHz
Am5x86 at 133-160 MHz
Cx5x86 at 100-133 MHz
Pentium Overdrive at 63-83 MHz | sis496/sis496-1.awa + +### Pentium based +Release | Machine
(+ addl. hardware) | CPU(s) Supported | ROM file needed
(within ./roms/ folder) +:-: | --- | --- | --- +1994 | Intel Premiere/PCI (Batman's Revenge)
1MB - 128MB RAM | Pentium at 60-66 MHz
Pentium Overdrive at 120-133 MHz | revenge/1009af2_.bi0
revenge/1009af2_.bi1 +1995 | Intel Advanced/EV (Endeavor) [[4]](#system-note-4)
1MB - 128MB RAM | Pentium at 75-133 MHz
Pentium Overdrive at 125-200 MHz | endeavor/1006cb0_.bi0
endeavor/1006cb0_.bi1 +1995 | Intel Advanced/ZP (Zappa)
1MB - 128MB RAM | Pentium at 75-133 MHz
Pentium Overdrive at 125-200 MHz | zappa/1006bs0_.bio
zappa/1006bs0_.bi1 +1995 | Packard Bell PB520R (Robin LC) [[5]](#system-note-5)
1MB - 128MB RAM
Built-in Cirrus Logic GD-5434 | Pentium at 60-66 MHz
Pentium Overdrive at 120-133 MHz | pb520r/1009bc0r.bio
pb520r/1009bc0r.bi1
pb520r/gd5434.bin +1995 | Packard Bell PB570 (Hillary) [[5]](#system-note-5)
1MB - 128MB RAM
Built-in Cirrus Logic GD-5430 | Pentium at 75-133 MHz
Pentium Overdrive at 125-200 MHz | pb570/1007by0r.bio
pb570/1007by0r.bi1
pb570/gd5430.bin +1996 | ASUS P/I-P55TVP4
1MB - 128MB RAM | Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT Winchip 2 at 200-240 MHz
IDT Winchip 2A at 200-233 MHz
AMD K6 at 166-300 MHz
AMD K6-2 (AFR-66) at 233-300 MHz | p55tvp4/tv5i0204.awd +1996 | ASUS P/I-P55T2P4
1MB - 512MB RAM | Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT Winchip 2 at 200-240 MHz
IDT Winchip 2A at 200-233 MHz
AMD K6 at 166-300 MHz
AMD K6-2 (AFR-66) at 233-300 MHz | p55t2p4/0207_j2.bin +1996 | Award 430VX PCI
1MB - 128MB RAM | Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT Winchip 2 at 200-240 MHz
IDT Winchip 2A at 200-233 MHz
AMD K6 at 166-300 MHz
AMD K6-2 (AFR-66) at 233-300 MHz | 430vx/55xwuq0e.bin +1996 | Itautec Infoway Multimidia
8MB - 128MB RAM | Pentium at 75-133 MHz
Pentium Overdrive at 125-200 MHz | infowaym/1006bs0_.bio
infowaym/1006bs0_.bi1 +1997 | Epox P55-VA
1MB - 128MB RAM | Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT Winchip 2 at 200-240 MHz
IDT Winchip 2A at 200-233 MHz
AMD K6 at 166-300 MHz
AMD K6-2 (AFR-66) at 233-300 MHz | p55va/va021297.bin + +### Super Socket 7 based +Release | Machine
(+ addl. hardware) | CPU(s) Supported | ROM file needed
(within ./roms/ folder) +:-: | --- | --- | --- +1998 | FIC VA-503+
1MB - 512MB RAM | AMD K6 at 166-300 MHz
AMD K6-2 at 233-550 MHz
AMD K6-2+ at 450-550 MHz
AMD K6-III at 400-450 MHz
AMD K6-III+ at 400-500 MHz
Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT WinChip2 at 200-250 MHz
IDT Winchip 2A at PR200(200 MHz)-PR300(250 MHz) | fic_va503p/je4333.bin + +### Socket 8 based +Release | Machine
(+ addl. hardware) | CPU(s) Supported | ROM file needed
(within ./roms/ folder) +:-: | --- | --- | --- +1996 | Intel VS440FX
8MB - 256 MB RAM | Pentium Pro at 150-200 MHz
Pentium II Overdrive at 300-333 MHz | vs440fx/1018CS1_.BI1
vs440fx/1018CS1_.BI2
vs440fx/1018CS1_.BI3
vs440fx/1018CS1_.BIO
vs440fx/1018CS1_.RCV + +### Slot 1 based +Release | Machine
(+ addl. hardware) | CPU(s) Supported | ROM file needed
(within ./roms/ folder) +:-: | --- | --- | --- +1998 | Gigabyte GA-686BX
8MB - 512MB RAM | Pentium II at 233-450 MHz
Celeron at 266-533 MHz
Cyrix IIIat 500 MHz | ga686bx/6BX.F2a + +#### Additional Notes +`[1]` Toshiba Button Mapping: +PCem maps [Fn] to `right-Ctrl` and `right-Alt`. The following functions are supported: +Key Combo | Function +---|--- +Fn + Num Lock | toggle numpad +Fn + Home | Internal LCD display +Fn + Page Down | Turbo on +Fn + Right | Toggle LCD font +Fn + End | External CRT display +Fn + SysRQ | Toggle window + +`[2]` Amstrad MegaPC (386SX): The original machine had a built-in Sega MegaDrive. This is not emulated in PCem. + +`[3]` IBM PS/2 Model 70 (type 4) (486DX): PCem's FPU emulation is not bit accurate and can not pass IBM's floating point tests. As a result, this machine will always print 12903 and 162 errors on bootup. These can be ignored - F1 will boot the machine. + +`[4]` Intel Advanced/EV (Endeavor) (Pentium): The real board has a Sound Blaster 16 onboard and optionally an S3 Trio64V+. Neither are emulated as onboard devices. + +`[5]` Some systems have fixed graphics adapters:
+** = Can use external video card.
+ +System | Graphics | Addl. Info | ** +--- | --- | --- | :-: +Amstrad MegaPC | Paradise 90C11 | A development of the PVGA1 with 512KB VRAM | ✔ +Acer 386SX/25N | Oak OTI-067 | Another 512KB SVGA clone | ✔ +Amstrad PC1512 | CGA | Has a new mode (640x200x16) | X +Amstrad PC1640 | Paradise EGA |   | ✔ +Amstrad PC2086/PC3086 | Paradise PVGA1 | An early SVGA clone with 256KB VRAM | ✔ +Amstrad PPC512/640 | CGA/MDA | Outputs to 640x200 plasma display | ✔ +Commodore SL386SX-25 | AVGA2 | 256KB - 512KB VRAM | X +Elonex PC-425X | Trident TGUI9400CXi | 512KB VRAM | X +IBM PCjr | CGA | Has various new modes:
160x200 x 16
320x200 x 16
640x200 x 4 | X +IBM PS/1 Model 2011 | Stock VGA | 256KB VRAM | X +IBM PS/1 Model 2121 | Basic (and unknown) SVGA | 256KB VRAM | X +IBM PS/2 machines | Stock VGA | 256KB VRAM | X +Olivetti M24 [[6]](#system-note-6)| CGA | Has double-res text modes + 640x400 mode | X +Packard Bell PB410A | Headland HT-216 |   | ✔ +Packard Bell PB520R | Cirrus Logic GD-5434 |   | ✔ +Packard Bell PB570 | Cirrus Logic GD-5430 |   | ✔ +Sinclair PC200 | CGA | Can output to TV @ 50hz (UK) | ✔ +Tandy 1000 | Clone of PCjr video | Widely supported in 80s games | X +Tandy 1000 SL/2 | Improved Tandy 1000 | Has support for 640x200x16 | X +Toshiba T-series | CGA | Outputs to built-in LCD or plasma display | X + +`[6]` Olivetti M24 (display): 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. + +
+ +## Graphics Cards + +### Basic cards +Hardware | Addl. Info | ROM file needed
(within ./roms/ folder) +--- | --- | --- +MDA (1981) | 80x25 monochrome text | (none) +CGA (1981) | 40x25 and 80x25 text
320x200 in 4 colours
620x200 in 2 colours
Supports composite output for ~16 colours. | (none) +Hercules (1982) | 80x25 monochrome text
720x348 in monochrome | (none) +Plantronics ColorPlus | An enhanced CGA board with support for 320x200x16 and 640x200x4 | (none) +Wyse WY-700 | A CGA-compatible board with support for a 1280x800 mode | (none) +MDSI Genius | Mono portrait board with support for a 728x1008 mode | 8x12.bin +IBM EGA (1984) | Text up to 80x43
Graphics up to 640x350 in 16 colours | ibm_6277356_ega_card_u44_27128.bin +ATI EGA Wonder 800+ | An enhanced EGA-compatible board with support for up to 800x600 in 16 colours | ATI EGA Wonder 800+ N1.00.BIN +Hercules InColor | An enhanced Hercules with a custom 720x350 16 colour mode | (none) + +### Unaccelerated (S)VGA cards +Hardware | Addl. Info | ROM file needed
(within ./roms/ folder) +--- | --- | --- +ATI Korean VGA | ATI-28800 based.
512KB VRAM
Supports up to 8-bit colour
Korean font support | atikorvga.bin
ati_ksc5601.rom +ATI VGA Edge-16 | ATI-18800 based
512KB VRAM
Supports up to 8-bit colour | vgaedge16.vbi +ATI VGA Charger | ATI-28800 based
512KB VRAM
Supports up to 8-bit colour | bios.bin +AVGA2 | Also known as Cirrus Logic GD5402
256KB - 512KB VRAM
Supports up to 8-bit colour | avga2vram.vbi +IBM VGA (1987) | 256KB VRAM
Text up to 80x50
Graphics up to 320x200 in 256 colours or 640x480 in 16 colours | ibm_vga.bin +Kasan Hangulmadang-16 | ET4000AX based
1MB VRAM
Supports up to 8-bit colour
Korean font support | et4000_kasan16.bin
kasan_ksc5601.rom +OAK OTI-037C | 256KB VRAM
Supports up to 8-bit colour | oti037/bios.bin +OAK OTI-067 | 256KB - 512KB VRAM
Supports up to 8-bit colour | oti067/bios.bin +Olivetti GO481 (Paradise PVGA1A) | 256KB VRAM
Supports up to 8-bit colour | oli_go481_lo.bin
oli_go481_hi.bin +Trident 8900D SVGA | 256KB - 1MB VRAM
Supports up to 24-bit colour | trident.bin +Trident 9000B SVGA | 512KB VRAM
Supports up to 8-bit colour | tvga9000b/BIOS.BIN +Trident TGUI9400CXi | 1MB - 2MB VRAM
Supports up to 24-bit colour | 9440.vbi +Trigem Korean VGA | ET4000AX based
1MB VRAM
Supports up to 8-bit colour
Korean font support | tgkorvga.bin
tg_ksc5601.rom +Tseng ET4000AX SVGA | 1MB VRAM
Supports up to 8-bit colour | et4000.bin + +### 2D Accelerated SVGA cards +Hardware | Addl. Info | ROM file needed
(within ./roms/ folder) +--- | --- | --- +ATI Graphics Pro Turbo | Mach64GX based
1MB - 4MB VRAM | mach64gx/bios.bin +ATI Video Xpression | Mach64VT2 based
2MB - 4MB VRAM
Has video acceleration | atimach64vt2pci.bin +Cirrus Logic GD-5428 | 1MB - 2MB VRAM | Machspeed_VGA_GUI_2100_VLB.vbi +Cirrus Logic GD-5429 | 1MB - 2MB VRAM | 5429.vbi +Cirrus Logic GD-5430 | 1MB - 2MB VRAM | gd5430/pci.bin +Cirrus Logic GD-5434 [[1]](#graphics-note-1) | 2MB - 4MB VRAM | gd5434.bin +Diamond Stealth 32 SVGA | ET4000/W32p based
1MB - 2MB VRAM | et4000w32.bin +IBM 1MB SVGA Adapter/A | Cirrus Logic GD5428 based
1 MB VRAM
Only supported on PS/2 models | SVGA141.ROM +Number Nine 9FX | S3 Trio64 based
1MB - 2MB VRAM | s3_764.bin +Paradise Bahamas 64 | S3 Vision864 based
1MB - 4MB VRAM | bahamas64.bin +Phoenix S3 Trio32 | S3 Trio32 based
512KB - 2MB VRAM | 86c732p.bin +Phoenix S3 Trio64 | S3 Trio64 based
1MB - 4MB VRAM | 86c764x1.bin +Trident TGUI9440 | 1MB - 2MB VRAM | 9440.vbi + +### 3D Accelerated SVGA cards +Hardware | Addl. Info | ROM file needed
(within ./roms/ folder) +--- | --- | --- +3DFX Voodoo Banshee (reference) | Voodoo Banshee based
8MB - 16MB VRAM | pci_sg.rom +3DFX Voodoo 3 2000 | Voodoo 3 based
16MB VRAM | voodoo3_2000/2k11sd.rom +3DFX Voodoo 3 3000 | Voodoo 3 based
16MB VRAM | voodoo3_3000/3k12sd.rom +Creative Labs 3D Blaster Banshee | Voodoo Banshee based
16MB VRAM | blasterpci.rom +Diamond Stealth 3D 2000 [[2]](#graphics-note-2)| S3 ViRGE/325 based
2MB - 4MB VRAM | s3virge.bin +S3 ViRGE/DX [[3]](#graphics-note-3)| S3 ViRGE/DX based
2MB - 4MB VRAM | 86c375_1.bin + +### 3D only cards +Hardware | Addl. Info +--- | --- +3DFX Voodoo Graphics [[4]](#graphics-note-4)| 3D accelerator. Widely supported in late 90s games. +Obsidian SB50 [[5]](#graphics-note-5)| Voodoo with 2 TMUs +3DFX Voodoo 2 [[6]](#graphics-note-6)| Improved Voodoo Graphics
Higher clocks
2 TMUs
Triangle setup, etc. + +#### Additional Notes +`[1]` Cirrus Logic GD-5434: Real chip also supports 1MB configurations, however this is not currently supported in PCem. + +`[2]` Diamond Stealth 3D 2000: 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. + +`[3]` S3 ViRGE/DX: 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). + +`[4]` 3DFX Voodoo Graphics: PCem emulates this in software. The emulation is a lot faster than in v10 (thanks to a new dynamic recompiler) and should be capable of hitting Voodoo 1 performance on most machines when two render threads are used. As before, the emulated CPU is the bottleneck for most games.

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. + +`[5]` Obsidian SB50: Drivers for this are a bit limited - the official drivers don't support 2 TMUs in Direct3D. + +`[6]` 3DFX Voodoo 2: PCem can emulate both 8 and 12 MB configurations. It can also emulate 6 and 10 MB configurations (with 2MB framebuffer memory), which were never sold into the PC market but do exist for arcade systems. + +
+ +## Sound Cards + +Hardware | Notes +--- | --- +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). PCem emulates the differences between the SN76496 (PCjr and Tandy 1000), and the NCR8496 (currently assigned to the Tandy 1000HX). Maniac Mansion and Zak McKraken will only sound correct on the latter. +Tandy PSSJ | Used on the Tandy 1000SL/2, this clones the NCR8496, adding an addition frequency divider (did any software actually use this?) and an 8-bit DAC. +PS/1 audio card | An SN76496 clone plus an 8-bit DAC. The SN76496 isn't at the same address as PCjr/Tandy, so most software doesn't support it. +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). The surround module is now emulated. +Sound Blaster [[1]](#sound-note-1) | See linked note for more details. +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) +Aztech Sound Galaxy Pro 16 AB (Washington) | SB compatible + WSS compatible +Innovation SSI-2001 | SID6581. Emulated using resid-fp. Board is fixed to port 280. +Ensoniq AudioPCI (ES1371)
Sound Blaster PCI 128
| Basic PCI sound card. Emulates Sound Blaster in software. + +### Additional Notes +`[1]` 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 cards 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. + +
+ +## HDD Controller Cards + +Int. | Hardware | Notes | ROM file needed
(within ./roms/ folder) +:-: | --- | --- | ---- +MFM | Fixed Disk Adapter (Xebec) | MFM controller originally included in the IBM XT. This controller only supports HD types 0, 2, 13, and 16. | ibm_xebec_62x0822_1985.bin +MFM | DTC 5150X | 8-bit MFM controller.
To configure drive types, run `DEBUG.EXE` and enter `g=c800:5`. | dtc_cxd21a.bin +MFM | AT Fixed Disk Adapter | MFM controller originally included in the IBM AT. Supported by all AT-compatible BIOSes. | (none) +ESDI | Western Digital WD1007V-SE1 | 16-bit ESDI controller | 62-000279-061.bin +ESDI | IBM ESDI Fixed Disk Controller | MCA ESDI controller. Only supported on PS/2 models. | 90x8969.bin
90x8970.bin +IDE | Standard IDE | Standard IDE controller. Supported by all AT-compatible BIOSes. Use this if in any doubt! | (none) +IDE | XTIDE | 8-bit IDE controller. The BIOS is available [here](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. | ide_xt.bin +IDE | XTIDE (AT) | 16-bit IDE controller. | ide_at.bin +IDE | XTIDE (PS/1) | IDE controller for the PS/1 model 2033. For this machine you will need BIOS version 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. | ide_at_1_1_5.bin +SCSI | Longshine LCS-6821N | 8-bit SCSI controller. | Longshine LCS-6821N - BIOS version 1.04.bin +SCSI | Rancho RT1000B | 8-bit SCSI controller. | Rancho_RT1000_RTBios_version_8.10R.bin +SCSI | Trantor T130B | 8-bit SCSI controller. | trantor_t130b_bios_v2.14.bin +SCSI | IBM SCSI Adapter with Cache | MCA SCSI controller. Only supported on PS/2 models. | 92F2244.U68
92F2245.U69 +SCSI | Adaptec AHA-1542C | 16-bit SCSI controller. | adaptec_aha1542c_bios_534201-00.bin +SCSI | BusLogic BT-545S | 16-bit SCSI controller. | BusLogic_BT-545S_U15_27128_5002026-4.50.bin + +
+ +## Misc Cards + +Hardware | Note +--- | --- +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 standard 2 button PS/2 mouse. As with serial, compatible drivers are common. +Microsoft PS/2 Intellimouse | A PS/2 mouse with mouse wheel. +ATAPI CD-ROM | Works with OAKCDROM.SYS, VDD-IDE.SYS, and the internal drivers of every OS I've tried. diff --git a/Readme-LINUX.txt b/Readme-LINUX.txt deleted file mode 100644 index c3aff39..0000000 --- a/Readme-LINUX.txt +++ /dev/null @@ -1,31 +0,0 @@ -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/TESTED.md b/TESTED.md new file mode 100644 index 0000000..d7ae6e5 --- /dev/null +++ b/TESTED.md @@ -0,0 +1,330 @@ +## Software tested (v17): + +### DOS +- PC-DOS 1.0 +- MS-DOS 2.11 +- MS-DOS 3.30 +- MS-DOS 4.01 +- MS-DOS 5.0 +- MS-DOS 6.0 +- MS-DOS 6.22 + +### Windows +- Windows 1.04 +- Windows/286 2.11 +- Windows/386 2.11 +- Windows 3.0 +- Windows 3.1 +- Windows for Workgroups 3.11 +- Windows 95 +- Windows 95 OSR2 +- Windows 98SE +- Windows ME + +### Windows NT +- Windows NT 3.1 +- Windows NT 3.51 +- Windows NT 4 Workstation (SP6a) +- Windows 2000 +- Windows XP + +### OS/2 +- OS/2 v1.0 +- OS/2 v1.1 +- OS/2 v1.2 +- OS/2 v1.3 +- OS/2 v2.1 +- OS/2 Warp 3 +- OS/2 Warp 4 + +### Linux +- Corel Linux 1.2 +- Mandriva LE 2005 +- Red Hat Linux 7.1 (Seawolf) + +### BeOS +- BeOS 5.0 Professional Edition + +### Applications +- 3DMark 2000 +- 3DMark 2001SE +- After Dark 3.06 +- Cinemania 1994 +- Creative Writer +- Cubasis +- Encarta 1994 +- Fasttracker v2.08 +- PageMaker 5.0 +- PC Paintbrush 1.05 +- Photoshop 3.0 +- Smartsuite 97 +- Visual Basic 3.0 +- Visual C++ 6.0 +- Word for Windows 2.0 +- Winzip 6.2 + +### Games +- 1602 AD (demo) +- 3D Ultra Pinball Thrillride +- A-10 Tank Killer +- Actua Soccer +- Adventure Pinball Forgotten Island (demo) +- Aladdin +- Alien vs Predator +- Alien vs Predator 2 (demo) +- All New World of Lemmings +- Alone in the Dark +- Alone in the Dark : The New Nightmare (demo) +- Anachronox +- Arkanoid +- Armoured Fist 3 (demo) +- Asteroids (1998) +- B-17 Flying Fortress +- Battle Chess +- Battlezone +- Battlezone II +- Bejeweled +- Beyond Castle Wolfenstein +- Big Red Racing +- Bio Menace +- Black & White +- Brix +- Bugs Bunny Lost In Time (demo) +- Cannon Fodder 2 +- Carnivores 2 +- Civilization +- Civilization for Windows +- Claw +- Clive Barker's Undying (demo) +- Clockwiser +- Command & Conquer : Red Alert +- Command & Conquer : Red Alert 2 +- Command & Conquer : Tiberian Sun (demo) +- Command & Conquer Renegade +- Conquest +- Corridor 7 +- Counter-Strike 2D +- Crimson Skies (demo) +- Croc +- Curse of Monkey Island +- Cutthroats (demo) +- Daikatana +- Dawn Patrol +- Day of the Tentacle +- Dance Dance Revolution +- Dead Reckoning (demo) +- Death Drome +- Desert Strike +- Digger +- Dirt Track Racing (demo) +- Disciples (demo) +- Discworld II +- Doom (v1.2) +- Doom II (v1.666) +- Double Dragon +- Drakan (demo) +- Duke Nukem 3D (v1.3D) +- Dune +- DX-Ball 2 +- Echelon +- Ecstatica +- Epic Pinball +- Every Extend +- Evolva (demo) +- Expendable +- Eye of the Beholder +- Fallout Tactics (demo) +- Final Fantasy VIII (demo) +- Flashback +- Flight Simulator 5 +- Frogger +- Frontier : First Encounters +- Gabriel Knight 3 (demo) +- Giants : Citizen Kabuto +- GLQuake +- Grand Theft Auto 2 +- Half-Life +- Halloween Harry +- Heartlight +- Hellbender +- Hexen +- High Heat Baseball 2002 (demo) +- Hitch Hiker's Guide to the Galaxy +- Hocus Pocus +- Homeworld Cataclysm (demo) +- Incoming +- James Pond 2 : Robocod +- Jazz Jackrabbit +- Jazz Jackrabbit 2 +- Jill of the Jungle +- King's Quest +- King's Quest II +- King's Quest III +- Lemmings +- Lemmings 2 : The Tribes +- Lode Runner : The Legend Continues +- Lotus III +- Madden 2002 (demo) +- Majesty (demo) +- Maniac Mansion (enhanced) +- Max Payne +- MDK (Direct3D, USA release) +- MechCommander 2 +- Mechwarrior 2 +- Mechwarrior 3 +- Megaman Legends +- Metal Gear Solid +- Microsoft Arcade +- Microsoft Golf 99 (demo) +- Midtown Madness 2 (demo) +- Monaco Grand Prix (demo) +- Monkey Island 2 +- Monster Bash +- Monster Truck Madness +- Mortal Kombat +- Mortal Kombat 2 +- Mortal Kombat 3 +- Motorcross Madness (demo) +- Mystic Towers +- Nascar Heat +- Need for Speed II SE +- Need for Speed III +- Need for Speed : High Stakes +- NHL 2001 (demo) +- No One Lives Forever +- Oddworld : Abe's Exoddus +- One Must Fall 2097 +- Oni +- Outlaws +- Pacific Strike +- Pacman Adventures in Time (demo) +- Pharoah (demo) +- Pinball Fantasies +- Pinball Illusions +- Police Quest +- Police Quest 2 +- Porrasturvat +- Power Drive +- Prince of Persia +- Prince of Persia 3D (demo) +- Pro Pinball : The Web +- Psycho Pinball +- Quake +- Quake II +- Quake III Arena +- Rayman 2 (demo) +- Red Faction +- Redline Racer +- Rise of the Triad (v1.2) +- Screamer +- Sega Rally 2 (demo) +- Sensible World of Soccer +- Settlers 3 (demo) +- Severance : Blade of Darkness (demo) +- Shadow Company (demo) +- Shadow Warrior +- Shadowman (demo) +- Sid Meier's Alien Crossfire (demo) +- SimCity 2000 +- SimCity Classic +- SimTower +- Sink or Swim +- Soldat (1.0.5) +- Sonic CD +- Space Simulator +- Space Strike +- Spider-Man (demo) +- Springy Madness +- Star Trek Hidden Evil (demo) +- Star Trek Voyager Elite Force +- Star Wars Jedi Academy +- Starfleet Command 2 (demo) +- Stargunner +- Starlancer (demo) +- Steel Beasts (demo) +- Stunt Island +- SWAT 3 Elite Edition (demo) +- Syndicate +- System Shock +- Tanktics (demo) +- Terminal Velocity +- The Dig +- The Humans +- The Labyrinth (RealArcade version) +- The Lost Vikings +- The Ultimate Doom (v1.9) +- Theme Hospital +- Theme Park +- Tomb Raider +- Tomb Raider II +- Tomb Raider The Last Revelation (demo) +- Tony Hawk's Pro Skater 2 +- Transport Tycoon +- Transport Tycoon Deluxe +- Tropico (demo) +- Turrican 2 +- UFO : Enemy Unknown +- Ultimate Ride (demo) +- Unreal +- Unreal Tournament +- Unreal Tournament 2004 (Direct3D) +- Wacky Wheels +- Warlords Battlecry (demo) +- Wheel of Time (demo) +- Wing Commander +- Wing Commander : Privateer +- Wizkid +- Wolfenstein 3D +- World War III : Black Gold (demo) +- Worms +- Worms Armageddon +- X-Com : Terror From The Deep +- Xargon +- Z : Steel Soldiers (demo) +- Zak McKracken +- Zone 66 + +### Demos +- Cascada - Cronologia +- Coma - Paimen +- Complex - Cyboman 2 +- Complex - Dope +- EMF - Verses +- Exceed - Heaven 7 +- Future Crew - Second Reality +- Gazebo - Cyboman +- Halcyon - Lifeforms +- Iguana - Heartquake +- Impact Studios - Legend +- Impact Studios - Project Angel +- KFMF - Dance, Move, Shake +- KFMF - Trip +- Logic Design - Fashion +- Majic 12 - Show +- Majic 12 - Wish +- Megabusters - Hellraiser +- Orange - x14 +- Renaissance - Amnesia +- Skull - Putre Faction +- Tran - Ambience (flickery) +- Tran - Luminati (flickery) +- Tran - Timeless +- Triton - Crystal Dream +- Triton - Crystal Dream 2 +- Ultraforce - Coldcut +- Ultraforce - Vector Demo +- Valhalla - Solstice +- Witan - Witan House + +### Emulators +- Beebem v1.02 +- BeebInC v0.99f +- CPE v5.2i +- DOSBox 0.74-3 +- Fellow 0.33 +- KGen98 v0.4b +- PaCifiST v0.48 +- SNES9x v0.96 +- UltraHLE v1.0.0 +- vMac v0.1.9.1 +- ZSNES v0.800c diff --git a/aclocal.m4 b/aclocal.m4 index ad14be9..5b27abd 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,6 +1,6 @@ -# generated automatically by aclocal 1.15 -*- Autoconf -*- +# generated automatically by aclocal 1.16.3 -*- Autoconf -*- -# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -14,13 +14,1582 @@ m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, -[m4_warning([this file was generated for autoconf 2.69. +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],, +[m4_warning([this file was generated for autoconf 2.71. 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'.])]) -# Copyright (C) 2002-2014 Free Software Foundation, Inc. +# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- +# serial 12 (pkg-config-0.29.2) + +dnl Copyright © 2004 Scott James Remnant . +dnl Copyright © 2012-2015 Dan Nicholson +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, but +dnl WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +dnl General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA +dnl 02111-1307, USA. +dnl +dnl As a special exception to the GNU General Public License, if you +dnl distribute this file as part of a program that contains a +dnl configuration script generated by Autoconf, you may include it under +dnl the same distribution terms that you use for the rest of that +dnl program. + +dnl PKG_PREREQ(MIN-VERSION) +dnl ----------------------- +dnl Since: 0.29 +dnl +dnl Verify that the version of the pkg-config macros are at least +dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's +dnl installed version of pkg-config, this checks the developer's version +dnl of pkg.m4 when generating configure. +dnl +dnl To ensure that this macro is defined, also add: +dnl m4_ifndef([PKG_PREREQ], +dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) +dnl +dnl See the "Since" comment for each macro you use to see what version +dnl of the macros you require. +m4_defun([PKG_PREREQ], +[m4_define([PKG_MACROS_VERSION], [0.29.2]) +m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, + [m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) +])dnl PKG_PREREQ + +dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) +dnl ---------------------------------- +dnl Since: 0.16 +dnl +dnl Search for the pkg-config tool and set the PKG_CONFIG variable to +dnl first found in the path. Checks that the version of pkg-config found +dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is +dnl used since that's the first version where most current features of +dnl pkg-config existed. +AC_DEFUN([PKG_PROG_PKG_CONFIG], +[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) +m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) +m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) +AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) +AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) +AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=m4_default([$1], [0.9.0]) + AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + AC_MSG_RESULT([yes]) + else + AC_MSG_RESULT([no]) + PKG_CONFIG="" + fi +fi[]dnl +])dnl PKG_PROG_PKG_CONFIG + +dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------------------------------- +dnl Since: 0.18 +dnl +dnl Check to see whether a particular set of modules exists. Similar to +dnl PKG_CHECK_MODULES(), but does not set variables or print errors. +dnl +dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +dnl only at the first occurence in configure.ac, so if the first place +dnl it's called might be skipped (such as if it is within an "if", you +dnl have to call PKG_CHECK_EXISTS manually +AC_DEFUN([PKG_CHECK_EXISTS], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +if test -n "$PKG_CONFIG" && \ + AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then + m4_default([$2], [:]) +m4_ifvaln([$3], [else + $3])dnl +fi]) + +dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) +dnl --------------------------------------------- +dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting +dnl pkg_failed based on the result. +m4_define([_PKG_CONFIG], +[if test -n "$$1"; then + pkg_cv_[]$1="$$1" + elif test -n "$PKG_CONFIG"; then + PKG_CHECK_EXISTS([$3], + [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes ], + [pkg_failed=yes]) + else + pkg_failed=untried +fi[]dnl +])dnl _PKG_CONFIG + +dnl _PKG_SHORT_ERRORS_SUPPORTED +dnl --------------------------- +dnl Internal check to see if pkg-config supports short errors. +AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi[]dnl +])dnl _PKG_SHORT_ERRORS_SUPPORTED + + +dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl -------------------------------------------------------------- +dnl Since: 0.4.0 +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES might not happen, you should be sure to include an +dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac +AC_DEFUN([PKG_CHECK_MODULES], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl +AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl + +pkg_failed=no +AC_MSG_CHECKING([for $2]) + +_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) +_PKG_CONFIG([$1][_LIBS], [libs], [$2]) + +m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS +and $1[]_LIBS to avoid the need to call pkg-config. +See the pkg-config man page for more details.]) + +if test $pkg_failed = yes; then + AC_MSG_RESULT([no]) + _PKG_SHORT_ERRORS_SUPPORTED + if test $_pkg_short_errors_supported = yes; then + $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` + else + $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD + + m4_default([$4], [AC_MSG_ERROR( +[Package requirements ($2) were not met: + +$$1_PKG_ERRORS + +Consider adjusting the PKG_CONFIG_PATH environment variable if you +installed software in a non-standard prefix. + +_PKG_TEXT])[]dnl + ]) +elif test $pkg_failed = untried; then + AC_MSG_RESULT([no]) + m4_default([$4], [AC_MSG_FAILURE( +[The pkg-config script could not be found or is too old. Make sure it +is in your PATH or set the PKG_CONFIG environment variable to the full +path to pkg-config. + +_PKG_TEXT + +To get pkg-config, see .])[]dnl + ]) +else + $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS + $1[]_LIBS=$pkg_cv_[]$1[]_LIBS + AC_MSG_RESULT([yes]) + $3 +fi[]dnl +])dnl PKG_CHECK_MODULES + + +dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], +dnl [ACTION-IF-NOT-FOUND]) +dnl --------------------------------------------------------------------- +dnl Since: 0.29 +dnl +dnl Checks for existence of MODULES and gathers its build flags with +dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags +dnl and VARIABLE-PREFIX_LIBS from --libs. +dnl +dnl Note that if there is a possibility the first call to +dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to +dnl include an explicit call to PKG_PROG_PKG_CONFIG in your +dnl configure.ac. +AC_DEFUN([PKG_CHECK_MODULES_STATIC], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +_save_PKG_CONFIG=$PKG_CONFIG +PKG_CONFIG="$PKG_CONFIG --static" +PKG_CHECK_MODULES($@) +PKG_CONFIG=$_save_PKG_CONFIG[]dnl +])dnl PKG_CHECK_MODULES_STATIC + + +dnl PKG_INSTALLDIR([DIRECTORY]) +dnl ------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable pkgconfigdir as the location where a module +dnl should install pkg-config .pc files. By default the directory is +dnl $libdir/pkgconfig, but the default can be changed by passing +dnl DIRECTORY. The user can override through the --with-pkgconfigdir +dnl parameter. +AC_DEFUN([PKG_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([pkgconfigdir], + [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, + [with_pkgconfigdir=]pkg_default) +AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_INSTALLDIR + + +dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) +dnl -------------------------------- +dnl Since: 0.27 +dnl +dnl Substitutes the variable noarch_pkgconfigdir as the location where a +dnl module should install arch-independent pkg-config .pc files. By +dnl default the directory is $datadir/pkgconfig, but the default can be +dnl changed by passing DIRECTORY. The user can override through the +dnl --with-noarch-pkgconfigdir parameter. +AC_DEFUN([PKG_NOARCH_INSTALLDIR], +[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) +m4_pushdef([pkg_description], + [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) +AC_ARG_WITH([noarch-pkgconfigdir], + [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, + [with_noarch_pkgconfigdir=]pkg_default) +AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) +m4_popdef([pkg_default]) +m4_popdef([pkg_description]) +])dnl PKG_NOARCH_INSTALLDIR + + +dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, +dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) +dnl ------------------------------------------- +dnl Since: 0.28 +dnl +dnl Retrieves the value of the pkg-config variable for the given module. +AC_DEFUN([PKG_CHECK_VAR], +[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl +AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl + +_PKG_CONFIG([$1], [variable="][$3]["], [$2]) +AS_VAR_COPY([$1], [pkg_cv_][$1]) + +AS_VAR_IF([$1], [""], [$5], [$4])dnl +])dnl PKG_CHECK_VAR + +# Configure paths for SDL +# Sam Lantinga 9/21/99 +# stolen from Manish Singh +# stolen back from Frank Belew +# stolen from Manish Singh +# Shamelessly stolen from Owen Taylor +# +# Changelog: +# * also look for SDL2.framework under Mac OS X + +# serial 1 + +dnl AM_PATH_SDL2([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for SDL, and define SDL_CFLAGS and SDL_LIBS +dnl +AC_DEFUN([AM_PATH_SDL2], +[dnl +dnl Get the cflags and libraries from the sdl2-config script +dnl +AC_ARG_WITH(sdl-prefix,[ --with-sdl-prefix=PFX Prefix where SDL is installed (optional)], + sdl_prefix="$withval", sdl_prefix="") +AC_ARG_WITH(sdl-exec-prefix,[ --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional)], + sdl_exec_prefix="$withval", sdl_exec_prefix="") +AC_ARG_ENABLE(sdltest, [ --disable-sdltest Do not try to compile and run a test SDL program], + , enable_sdltest=yes) +AC_ARG_ENABLE(sdlframework, [ --disable-sdlframework Do not search for SDL2.framework], + , search_sdl_framework=yes) + +AC_ARG_VAR(SDL2_FRAMEWORK, [Path to SDL2.framework]) + + min_sdl_version=ifelse([$1], ,2.0.0,$1) + + if test "x$sdl_prefix$sdl_exec_prefix" = x ; then + PKG_CHECK_MODULES([SDL], [sdl2 >= $min_sdl_version], + [sdl_pc=yes], + [sdl_pc=no]) + else + sdl_pc=no + if test x$sdl_exec_prefix != x ; then + sdl_config_args="$sdl_config_args --exec-prefix=$sdl_exec_prefix" + if test x${SDL2_CONFIG+set} != xset ; then + SDL2_CONFIG=$sdl_exec_prefix/bin/sdl2-config + fi + fi + if test x$sdl_prefix != x ; then + sdl_config_args="$sdl_config_args --prefix=$sdl_prefix" + if test x${SDL2_CONFIG+set} != xset ; then + SDL2_CONFIG=$sdl_prefix/bin/sdl2-config + fi + fi + fi + + if test "x$sdl_pc" = xyes ; then + no_sdl="" + SDL2_CONFIG="pkg-config sdl2" + else + as_save_PATH="$PATH" + if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then + PATH="$prefix/bin:$prefix/usr/bin:$PATH" + fi + AC_PATH_PROG(SDL2_CONFIG, sdl2-config, no, [$PATH]) + PATH="$as_save_PATH" + no_sdl="" + + if test "$SDL2_CONFIG" = "no" -a "x$search_sdl_framework" = "xyes"; then + AC_MSG_CHECKING(for SDL2.framework) + if test "x$SDL2_FRAMEWORK" != x; then + sdl_framework=$SDL2_FRAMEWORK + else + for d in / ~/ /System/; do + if test -d "$dLibrary/Frameworks/SDL2.framework"; then + sdl_framework="$dLibrary/Frameworks/SDL2.framework" + fi + done + fi + + if test x"$sdl_framework" != x && test -d "$sdl_framework"; then + AC_MSG_RESULT($sdl_framework) + sdl_framework_dir=`dirname $sdl_framework` + SDL_CFLAGS="-F$sdl_framework_dir -Wl,-framework,SDL2 -I$sdl_framework/include" + SDL_LIBS="-F$sdl_framework_dir -Wl,-framework,SDL2" + else + no_sdl=yes + fi + fi + + if test "$SDL2_CONFIG" != "no"; then + if test "x$sdl_pc" = "xno"; then + AC_MSG_CHECKING(for SDL - version >= $min_sdl_version) + SDL_CFLAGS=`$SDL2_CONFIG $sdl_config_args --cflags` + SDL_LIBS=`$SDL2_CONFIG $sdl_config_args --libs` + fi + + sdl_major_version=`$SDL2_CONFIG $sdl_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + sdl_minor_version=`$SDL2_CONFIG $sdl_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + sdl_micro_version=`$SDL2_CONFIG $sdl_config_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_sdltest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_CXXFLAGS="$CXXFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $SDL_CFLAGS" + CXXFLAGS="$CXXFLAGS $SDL_CFLAGS" + LIBS="$LIBS $SDL_LIBS" +dnl +dnl Now check if the installed SDL is sufficiently new. (Also sanity +dnl checks the results of sdl2-config to some extent +dnl + rm -f conf.sdltest + AC_TRY_RUN([ +#include +#include +#include +#include "SDL.h" + +char* +my_strdup (char *str) +{ + char *new_str; + + if (str) + { + new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char)); + strcpy (new_str, str); + } + else + new_str = NULL; + + return new_str; +} + +int main (int argc, char *argv[]) +{ + int major, minor, micro; + char *tmp_version; + + /* This hangs on some systems (?) + system ("touch conf.sdltest"); + */ + { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); } + + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = my_strdup("$min_sdl_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_sdl_version"); + exit(1); + } + + if (($sdl_major_version > major) || + (($sdl_major_version == major) && ($sdl_minor_version > minor)) || + (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** 'sdl2-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version); + printf("*** of SDL required is %d.%d.%d. If sdl2-config is correct, then it is\n", major, minor, micro); + printf("*** best to upgrade to the required version.\n"); + printf("*** If sdl2-config was wrong, set the environment variable SDL2_CONFIG\n"); + printf("*** to point to the correct copy of sdl2-config, and remove the file\n"); + printf("*** config.cache before re-running configure\n"); + return 1; + } +} + +],, no_sdl=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + + fi + if test "x$sdl_pc" = "xno"; then + if test "x$no_sdl" = "xyes"; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + fi + fi + fi + if test "x$no_sdl" = x ; then + ifelse([$2], , :, [$2]) + else + if test "$SDL2_CONFIG" = "no" ; then + echo "*** The sdl2-config script installed by SDL could not be found" + echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the SDL2_CONFIG environment variable to the" + echo "*** full path to sdl2-config." + else + if test -f conf.sdltest ; then + : + else + echo "*** Could not run SDL test program, checking why..." + CFLAGS="$CFLAGS $SDL_CFLAGS" + CXXFLAGS="$CXXFLAGS $SDL_CFLAGS" + LIBS="$LIBS $SDL_LIBS" + AC_TRY_LINK([ +#include +#include "SDL.h" + +int main(int argc, char *argv[]) +{ return 0; } +#undef main +#define main K_and_R_C_main +], [ return 0; ], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding SDL or finding the wrong" + echo "*** version of SDL. If it is not finding SDL, 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 SDL was incorrectly installed" + echo "*** or that you have moved SDL since it was installed. In the latter case, you" + echo "*** may want to edit the sdl2-config script: $SDL2_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + SDL_CFLAGS="" + SDL_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(SDL_CFLAGS) + AC_SUBST(SDL_LIBS) + rm -f conf.sdltest +]) + +dnl --------------------------------------------------------------------------- +dnl Author: wxWidgets development team, +dnl Francesco Montorsi, +dnl Bob McCown (Mac-testing) +dnl Creation date: 24/11/2001 +dnl --------------------------------------------------------------------------- + +dnl =========================================================================== +dnl Table of Contents of this macro file: +dnl ------------------------------------- +dnl +dnl SECTION A: wxWidgets main macros +dnl - WX_CONFIG_OPTIONS +dnl - WX_CONFIG_CHECK +dnl - WXRC_CHECK +dnl - WX_STANDARD_OPTIONS +dnl - WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS +dnl - WX_DETECT_STANDARD_OPTION_VALUES +dnl +dnl SECTION B: wxWidgets-related utilities +dnl - WX_LIKE_LIBNAME +dnl - WX_ARG_ENABLE_YESNOAUTO +dnl - WX_ARG_WITH_YESNOAUTO +dnl +dnl SECTION C: messages to the user +dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG +dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN +dnl - WX_STANDARD_OPTIONS_SUMMARY_MSG_END +dnl - WX_BOOLOPT_SUMMARY +dnl +dnl The special "WX_DEBUG_CONFIGURE" variable can be set to 1 to enable extra +dnl debug output on stdout from these macros. +dnl =========================================================================== + + +dnl --------------------------------------------------------------------------- +dnl Macros for wxWidgets detection. Typically used in configure.in as: +dnl +dnl AC_ARG_ENABLE(...) +dnl AC_ARG_WITH(...) +dnl ... +dnl WX_CONFIG_OPTIONS +dnl ... +dnl ... +dnl WX_CONFIG_CHECK([2.6.0], [wxWin=1]) +dnl if test "$wxWin" != 1; then +dnl AC_MSG_ERROR([ +dnl wxWidgets must be installed on your system +dnl but wx-config script couldn't be found. +dnl +dnl Please check that wx-config is in path, the directory +dnl where wxWidgets libraries are installed (returned by +dnl 'wx-config --libs' command) is in LD_LIBRARY_PATH or +dnl equivalent variable and wxWidgets version is 2.3.4 or above. +dnl ]) +dnl fi +dnl CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS" +dnl CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY" +dnl CFLAGS="$CFLAGS $WX_CFLAGS_ONLY" +dnl +dnl LIBS="$LIBS $WX_LIBS" +dnl +dnl If you want to support standard --enable-debug/unicode/shared options, you +dnl may do the following: +dnl +dnl ... +dnl AC_CANONICAL_SYSTEM +dnl +dnl # define configure options +dnl WX_CONFIG_OPTIONS +dnl WX_STANDARD_OPTIONS([debug,unicode,shared,toolkit,wxshared]) +dnl +dnl # basic configure checks +dnl ... +dnl +dnl # we want to always have DEBUG==WX_DEBUG and UNICODE==WX_UNICODE +dnl WX_DEBUG=$DEBUG +dnl WX_UNICODE=$UNICODE +dnl +dnl WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS +dnl WX_CONFIG_CHECK([2.8.0], [wxWin=1],,[html,core,net,base],[$WXCONFIG_FLAGS]) +dnl WX_DETECT_STANDARD_OPTION_VALUES +dnl +dnl # write the output files +dnl AC_CONFIG_FILES([Makefile ...]) +dnl AC_OUTPUT +dnl +dnl # optional: just to show a message to the user +dnl WX_STANDARD_OPTIONS_SUMMARY_MSG +dnl +dnl --------------------------------------------------------------------------- + + +dnl --------------------------------------------------------------------------- +dnl WX_CONFIG_OPTIONS +dnl +dnl adds support for --wx-prefix, --wx-exec-prefix, --with-wxdir and +dnl --wx-config command line options +dnl --------------------------------------------------------------------------- + +AC_DEFUN([WX_CONFIG_OPTIONS], +[ + AC_ARG_WITH(wxdir, + [ --with-wxdir=PATH Use uninstalled version of wxWidgets in PATH], + [ wx_config_name="$withval/wx-config" + wx_config_args="--inplace"]) + AC_ARG_WITH(wx-config, + [ --with-wx-config=CONFIG wx-config script to use (optional)], + wx_config_name="$withval" ) + AC_ARG_WITH(wx-prefix, + [ --with-wx-prefix=PREFIX Prefix where wxWidgets is installed (optional)], + wx_config_prefix="$withval", wx_config_prefix="") + AC_ARG_WITH(wx-exec-prefix, + [ --with-wx-exec-prefix=PREFIX + Exec prefix where wxWidgets is installed (optional)], + wx_config_exec_prefix="$withval", wx_config_exec_prefix="") +]) + +dnl Helper macro for checking if wx version is at least $1.$2.$3, set's +dnl wx_ver_ok=yes if it is: +AC_DEFUN([_WX_PRIVATE_CHECK_VERSION], +[ + wx_ver_ok="" + if test "x$WX_VERSION" != x ; then + if test $wx_config_major_version -gt $1; then + wx_ver_ok=yes + else + if test $wx_config_major_version -eq $1; then + if test $wx_config_minor_version -gt $2; then + wx_ver_ok=yes + else + if test $wx_config_minor_version -eq $2; then + if test $wx_config_micro_version -ge $3; then + wx_ver_ok=yes + fi + fi + fi + fi + fi + fi +]) + +dnl --------------------------------------------------------------------------- +dnl WX_CONFIG_CHECK(VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND +dnl [, WX-LIBS [, ADDITIONAL-WX-CONFIG-FLAGS +dnl [, WX-OPTIONAL-LIBS]]]]]) +dnl +dnl Test for wxWidgets, and define WX_C*FLAGS, WX_LIBS and WX_LIBS_STATIC +dnl (the latter is for static linking against wxWidgets). Set WX_CONFIG_NAME +dnl environment variable to override the default name of the wx-config script +dnl to use. Set WX_CONFIG_PATH to specify the full path to wx-config - in this +dnl case the macro won't even waste time on tests for its existence. +dnl +dnl Optional WX-LIBS argument contains comma- or space-separated list of +dnl wxWidgets libraries to link against. If it is not specified then WX_LIBS +dnl and WX_LIBS_STATIC will contain flags to link with all of the core +dnl wxWidgets libraries. +dnl +dnl Optional ADDITIONAL-WX-CONFIG-FLAGS argument is appended to wx-config +dnl invocation command in present. It can be used to fine-tune lookup of +dnl best wxWidgets build available. +dnl +dnl Optional WX-OPTIONAL-LIBS argument contains comma- or space-separated list +dnl of wxWidgets libraries to link against if they are available. +dnl WX-OPTIONAL-LIBS is supported on version 2.9.0 and later. +dnl +dnl Example use: +dnl WX_CONFIG_CHECK([2.6.0], [wxWin=1], [wxWin=0], [html,core,net] +dnl [--unicode --debug]) +dnl --------------------------------------------------------------------------- + +dnl +dnl Get the cflags and libraries from the wx-config script +dnl +AC_DEFUN([WX_CONFIG_CHECK], +[ + dnl do we have wx-config name: it can be wx-config or wxd-config or ... + if test x${WX_CONFIG_NAME+set} != xset ; then + WX_CONFIG_NAME=wx-config + fi + + if test "x$wx_config_name" != x ; then + WX_CONFIG_NAME="$wx_config_name" + fi + + dnl deal with optional prefixes + if test x$wx_config_exec_prefix != x ; then + wx_config_args="$wx_config_args --exec-prefix=$wx_config_exec_prefix" + WX_LOOKUP_PATH="$wx_config_exec_prefix/bin" + fi + if test x$wx_config_prefix != x ; then + wx_config_args="$wx_config_args --prefix=$wx_config_prefix" + WX_LOOKUP_PATH="$WX_LOOKUP_PATH:$wx_config_prefix/bin" + fi + if test "$cross_compiling" = "yes"; then + wx_config_args="$wx_config_args --host=$host_alias" + fi + + dnl don't search the PATH if WX_CONFIG_NAME is absolute filename + if test -x "$WX_CONFIG_NAME" ; then + AC_MSG_CHECKING(for wx-config) + WX_CONFIG_PATH="$WX_CONFIG_NAME" + AC_MSG_RESULT($WX_CONFIG_PATH) + else + AC_PATH_PROG(WX_CONFIG_PATH, $WX_CONFIG_NAME, no, "$WX_LOOKUP_PATH:$PATH") + fi + + if test "$WX_CONFIG_PATH" != "no" ; then + WX_VERSION="" + + min_wx_version=ifelse([$1], ,2.2.1,$1) + if test -z "$5" ; then + AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version]) + else + AC_MSG_CHECKING([for wxWidgets version >= $min_wx_version ($5)]) + fi + + dnl don't add the libraries (4th argument) to this variable as this would + dnl result in an error when it's used with --version below + WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args $5" + + WX_VERSION=`$WX_CONFIG_WITH_ARGS --version 2>/dev/null` + wx_config_major_version=`echo $WX_VERSION | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + wx_config_minor_version=`echo $WX_VERSION | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + wx_config_micro_version=`echo $WX_VERSION | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + wx_requested_major_version=`echo $min_wx_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + wx_requested_minor_version=`echo $min_wx_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + wx_requested_micro_version=`echo $min_wx_version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + + _WX_PRIVATE_CHECK_VERSION([$wx_requested_major_version], + [$wx_requested_minor_version], + [$wx_requested_micro_version]) + + if test -n "$wx_ver_ok"; then + AC_MSG_RESULT(yes (version $WX_VERSION)) + + wx_optional_libs="" + _WX_PRIVATE_CHECK_VERSION(2,9,0) + if test -n "$wx_ver_ok" -a -n "$6"; then + wx_optional_libs="--optional-libs $6" + fi + WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs $4 $wx_optional_libs` + + dnl is this even still appropriate? --static is a real option now + dnl and WX_CONFIG_WITH_ARGS is likely to contain it if that is + dnl what the user actually wants, making this redundant at best. + dnl For now keep it in case anyone actually used it in the past. + AC_MSG_CHECKING([for wxWidgets static library]) + WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs $4 $wx_optional_libs 2>/dev/null` + if test "x$WX_LIBS_STATIC" = "x"; then + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(yes) + fi + + dnl starting with version 2.2.6 wx-config has --cppflags argument + wx_has_cppflags="" + if test $wx_config_major_version -gt 2; then + wx_has_cppflags=yes + else + if test $wx_config_major_version -eq 2; then + if test $wx_config_minor_version -gt 2; then + wx_has_cppflags=yes + else + if test $wx_config_minor_version -eq 2; then + if test $wx_config_micro_version -ge 6; then + wx_has_cppflags=yes + fi + fi + fi + fi + fi + + dnl starting with version 2.7.0 wx-config has --rescomp option + wx_has_rescomp="" + if test $wx_config_major_version -gt 2; then + wx_has_rescomp=yes + else + if test $wx_config_major_version -eq 2; then + if test $wx_config_minor_version -ge 7; then + wx_has_rescomp=yes + fi + fi + fi + if test "x$wx_has_rescomp" = x ; then + dnl cannot give any useful info for resource compiler + WX_RESCOMP= + else + WX_RESCOMP=`$WX_CONFIG_WITH_ARGS --rescomp` + fi + + if test "x$wx_has_cppflags" = x ; then + dnl no choice but to define all flags like CFLAGS + WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags $4` + WX_CPPFLAGS=$WX_CFLAGS + WX_CXXFLAGS=$WX_CFLAGS + + WX_CFLAGS_ONLY=$WX_CFLAGS + WX_CXXFLAGS_ONLY=$WX_CFLAGS + else + dnl we have CPPFLAGS included in CFLAGS included in CXXFLAGS + WX_CPPFLAGS=`$WX_CONFIG_WITH_ARGS --cppflags $4` + WX_CXXFLAGS=`$WX_CONFIG_WITH_ARGS --cxxflags $4` + WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags $4` + + WX_CFLAGS_ONLY=`echo $WX_CFLAGS | sed "s@^$WX_CPPFLAGS *@@"` + WX_CXXFLAGS_ONLY=`echo $WX_CXXFLAGS | sed "s@^$WX_CFLAGS *@@"` + fi + + ifelse([$2], , :, [$2]) + + else + + if test "x$WX_VERSION" = x; then + dnl no wx-config at all + AC_MSG_RESULT(no) + else + AC_MSG_RESULT(no (version $WX_VERSION is not new enough)) + fi + + WX_CFLAGS="" + WX_CPPFLAGS="" + WX_CXXFLAGS="" + WX_LIBS="" + WX_LIBS_STATIC="" + WX_RESCOMP="" + + if test ! -z "$5"; then + + wx_error_message=" + The configuration you asked for $PACKAGE_NAME requires a wxWidgets + build with the following settings: + $5 + but such build is not available. + + To see the wxWidgets builds available on this system, please use + 'wx-config --list' command. To use the default build, returned by + 'wx-config --selected-config', use the options with their 'auto' + default values." + + fi + + wx_error_message=" + The requested wxWidgets build couldn't be found. + $wx_error_message + + If you still get this error, then check that 'wx-config' is + in path, the directory where wxWidgets libraries are installed + (returned by 'wx-config --libs' command) is in LD_LIBRARY_PATH + or equivalent variable and wxWidgets version is $1 or above." + + ifelse([$3], , AC_MSG_ERROR([$wx_error_message]), [$3]) + + fi + else + + WX_CFLAGS="" + WX_CPPFLAGS="" + WX_CXXFLAGS="" + WX_LIBS="" + WX_LIBS_STATIC="" + WX_RESCOMP="" + + ifelse([$3], , :, [$3]) + + fi + + AC_SUBST(WX_CPPFLAGS) + AC_SUBST(WX_CFLAGS) + AC_SUBST(WX_CXXFLAGS) + AC_SUBST(WX_CFLAGS_ONLY) + AC_SUBST(WX_CXXFLAGS_ONLY) + AC_SUBST(WX_LIBS) + AC_SUBST(WX_LIBS_STATIC) + AC_SUBST(WX_VERSION) + AC_SUBST(WX_RESCOMP) + + dnl need to export also WX_VERSION_MINOR and WX_VERSION_MAJOR symbols + dnl to support wxpresets bakefiles (we export also WX_VERSION_MICRO for completeness): + WX_VERSION_MAJOR="$wx_config_major_version" + WX_VERSION_MINOR="$wx_config_minor_version" + WX_VERSION_MICRO="$wx_config_micro_version" + AC_SUBST(WX_VERSION_MAJOR) + AC_SUBST(WX_VERSION_MINOR) + AC_SUBST(WX_VERSION_MICRO) +]) + +dnl --------------------------------------------------------------------------- +dnl Get information on the wxrc program for making C++, Python and xrs +dnl resource files. +dnl +dnl AC_ARG_ENABLE(...) +dnl AC_ARG_WITH(...) +dnl ... +dnl WX_CONFIG_OPTIONS +dnl ... +dnl WX_CONFIG_CHECK(2.6.0, wxWin=1) +dnl if test "$wxWin" != 1; then +dnl AC_MSG_ERROR([ +dnl wxWidgets must be installed on your system +dnl but wx-config script couldn't be found. +dnl +dnl Please check that wx-config is in path, the directory +dnl where wxWidgets libraries are installed (returned by +dnl 'wx-config --libs' command) is in LD_LIBRARY_PATH or +dnl equivalent variable and wxWidgets version is 2.6.0 or above. +dnl ]) +dnl fi +dnl +dnl WXRC_CHECK([HAVE_WXRC=1], [HAVE_WXRC=0]) +dnl if test "x$HAVE_WXRC" != x1; then +dnl AC_MSG_ERROR([ +dnl The wxrc program was not installed or not found. +dnl +dnl Please check the wxWidgets installation. +dnl ]) +dnl fi +dnl +dnl CPPFLAGS="$CPPFLAGS $WX_CPPFLAGS" +dnl CXXFLAGS="$CXXFLAGS $WX_CXXFLAGS_ONLY" +dnl CFLAGS="$CFLAGS $WX_CFLAGS_ONLY" +dnl +dnl LDFLAGS="$LDFLAGS $WX_LIBS" +dnl --------------------------------------------------------------------------- + +dnl --------------------------------------------------------------------------- +dnl WXRC_CHECK([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl +dnl Test for wxWidgets' wxrc program for creating either C++, Python or XRS +dnl resources. The variable WXRC will be set and substituted in the configure +dnl script and Makefiles. +dnl +dnl Example use: +dnl WXRC_CHECK([wxrc=1], [wxrc=0]) +dnl --------------------------------------------------------------------------- + +dnl +dnl wxrc program from the wx-config script +dnl +AC_DEFUN([WXRC_CHECK], +[ + AC_ARG_VAR([WXRC], [Path to wxWidget's wxrc resource compiler]) + + if test "x$WX_CONFIG_NAME" = x; then + AC_MSG_ERROR([The wxrc tests must run after wxWidgets test.]) + else + + AC_MSG_CHECKING([for wxrc]) + + if test "x$WXRC" = x ; then + dnl wx-config --utility is a new addition to wxWidgets: + _WX_PRIVATE_CHECK_VERSION(2,5,3) + if test -n "$wx_ver_ok"; then + WXRC=`$WX_CONFIG_WITH_ARGS --utility=wxrc` + fi + fi + + if test "x$WXRC" = x ; then + AC_MSG_RESULT([not found]) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT([$WXRC]) + ifelse([$1], , :, [$1]) + fi + + AC_SUBST(WXRC) + fi +]) + +dnl --------------------------------------------------------------------------- +dnl WX_LIKE_LIBNAME([output-var] [prefix], [name]) +dnl +dnl Sets the "output-var" variable to the name of a library named with same +dnl wxWidgets rule. +dnl E.g. for output-var=='lib', name=='test', prefix='mine', sets +dnl the $lib variable to: +dnl 'mine_gtk2ud_test-2.8' +dnl if WX_PORT=gtk2, WX_UNICODE=1, WX_DEBUG=1 and WX_RELEASE=28 +dnl --------------------------------------------------------------------------- +AC_DEFUN([WX_LIKE_LIBNAME], + [ + wx_temp="$2""_""$WX_PORT" + + dnl add the [u][d] string + if test "$WX_UNICODE" = "1"; then + wx_temp="$wx_temp""u" + fi + if test "$WX_DEBUG" = "1"; then + wx_temp="$wx_temp""d" + fi + + dnl complete the name of the lib + wx_temp="$wx_temp""_""$3""-$WX_VERSION_MAJOR.$WX_VERSION_MINOR" + + dnl save it in the user's variable + $1=$wx_temp + ]) + +dnl --------------------------------------------------------------------------- +dnl WX_ARG_ENABLE_YESNOAUTO/WX_ARG_WITH_YESNOAUTO +dnl +dnl Two little custom macros which define the ENABLE/WITH configure arguments. +dnl Macro arguments: +dnl $1 = the name of the --enable / --with feature +dnl $2 = the name of the variable associated +dnl $3 = the description of that feature +dnl $4 = the default value for that feature +dnl $5 = additional action to do in case option is given with "yes" value +dnl --------------------------------------------------------------------------- +AC_DEFUN([WX_ARG_ENABLE_YESNOAUTO], + [AC_ARG_ENABLE($1, + AC_HELP_STRING([--enable-$1], [$3 (default is $4)]), + [], [enableval="$4"]) + + dnl Show a message to the user about this option + AC_MSG_CHECKING([for the --enable-$1 option]) + if test "$enableval" = "yes" ; then + AC_MSG_RESULT([yes]) + $2=1 + $5 + elif test "$enableval" = "no" ; then + AC_MSG_RESULT([no]) + $2=0 + elif test "$enableval" = "auto" ; then + AC_MSG_RESULT([will be automatically detected]) + $2="" + else + AC_MSG_ERROR([ + Unrecognized option value (allowed values: yes, no, auto) + ]) + fi + ]) + +AC_DEFUN([WX_ARG_WITH_YESNOAUTO], + [AC_ARG_WITH($1, + AC_HELP_STRING([--with-$1], [$3 (default is $4)]), + [], [withval="$4"]) + + dnl Show a message to the user about this option + AC_MSG_CHECKING([for the --with-$1 option]) + if test "$withval" = "yes" ; then + AC_MSG_RESULT([yes]) + $2=1 + $5 + dnl NB: by default we don't allow --with-$1=no option + dnl since it does not make much sense ! + elif test "$6" = "1" -a "$withval" = "no" ; then + AC_MSG_RESULT([no]) + $2=0 + elif test "$withval" = "auto" ; then + AC_MSG_RESULT([will be automatically detected]) + $2="" + else + AC_MSG_ERROR([ + Unrecognized option value (allowed values: yes, auto) + ]) + fi + ]) + + +dnl --------------------------------------------------------------------------- +dnl WX_STANDARD_OPTIONS([options-to-add]) +dnl +dnl Adds to the configure script one or more of the following options: +dnl --enable-[debug|unicode|shared|wxshared|wxdebug] +dnl --with-[gtk|msw|motif|x11|mac|dfb] +dnl --with-wxversion +dnl Then checks for their presence and eventually set the DEBUG, UNICODE, SHARED, +dnl PORT, WX_SHARED, WX_DEBUG, variables to one of the "yes", "no", "auto" values. +dnl +dnl Note that e.g. UNICODE != WX_UNICODE; the first is the value of the +dnl --enable-unicode option (in boolean format) while the second indicates +dnl if wxWidgets was built in Unicode mode (and still is in boolean format). +dnl --------------------------------------------------------------------------- +AC_DEFUN([WX_STANDARD_OPTIONS], + [ + + dnl the following lines will expand to WX_ARG_ENABLE_YESNOAUTO calls if and only if + dnl the $1 argument contains respectively the debug,unicode or shared options. + + dnl be careful here not to set debug flag if only "wxdebug" was specified + ifelse(regexp([$1], [\bdebug]), [-1],, + [WX_ARG_ENABLE_YESNOAUTO([debug], [DEBUG], [Build in debug mode], [auto])]) + + ifelse(index([$1], [unicode]), [-1],, + [WX_ARG_ENABLE_YESNOAUTO([unicode], [UNICODE], [Build in Unicode mode], [auto])]) + + ifelse(regexp([$1], [\bshared]), [-1],, + [WX_ARG_ENABLE_YESNOAUTO([shared], [SHARED], [Build as shared library], [auto])]) + + dnl WX_ARG_WITH_YESNOAUTO cannot be used for --with-toolkit since it's an option + dnl which must be able to accept the auto|gtk1|gtk2|msw|... values + ifelse(index([$1], [toolkit]), [-1],, + [ + AC_ARG_WITH([toolkit], + AC_HELP_STRING([--with-toolkit], + [Build against a specific wxWidgets toolkit (default is auto)]), + [], [withval="auto"]) + + dnl Show a message to the user about this option + AC_MSG_CHECKING([for the --with-toolkit option]) + if test "$withval" = "auto" ; then + AC_MSG_RESULT([will be automatically detected]) + TOOLKIT="" + else + TOOLKIT="$withval" + + dnl PORT must be one of the allowed values + if test "$TOOLKIT" != "gtk1" -a "$TOOLKIT" != "gtk2" -a "$TOOLKIT" != "gtk3" -a \ + "$TOOLKIT" != "msw" -a "$TOOLKIT" != "motif" -a \ + "$TOOLKIT" != "osx_carbon" -a "$TOOLKIT" != "osx_cocoa" -a \ + "$TOOLKIT" != "dfb" -a "$TOOLKIT" != "x11" -a "$TOOLKIT" != "base"; then + AC_MSG_ERROR([ + Unrecognized option value (allowed values: auto, gtk1, gtk2, gtk3, msw, motif, osx_carbon, osx_cocoa, dfb, x11, base) + ]) + fi + + AC_MSG_RESULT([$TOOLKIT]) + fi + ]) + + dnl ****** IMPORTANT ******* + dnl Unlike for the UNICODE setting, you can build your program in + dnl shared mode against a static build of wxWidgets. Thus we have the + dnl following option which allows these mixtures. E.g. + dnl + dnl ./configure --disable-shared --with-wxshared + dnl + dnl will build your library in static mode against the first available + dnl shared build of wxWidgets. + dnl + dnl Note that's not possible to do the viceversa: + dnl + dnl ./configure --enable-shared --without-wxshared + dnl + dnl Doing so you would try to build your library in shared mode against a static + dnl build of wxWidgets. This is not possible (you would mix PIC and non PIC code) ! + dnl A check for this combination of options is in WX_DETECT_STANDARD_OPTION_VALUES + dnl (where we know what 'auto' should be expanded to). + dnl + dnl If you try to build something in ANSI mode against a UNICODE build + dnl of wxWidgets or in RELEASE mode against a DEBUG build of wxWidgets, + dnl then at best you'll get ton of linking errors ! + dnl ************************ + + ifelse(index([$1], [wxshared]), [-1],, + [ + WX_ARG_WITH_YESNOAUTO( + [wxshared], [WX_SHARED], + [Force building against a shared build of wxWidgets, even if --disable-shared is given], + [auto], [], [1]) + ]) + + dnl Just like for SHARED and WX_SHARED it may happen that some adventurous + dnl peoples will want to mix a wxWidgets release build with a debug build of + dnl his app/lib. So, we have both DEBUG and WX_DEBUG variables. + ifelse(index([$1], [wxdebug]), [-1],, + [ + WX_ARG_WITH_YESNOAUTO( + [wxdebug], [WX_DEBUG], + [Force building against a debug build of wxWidgets, even if --disable-debug is given], + [auto], [], [1]) + ]) + + dnl WX_ARG_WITH_YESNOAUTO cannot be used for --with-wxversion since it's an option + dnl which accepts the "auto|2.6|2.7|2.8|2.9|3.0" etc etc values + ifelse(index([$1], [wxversion]), [-1],, + [ + AC_ARG_WITH([wxversion], + AC_HELP_STRING([--with-wxversion], + [Build against a specific version of wxWidgets (default is auto)]), + [], [withval="auto"]) + + dnl Show a message to the user about this option + AC_MSG_CHECKING([for the --with-wxversion option]) + if test "$withval" = "auto" ; then + AC_MSG_RESULT([will be automatically detected]) + WX_RELEASE="" + else + + wx_requested_major_version=`echo $withval | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).*/\1/'` + wx_requested_minor_version=`echo $withval | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).*/\2/'` + + dnl both vars above must be exactly 1 digit + if test "${#wx_requested_major_version}" != "1" -o \ + "${#wx_requested_minor_version}" != "1" ; then + AC_MSG_ERROR([ + Unrecognized option value (allowed values: auto, 2.6, 2.7, 2.8, 2.9, 3.0) + ]) + fi + + WX_RELEASE="$wx_requested_major_version"".""$wx_requested_minor_version" + AC_MSG_RESULT([$WX_RELEASE]) + fi + ]) + + if test "$WX_DEBUG_CONFIGURE" = "1"; then + echo "[[dbg]] DEBUG: $DEBUG, WX_DEBUG: $WX_DEBUG" + echo "[[dbg]] UNICODE: $UNICODE, WX_UNICODE: $WX_UNICODE" + echo "[[dbg]] SHARED: $SHARED, WX_SHARED: $WX_SHARED" + echo "[[dbg]] TOOLKIT: $TOOLKIT, WX_TOOLKIT: $WX_TOOLKIT" + echo "[[dbg]] VERSION: $VERSION, WX_RELEASE: $WX_RELEASE" + fi + ]) + + +dnl --------------------------------------------------------------------------- +dnl WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS +dnl +dnl Sets the WXCONFIG_FLAGS string using the SHARED,DEBUG,UNICODE variable values +dnl which were specified. +dnl Thus this macro needs to be called only once all options have been set. +dnl --------------------------------------------------------------------------- +AC_DEFUN([WX_CONVERT_STANDARD_OPTIONS_TO_WXCONFIG_FLAGS], + [ + if test "$WX_SHARED" = "1" ; then + WXCONFIG_FLAGS="--static=no " + elif test "$WX_SHARED" = "0" ; then + WXCONFIG_FLAGS="--static=yes " + fi + + if test "$WX_DEBUG" = "1" ; then + WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--debug=yes " + elif test "$WX_DEBUG" = "0" ; then + WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--debug=no " + fi + + dnl The user should have set WX_UNICODE=UNICODE + if test "$WX_UNICODE" = "1" ; then + WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=yes " + elif test "$WX_UNICODE" = "0" ; then + WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--unicode=no " + fi + + if test -n "$TOOLKIT" ; then + WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--toolkit=$TOOLKIT " + fi + + if test -n "$WX_RELEASE" ; then + WXCONFIG_FLAGS="$WXCONFIG_FLAGS""--version=$WX_RELEASE " + fi + + dnl strip out the last space of the string + WXCONFIG_FLAGS=${WXCONFIG_FLAGS% } + + if test "$WX_DEBUG_CONFIGURE" = "1"; then + echo "[[dbg]] WXCONFIG_FLAGS: $WXCONFIG_FLAGS" + fi + ]) + + +dnl --------------------------------------------------------------------------- +dnl _WX_SELECTEDCONFIG_CHECKFOR([RESULTVAR], [STRING], [MSG]) +dnl +dnl Sets WX_$RESULTVAR to the value of $RESULTVAR if it's defined. Otherwise, +dnl auto-detect the value by checking for the presence of STRING in +dnl $WX_SELECTEDCONFIG (which is supposed to be set by caller) and set +dnl WX_$RESULTVAR to either 0 or 1, also outputting "yes" or "no" after MSG. +dnl --------------------------------------------------------------------------- +AC_DEFUN([_WX_SELECTEDCONFIG_CHECKFOR], + [ + if test -z "$$1" ; then + + dnl The user does not have particular preferences for this option; + dnl so we will detect the wxWidgets relative build setting and use it + AC_MSG_CHECKING([$3]) + + dnl set WX_$1 variable to 1 if the $WX_SELECTEDCONFIG contains the $2 + dnl string or to 0 otherwise. + dnl NOTE: 'expr match STRING REGEXP' cannot be used since on Mac it + dnl doesn't work; we use 'expr STRING : REGEXP' instead + WX_$1=$(expr "$WX_SELECTEDCONFIG" : ".*$2.*") + + if test "$WX_$1" != "0"; then + WX_$1=1 + AC_MSG_RESULT([yes]) + else + WX_$1=0 + AC_MSG_RESULT([no]) + fi + else + + dnl Use the setting given by the user + WX_$1=$$1 + fi + ]) + +dnl --------------------------------------------------------------------------- +dnl WX_DETECT_STANDARD_OPTION_VALUES +dnl +dnl Detects the values of the following variables: +dnl 1) WX_RELEASE +dnl 2) WX_UNICODE +dnl 3) WX_DEBUG +dnl 4) WX_SHARED (and also WX_STATIC) +dnl 5) WX_PORT +dnl from the previously selected wxWidgets build; this macro in fact must be +dnl called *after* calling the WX_CONFIG_CHECK macro. +dnl +dnl Note that the WX_VERSION_MAJOR, WX_VERSION_MINOR symbols are already set +dnl by WX_CONFIG_CHECK macro +dnl --------------------------------------------------------------------------- +AC_DEFUN([WX_DETECT_STANDARD_OPTION_VALUES], + [ + dnl IMPORTANT: WX_VERSION contains all three major.minor.micro digits, + dnl while WX_RELEASE only the major.minor ones. + WX_RELEASE="$WX_VERSION_MAJOR""$WX_VERSION_MINOR" + if test $WX_RELEASE -lt 26 ; then + + AC_MSG_ERROR([ + Cannot detect the wxWidgets configuration for the selected wxWidgets build + since its version is $WX_VERSION < 2.6.0; please install a newer + version of wxWidgets. + ]) + fi + + dnl The wx-config we are using understands the "--selected_config" + dnl option which returns an easy-parseable string ! + WX_SELECTEDCONFIG=$($WX_CONFIG_WITH_ARGS --selected_config) + + if test "$WX_DEBUG_CONFIGURE" = "1"; then + echo "[[dbg]] Using wx-config --selected-config" + echo "[[dbg]] WX_SELECTEDCONFIG: $WX_SELECTEDCONFIG" + fi + + dnl we could test directly for WX_SHARED with a line like: + dnl _WX_SELECTEDCONFIG_CHECKFOR([SHARED], [shared], + dnl [if wxWidgets was built in SHARED mode]) + dnl but wx-config --selected-config DOES NOT outputs the 'shared' + dnl word when wx was built in shared mode; it rather outputs the + dnl 'static' word when built in static mode. + if test "$WX_SHARED" = "1"; then + STATIC=0 + elif test "$WX_SHARED" = "0"; then + STATIC=1 + fi + + dnl Now set the WX_UNICODE, WX_DEBUG, WX_STATIC variables + _WX_SELECTEDCONFIG_CHECKFOR([UNICODE], [unicode], + [if wxWidgets was built with UNICODE enabled]) + _WX_SELECTEDCONFIG_CHECKFOR([DEBUG], [debug], + [if wxWidgets was built in DEBUG mode]) + _WX_SELECTEDCONFIG_CHECKFOR([STATIC], [static], + [if wxWidgets was built in STATIC mode]) + + dnl init WX_SHARED from WX_STATIC + if test "$WX_STATIC" != "0"; then + WX_SHARED=0 + else + WX_SHARED=1 + fi + + AC_SUBST(WX_UNICODE) + AC_SUBST(WX_DEBUG) + AC_SUBST(WX_SHARED) + + dnl detect the WX_PORT to use + if test -z "$TOOLKIT" ; then + + dnl The user does not have particular preferences for this option; + dnl so we will detect the wxWidgets relative build setting and use it + AC_MSG_CHECKING([which wxWidgets toolkit was selected]) + + WX_GTKPORT1=$(expr "$WX_SELECTEDCONFIG" : ".*gtk1.*") + WX_GTKPORT2=$(expr "$WX_SELECTEDCONFIG" : ".*gtk2.*") + WX_GTKPORT3=$(expr "$WX_SELECTEDCONFIG" : ".*gtk3.*") + WX_MSWPORT=$(expr "$WX_SELECTEDCONFIG" : ".*msw.*") + WX_MOTIFPORT=$(expr "$WX_SELECTEDCONFIG" : ".*motif.*") + WX_OSXCOCOAPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_cocoa.*") + WX_OSXCARBONPORT=$(expr "$WX_SELECTEDCONFIG" : ".*osx_carbon.*") + WX_X11PORT=$(expr "$WX_SELECTEDCONFIG" : ".*x11.*") + WX_DFBPORT=$(expr "$WX_SELECTEDCONFIG" : ".*dfb.*") + WX_BASEPORT=$(expr "$WX_SELECTEDCONFIG" : ".*base.*") + + WX_PORT="unknown" + if test "$WX_GTKPORT1" != "0"; then WX_PORT="gtk1"; fi + if test "$WX_GTKPORT2" != "0"; then WX_PORT="gtk2"; fi + if test "$WX_GTKPORT3" != "0"; then WX_PORT="gtk3"; fi + if test "$WX_MSWPORT" != "0"; then WX_PORT="msw"; fi + if test "$WX_MOTIFPORT" != "0"; then WX_PORT="motif"; fi + if test "$WX_OSXCOCOAPORT" != "0"; then WX_PORT="osx_cocoa"; fi + if test "$WX_OSXCARBONPORT" != "0"; then WX_PORT="osx_carbon"; fi + if test "$WX_X11PORT" != "0"; then WX_PORT="x11"; fi + if test "$WX_DFBPORT" != "0"; then WX_PORT="dfb"; fi + if test "$WX_BASEPORT" != "0"; then WX_PORT="base"; fi + + dnl NOTE: backward-compatible check for wx2.8; in wx2.9 the mac + dnl ports are called 'osx_cocoa' and 'osx_carbon' (see above) + WX_MACPORT=$(expr "$WX_SELECTEDCONFIG" : ".*mac.*") + if test "$WX_MACPORT" != "0"; then WX_PORT="mac"; fi + + dnl check at least one of the WX_*PORT has been set ! + + if test "$WX_PORT" = "unknown" ; then + AC_MSG_ERROR([ + Cannot detect the currently installed wxWidgets port ! + Please check your 'wx-config --cxxflags'... + ]) + fi + + AC_MSG_RESULT([$WX_PORT]) + else + dnl Use the setting given by the user + WX_PORT=$TOOLKIT + fi + + AC_SUBST(WX_PORT) + + if test "$WX_DEBUG_CONFIGURE" = "1"; then + echo "[[dbg]] Values of all WX_* options after final detection:" + echo "[[dbg]] WX_DEBUG: $WX_DEBUG" + echo "[[dbg]] WX_UNICODE: $WX_UNICODE" + echo "[[dbg]] WX_SHARED: $WX_SHARED" + echo "[[dbg]] WX_RELEASE: $WX_RELEASE" + echo "[[dbg]] WX_PORT: $WX_PORT" + fi + + dnl Avoid problem described in the WX_STANDARD_OPTIONS which happens when + dnl the user gives the options: + dnl ./configure --enable-shared --without-wxshared + dnl or just do + dnl ./configure --enable-shared + dnl but there is only a static build of wxWidgets available. + if test "$WX_SHARED" = "0" -a "$SHARED" = "1"; then + AC_MSG_ERROR([ + Cannot build shared library against a static build of wxWidgets ! + This error happens because the wxWidgets build which was selected + has been detected as static while you asked to build $PACKAGE_NAME + as shared library and this is not possible. + Use the '--disable-shared' option to build $PACKAGE_NAME + as static library or '--with-wxshared' to use wxWidgets as shared library. + ]) + fi + + dnl now we can finally update the options to their final values if they + dnl were not already set + if test -z "$UNICODE" ; then + UNICODE=$WX_UNICODE + fi + if test -z "$SHARED" ; then + SHARED=$WX_SHARED + fi + if test -z "$TOOLKIT" ; then + TOOLKIT=$WX_PORT + fi + + dnl respect the DEBUG variable adding the optimize/debug flags and also + dnl define a BUILD variable in case the user wants to use it + dnl + dnl NOTE: the CXXFLAGS are merged together with the CPPFLAGS so we + dnl don't need to set them, too + if test "$DEBUG" = "1"; then + BUILD="debug" + CXXFLAGS="$CXXFLAGS -g -O0" + CFLAGS="$CFLAGS -g -O0" + elif test "$DEBUG" = "0"; then + BUILD="release" + CXXFLAGS="$CXXFLAGS -O2" + CFLAGS="$CFLAGS -O2" + fi + ]) + +dnl --------------------------------------------------------------------------- +dnl WX_BOOLOPT_SUMMARY([name of the boolean variable to show summary for], +dnl [what to print when var is 1], +dnl [what to print when var is 0]) +dnl +dnl Prints $2 when variable $1 == 1 and prints $3 when variable $1 == 0. +dnl This macro mainly exists just to make configure.ac scripts more readable. +dnl +dnl NOTE: you need to use the [" my message"] syntax for 2nd and 3rd arguments +dnl if you want that m4 avoid to throw away the spaces prefixed to the +dnl argument value. +dnl --------------------------------------------------------------------------- +AC_DEFUN([WX_BOOLOPT_SUMMARY], + [ + if test "x$$1" = "x1" ; then + echo $2 + elif test "x$$1" = "x0" ; then + echo $3 + else + echo "$1 is $$1" + fi + ]) + +dnl --------------------------------------------------------------------------- +dnl WX_STANDARD_OPTIONS_SUMMARY_MSG +dnl +dnl Shows a summary message to the user about the WX_* variable contents. +dnl This macro is used typically at the end of the configure script. +dnl --------------------------------------------------------------------------- +AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG], + [ + echo + echo " The wxWidgets build which will be used by $PACKAGE_NAME $PACKAGE_VERSION" + echo " has the following settings:" + WX_BOOLOPT_SUMMARY([WX_DEBUG], [" - DEBUG build"], [" - RELEASE build"]) + WX_BOOLOPT_SUMMARY([WX_UNICODE], [" - UNICODE mode"], [" - ANSI mode"]) + WX_BOOLOPT_SUMMARY([WX_SHARED], [" - SHARED mode"], [" - STATIC mode"]) + echo " - VERSION: $WX_VERSION" + echo " - PORT: $WX_PORT" + ]) + + +dnl --------------------------------------------------------------------------- +dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN, WX_STANDARD_OPTIONS_SUMMARY_MSG_END +dnl +dnl Like WX_STANDARD_OPTIONS_SUMMARY_MSG macro but these two macros also gives info +dnl about the configuration of the package which used the wxpresets. +dnl +dnl Typical usage: +dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN +dnl echo " - Package setting 1: $SETTING1" +dnl echo " - Package setting 2: $SETTING1" +dnl ... +dnl WX_STANDARD_OPTIONS_SUMMARY_MSG_END +dnl +dnl --------------------------------------------------------------------------- +AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG_BEGIN], + [ + echo + echo " ----------------------------------------------------------------" + echo " Configuration for $PACKAGE_NAME $PACKAGE_VERSION successfully completed." + echo " Summary of main configuration settings for $PACKAGE_NAME:" + WX_BOOLOPT_SUMMARY([DEBUG], [" - DEBUG build"], [" - RELEASE build"]) + WX_BOOLOPT_SUMMARY([UNICODE], [" - UNICODE mode"], [" - ANSI mode"]) + WX_BOOLOPT_SUMMARY([SHARED], [" - SHARED mode"], [" - STATIC mode"]) + ]) + +AC_DEFUN([WX_STANDARD_OPTIONS_SUMMARY_MSG_END], + [ + WX_STANDARD_OPTIONS_SUMMARY_MSG + echo + echo " Now, just run make." + echo " ----------------------------------------------------------------" + echo + ]) + + +dnl --------------------------------------------------------------------------- +dnl Deprecated macro wrappers +dnl --------------------------------------------------------------------------- + +AC_DEFUN([AM_OPTIONS_WXCONFIG], [WX_CONFIG_OPTIONS]) +AC_DEFUN([AM_PATH_WXCONFIG], [ + WX_CONFIG_CHECK([$1],[$2],[$3],[$4],[$5]) +]) +AC_DEFUN([AM_PATH_WXRC], [WXRC_CHECK([$1],[$2])]) + +# Copyright (C) 2002-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -32,10 +1601,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.]) # 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.15' +[am__api_version='1.16' 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.15], [], +m4_if([$1], [1.16.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -51,14 +1620,14 @@ m4_define([_AM_AUTOCONF_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.15])dnl +[AM_AUTOMAKE_VERSION([1.16.3])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-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -110,7 +1679,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd` # AM_CONDITIONAL -*- Autoconf -*- -# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -141,7 +1710,7 @@ AC_CONFIG_COMMANDS_PRE( Usually this means the macro was only invoked conditionally.]]) fi])]) -# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -332,13 +1901,12 @@ _AM_SUBST_NOTMAKE([am__nodep])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 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_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], @@ -346,49 +1914,43 @@ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], # Older Autoconf 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 + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + AS_CASE([$CONFIG_FILES], + [*\'*], [eval set x "$CONFIG_FILES"], + [*], [set x $CONFIG_FILES]) shift - for mf + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_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 + am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: 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"` - # 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'`; 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 + sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`AS_DIRNAME(["$am_mf"])` + am_filepart=`AS_BASENAME(["$am_mf"])` + AM_RUN_LOG([cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles]) || am_rc=$? done + if test $am_rc -ne 0; then + AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE="gmake" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking).]) + fi + AS_UNSET([am_dirpart]) + AS_UNSET([am_filepart]) + AS_UNSET([am_mf]) + AS_UNSET([am_rc]) + rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS @@ -397,18 +1959,17 @@ AC_DEFUN([_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. +# This code is only required when automatic dependency tracking is enabled. +# This creates each '.Po' and '.Plo' makefile fragment that we'll 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"]) -]) + [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- -# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -495,8 +2056,8 @@ AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: -# -# +# +# AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. @@ -563,7 +2124,7 @@ END Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . +that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM @@ -605,7 +2166,7 @@ for _am_header in $config_headers :; do done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -626,7 +2187,7 @@ if test x"${install_sh+set}" != xset; then fi AC_SUBST([install_sh])]) -# Copyright (C) 2003-2014 Free Software Foundation, Inc. +# Copyright (C) 2003-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -647,7 +2208,7 @@ AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -655,49 +2216,42 @@ AC_SUBST([am__leading_dot])]) # AM_MAKE_INCLUDE() # ----------------- -# Check to see how make treats includes. +# Check whether make has an 'include' directive that can support all +# the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], -[am_make=${MAKE-make} -cat > confinc << 'END' +[AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) +cat > confinc.mk << 'END' am__doit: - @echo this is the am__doit target + @echo this is the am__doit target >confinc.out .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 -]) +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) + AS_CASE([$?:`cat confinc.out 2>/dev/null`], + ['0:this is the am__doit target'], + [AS_CASE([$s], + [BSD], [am__include='.include' am__quote='"'], + [am__include='include' am__quote=''])]) + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +AC_MSG_RESULT([${_am_result}]) +AC_SUBST([am__include])]) +AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- -# Copyright (C) 1997-2014 Free Software Foundation, Inc. +# Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -718,12 +2272,7 @@ 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 + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then @@ -736,7 +2285,7 @@ fi # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -765,7 +2314,7 @@ AC_DEFUN([_AM_SET_OPTIONS], AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) -# Copyright (C) 1999-2014 Free Software Foundation, Inc. +# Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -812,7 +2361,7 @@ AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -831,7 +2380,7 @@ AC_DEFUN([AM_RUN_LOG], # Check to make sure that the build environment is sane. -*- Autoconf -*- -# Copyright (C) 1996-2014 Free Software Foundation, Inc. +# Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -912,7 +2461,7 @@ AC_CONFIG_COMMANDS_PRE( rm -f conftest.file ]) -# Copyright (C) 2009-2014 Free Software Foundation, Inc. +# Copyright (C) 2009-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -972,7 +2521,7 @@ AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) -# Copyright (C) 2001-2014 Free Software Foundation, Inc. +# Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1000,7 +2549,7 @@ fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) -# Copyright (C) 2006-2014 Free Software Foundation, Inc. +# Copyright (C) 2006-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1019,7 +2568,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- -# Copyright (C) 2004-2014 Free Software Foundation, Inc. +# Copyright (C) 2004-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -1150,4 +2699,3 @@ AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR -m4_include([allegro.m4]) diff --git a/allegro.m4 b/allegro.m4 deleted file mode 100644 index 364cbac..0000000 --- a/allegro.m4 +++ /dev/null @@ -1,192 +0,0 @@ -# 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_error; 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 -]) diff --git a/configure b/configure index 3fa2a2d..9075b97 100755 --- a/configure +++ b/configure @@ -1,11 +1,12 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for PCem v12. +# Generated by GNU Autoconf 2.71 for PCem v17. # -# Report bugs to >. +# Report bugs to >. # # -# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -16,14 +17,16 @@ # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (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 +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -33,46 +36,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. 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 +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; 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 || @@ -81,13 +84,6 @@ if test "${PATH_SEPARATOR+set}" != set; then 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. as_myself= case $0 in #(( @@ -96,8 +92,12 @@ case $0 in #(( 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -109,30 +109,10 @@ 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 + printf "%s\n" "$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 # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. @@ -154,20 +134,22 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 -as_fn_exit 255 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then - as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + as_bourne_compatible="as_nop=: +if test \${ZSH_VERSION+y} && (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 +else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( @@ -187,41 +169,52 @@ 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 : +if ( set x; as_fn_ret_success y && test x = \"\$1\" ) +then : -else +else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 +blah=\$(echo \$(echo blah)) +test x\"\$blah\" = xblah || exit 1 test -x / || 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 : + if (eval "$as_required") 2>/dev/null +then : as_have_required=yes -else +else $as_nop as_have_required=no fi - if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null +then : -else +else $as_nop 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=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac 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 + 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 : + as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 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 : + if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null +then : break 2 fi fi @@ -229,14 +222,21 @@ fi 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 $as_found +then : + +else $as_nop + if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null +then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi +fi - if test "x$CONFIG_SHELL" != x; then : + if test "x$CONFIG_SHELL" != x +then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also @@ -254,22 +254,23 @@ esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. -$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 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." + if test x$as_have_required = xno +then : + printf "%s\n" "$0: This script requires a shell more modern than all" + printf "%s\n" "$0: the shells that I found on your system." + if test ${ZSH_VERSION+y} ; then + printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" + printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else - $as_echo "$0: Please tell bug-autoconf@gnu.org and Sarah 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." + printf "%s\n" "$0: Please tell bug-autoconf@gnu.org and Sarah Walker +$0: about your system, including +$0: any error possibly output before this message. Then +$0: install a modern shell, or manually run the script +$0: under such a shell if you do have one." fi exit 1 fi @@ -293,6 +294,7 @@ as_fn_unset () } as_unset=as_fn_unset + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -310,6 +312,14 @@ as_fn_exit () as_fn_set_status $1 exit $1 } # as_fn_exit +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_mkdir_p # ------------- @@ -324,7 +334,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -333,7 +343,7 @@ $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" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -372,12 +382,13 @@ as_fn_executable_p () # 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 : +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 +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -389,18 +400,27 @@ fi # as_fn_append # 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 : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith +# as_fn_nop +# --------- +# Do nothing but, unlike ":", preserve the value of $?. +as_fn_nop () +{ + return $? +} +as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- @@ -412,9 +432,9 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error @@ -441,7 +461,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -485,7 +505,7 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits 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; } + { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall @@ -499,6 +519,10 @@ as_cr_alnum=$as_cr_Letters$as_cr_digits exit } + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -512,6 +536,13 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -579,26 +610,61 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='PCem' PACKAGE_TARNAME='pcem' -PACKAGE_VERSION='v12' -PACKAGE_STRING='PCem v12' -PACKAGE_BUGREPORT='Sarah Walker ' +PACKAGE_VERSION='v17' +PACKAGE_STRING='PCem v17' +PACKAGE_BUGREPORT='Sarah Walker ' PACKAGE_URL='' ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS -allegro_LIBS -allegro_CFLAGS -ALLEGRO_CONFIG +OS_MACOSX_FALSE +OS_MACOSX_TRUE +OS_OTHER_FALSE +OS_OTHER_TRUE +OS_WINDOWS_FALSE +OS_WINDOWS_TRUE OS_LINUX_FALSE OS_LINUX_TRUE -OS_WIN_FALSE -OS_WIN_TRUE +WX_VERSION_MICRO +WX_VERSION_MINOR +WX_VERSION_MAJOR +WX_RESCOMP +WX_VERSION +WX_LIBS_STATIC +WX_LIBS +WX_CXXFLAGS_ONLY +WX_CFLAGS_ONLY +WX_CXXFLAGS +WX_CFLAGS +WX_CPPFLAGS +WX_CONFIG_PATH +SDL2_CONFIG +SDL_LIBS +SDL_CFLAGS +PKG_CONFIG_LIBDIR +PKG_CONFIG_PATH +PKG_CONFIG +SDL2_FRAMEWORK +HAS_OFF64T_FALSE +HAS_OFF64T_TRUE +USE_ALSA_FALSE +USE_ALSA_TRUE +USE_NETWORKING_FALSE +USE_NETWORKING_TRUE +USE_WX_FALSE +USE_WX_TRUE +CPU_ARM64_FALSE +CPU_ARM64_TRUE +CPU_ARM_FALSE +CPU_ARM_TRUE CPU_X86_64_FALSE CPU_X86_64_TRUE CPU_I386_FALSE CPU_I386_TRUE +RELEASE_BUILD_FALSE +RELEASE_BUILD_TRUE am__fastdepCXX_FALSE am__fastdepCXX_TRUE CXXDEPMODE @@ -612,7 +678,6 @@ am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE -am__quote am__include DEPDIR OBJEXT @@ -695,16 +760,25 @@ PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR -SHELL' +SHELL +am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking +enable_release_build enable_debug -with_allegro_prefix -with_allegro_exec_prefix -enable_allegrotest +enable_networking +enable_alsa +with_sdl_prefix +with_sdl_exec_prefix +enable_sdltest +enable_sdlframework +with_wxdir +with_wx_config +with_wx_prefix +with_wx_exec_prefix ' ac_precious_vars='build_alias host_alias @@ -716,7 +790,13 @@ LIBS CPPFLAGS CXX CXXFLAGS -CCC' +CCC +SDL2_FRAMEWORK +PKG_CONFIG +PKG_CONFIG_PATH +PKG_CONFIG_LIBDIR +SDL_CFLAGS +SDL_LIBS' # Initialize some variables set by options. @@ -785,8 +865,6 @@ do *) ac_optarg=yes ;; esac - # Accept the important Cygnus configure options, so we can diagnose typos. - case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; @@ -827,9 +905,9 @@ do 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" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -853,9 +931,9 @@ do 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" + as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" @@ -1066,9 +1144,9 @@ do 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" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1082,9 +1160,9 @@ do 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" + as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt - ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" @@ -1128,9 +1206,9 @@ Try \`$0 --help' for more information" *) # FIXME: should be removed in autoconf 3.0. - $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + printf "%s\n" "$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 + printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; @@ -1146,7 +1224,7 @@ 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 ;; + *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1210,7 +1288,7 @@ $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" | +printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -1267,7 +1345,7 @@ 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 v12 to adapt to many kinds of systems. +\`configure' configures PCem v17 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1338,7 +1416,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of PCem v12:";; + short | recursive ) echo "Configuration of PCem v17:";; esac cat <<\_ACEOF @@ -1352,14 +1430,23 @@ Optional Features: do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build + --enable-release-build build for release --enable-debug build debug executable - --disable-allegrotest Do not try to compile and run a test LIBallegro program + --enable-networking enable networking + --enable-alsa use ALSA for MIDI + --disable-sdltest Do not try to compile and run a test SDL program + --disable-sdlframework Do not search for SDL2.framework 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) + --with-sdl-prefix=PFX Prefix where SDL is installed (optional) + --with-sdl-exec-prefix=PFX Exec prefix where SDL is installed (optional) + --with-wxdir=PATH Use uninstalled version of wxWidgets in PATH + --with-wx-config=CONFIG wx-config script to use (optional) + --with-wx-prefix=PREFIX Prefix where wxWidgets is installed (optional) + --with-wx-exec-prefix=PREFIX + Exec prefix where wxWidgets is installed (optional) Some influential environment variables: CC C compiler command @@ -1371,11 +1458,20 @@ Some influential environment variables: you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags + SDL2_FRAMEWORK + Path to SDL2.framework + PKG_CONFIG path to pkg-config utility + PKG_CONFIG_PATH + directories to add to pkg-config's search path + PKG_CONFIG_LIBDIR + path overriding pkg-config's built-in search path + SDL_CFLAGS C compiler flags for SDL, overriding pkg-config + SDL_LIBS linker flags for SDL, overriding pkg-config 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 >. +Report bugs to >. _ACEOF ac_status=$? fi @@ -1391,9 +1487,9 @@ if test "$ac_init_help" = "recursive"; then case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$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|/||'` + ac_top_builddir_sub=`printf "%s\n" "$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/ ;; @@ -1421,7 +1517,8 @@ esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } - # Check for guested configure. + # Check for configure.gnu first; this name is used for a wrapper for + # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive @@ -1429,7 +1526,7 @@ ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix echo && $SHELL "$ac_srcdir/configure" --help=recursive else - $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done @@ -1438,10 +1535,10 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -PCem configure v12 -generated by GNU Autoconf 2.69 +PCem configure v17 +generated by GNU Autoconf 2.71 -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1458,14 +1555,14 @@ fi ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam 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 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1473,14 +1570,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$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 : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1496,14 +1594,14 @@ fi ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - rm -f conftest.$ac_objext + rm -f conftest.$ac_objext conftest.beam 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 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1511,14 +1609,15 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$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 : + } && test -s conftest.$ac_objext +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1528,62 +1627,20 @@ fi } # 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; ${as_lineno_stack:+:} 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 + rm -f conftest.$ac_objext conftest.beam 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 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -1591,17 +1648,18 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$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 || test -x conftest$ac_exeext - }; then : + } +then : ac_retval=0 -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 @@ -1615,14 +1673,77 @@ fi as_fn_set_status $ac_retval } # ac_fn_c_try_link + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to run 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\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + printf "%s\n" "$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\"" +printf "%s\n" "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; } +then : + ac_retval=0 +else $as_nop + printf "%s\n" "$as_me: program exited with status $ac_status" >&5 + printf "%s\n" "$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; ${as_lineno_stack:+:} unset as_lineno + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run +ac_configure_args_raw= +for ac_arg +do + case $ac_arg in + *\'*) + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append ac_configure_args_raw " '$ac_arg'" +done + +case $ac_configure_args_raw in + *$as_nl*) + ac_safe_unquote= ;; + *) + ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. + ac_unsafe_a="$ac_unsafe_z#~" + ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" + ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; +esac + 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 v12, which was -generated by GNU Autoconf 2.69. Invocation command line was +It was created by PCem $as_me v17, which was +generated by GNU Autoconf 2.71. Invocation command line was - $ $0 $@ + $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log @@ -1655,8 +1776,12 @@ 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" + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS @@ -1691,7 +1816,7 @@ do | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) - ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; @@ -1726,11 +1851,13 @@ done # 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=$? + # Sanitize IFS. + IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo - $as_echo "## ---------------- ## + printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo @@ -1741,8 +1868,8 @@ trap 'exit_status=$? 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;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -1766,7 +1893,7 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; ) echo - $as_echo "## ----------------- ## + printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo @@ -1774,14 +1901,14 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo @@ -1789,15 +1916,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; do eval ac_val=\$$ac_var case $ac_val in - *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac - $as_echo "$ac_var='\''$ac_val'\''" + printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then - $as_echo "## ----------- ## + printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo @@ -1805,8 +1932,8 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; echo fi test "$ac_signal" != 0 && - $as_echo "$as_me: caught signal $ac_signal" - $as_echo "$as_me: exit $exit_status" + printf "%s\n" "$as_me: caught signal $ac_signal" + printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && @@ -1820,63 +1947,48 @@ 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 +printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. -cat >>confdefs.h <<_ACEOF -#define PACKAGE_NAME "$PACKAGE_NAME" -_ACEOF +printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_TARNAME "$PACKAGE_TARNAME" -_ACEOF +printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_VERSION "$PACKAGE_VERSION" -_ACEOF +printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_STRING "$PACKAGE_STRING" -_ACEOF +printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" -_ACEOF +printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define PACKAGE_URL "$PACKAGE_URL" -_ACEOF +printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # 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 - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then - ac_site_file1=$prefix/share/config.site - ac_site_file2=$prefix/etc/config.site + ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else - ac_site_file1=$ac_default_prefix/share/config.site - ac_site_file2=$ac_default_prefix/etc/config.site + ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi -for ac_site_file in "$ac_site_file1" "$ac_site_file2" + +for ac_site_file in $ac_site_files 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;} + case $ac_site_file in #( + */*) : + ;; #( + *) : + ac_site_file=./$ac_site_file ;; +esac + if test -f "$ac_site_file" && test -r "$ac_site_file"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi @@ -1886,19 +1998,641 @@ 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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +printf "%s\n" "$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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi +# Test code for whether the C compiler supports C89 (global declarations) +ac_c_conftest_c89_globals=' +/* Does the compiler advertise C89 conformance? + Do not test the value of __STDC__, because some compilers set it to 0 + while being otherwise adequately conformant. */ +#if !defined __STDC__ +# error "Compiler does not advertise C89 conformance" +#endif + +#include +#include +struct stat; +/* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ +struct buf { int x; }; +struct buf * (*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 do not provoke an error unfortunately, instead are silently treated + as an "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 is necessary to write \x00 == 0 to get something + that is 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 **, int *(*)(struct buf *, struct stat *, int), + int, int);' + +# Test code for whether the C compiler supports C89 (body of main). +ac_c_conftest_c89_main=' +ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); +' + +# Test code for whether the C compiler supports C99 (global declarations) +ac_c_conftest_c99_globals=' +// Does the compiler advertise C99 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L +# error "Compiler does not advertise C99 conformance" +#endif + +#include +extern int puts (const char *); +extern int printf (const char *, ...); +extern int dprintf (int, const char *, ...); +extern void *malloc (size_t); + +// Check varargs macros. These examples are taken from C99 6.10.3.5. +// dprintf is used instead of fprintf to avoid needing to declare +// FILE and stderr. +#define debug(...) dprintf (2, __VA_ARGS__) +#define showlist(...) puts (#__VA_ARGS__) +#define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) +static void +test_varargs_macros (void) +{ + int x = 1234; + int y = 5678; + debug ("Flag"); + debug ("X = %d\n", x); + showlist (The first, second, and third items.); + report (x>y, "x is %d but y is %d", x, y); +} + +// Check long long types. +#define BIG64 18446744073709551615ull +#define BIG32 4294967295ul +#define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) +#if !BIG_OK + #error "your preprocessor is broken" +#endif +#if BIG_OK +#else + #error "your preprocessor is broken" +#endif +static long long int bignum = -9223372036854775807LL; +static unsigned long long int ubignum = BIG64; + +struct incomplete_array +{ + int datasize; + double data[]; +}; + +struct named_init { + int number; + const wchar_t *name; + double average; +}; + +typedef const char *ccp; + +static inline int +test_restrict (ccp restrict text) +{ + // See if C++-style comments work. + // Iterate through items via the restricted pointer. + // Also check for declarations in for loops. + for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) + continue; + return 0; +} + +// Check varargs and va_copy. +static bool +test_varargs (const char *format, ...) +{ + va_list args; + va_start (args, format); + va_list args_copy; + va_copy (args_copy, args); + + const char *str = ""; + int number = 0; + float fnumber = 0; + + while (*format) + { + switch (*format++) + { + case '\''s'\'': // string + str = va_arg (args_copy, const char *); + break; + case '\''d'\'': // int + number = va_arg (args_copy, int); + break; + case '\''f'\'': // float + fnumber = va_arg (args_copy, double); + break; + default: + break; + } + } + va_end (args_copy); + va_end (args); + + return *str && number && fnumber; +} +' + +# Test code for whether the C compiler supports C99 (body of main). +ac_c_conftest_c99_main=' + // Check bool. + _Bool success = false; + success |= (argc != 0); + + // Check restrict. + if (test_restrict ("String literal") == 0) + success = true; + char *restrict newvar = "Another string"; + + // Check varargs. + success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); + test_varargs_macros (); + + // Check flexible array members. + struct incomplete_array *ia = + malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); + ia->datasize = 10; + for (int i = 0; i < ia->datasize; ++i) + ia->data[i] = i * 1.234; + + // Check named initializers. + struct named_init ni = { + .number = 34, + .name = L"Test wide string", + .average = 543.34343, + }; + + ni.number = 58; + + int dynamic_array[ni.number]; + dynamic_array[0] = argv[0][0]; + dynamic_array[ni.number - 1] = 543; + + // work around unused variable warnings + ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' + || dynamic_array[ni.number - 1] != 543); +' + +# Test code for whether the C compiler supports C11 (global declarations) +ac_c_conftest_c11_globals=' +// Does the compiler advertise C11 conformance? +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L +# error "Compiler does not advertise C11 conformance" +#endif + +// Check _Alignas. +char _Alignas (double) aligned_as_double; +char _Alignas (0) no_special_alignment; +extern char aligned_as_int; +char _Alignas (0) _Alignas (int) aligned_as_int; + +// Check _Alignof. +enum +{ + int_alignment = _Alignof (int), + int_array_alignment = _Alignof (int[100]), + char_alignment = _Alignof (char) +}; +_Static_assert (0 < -_Alignof (int), "_Alignof is signed"); + +// Check _Noreturn. +int _Noreturn does_not_return (void) { for (;;) continue; } + +// Check _Static_assert. +struct test_static_assert +{ + int x; + _Static_assert (sizeof (int) <= sizeof (long int), + "_Static_assert does not work in struct"); + long int y; +}; + +// Check UTF-8 literals. +#define u8 syntax error! +char const utf8_literal[] = u8"happens to be ASCII" "another string"; + +// Check duplicate typedefs. +typedef long *long_ptr; +typedef long int *long_ptr; +typedef long_ptr long_ptr; + +// Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. +struct anonymous +{ + union { + struct { int i; int j; }; + struct { int k; long int l; } w; + }; + int m; +} v1; +' + +# Test code for whether the C compiler supports C11 (body of main). +ac_c_conftest_c11_main=' + _Static_assert ((offsetof (struct anonymous, i) + == offsetof (struct anonymous, w.k)), + "Anonymous union alignment botch"); + v1.i = 2; + v1.w.k = 5; + ok |= v1.i != 5; +' + +# Test code for whether the C compiler supports C11 (complete). +ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} +${ac_c_conftest_c11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + ${ac_c_conftest_c11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C99 (complete). +ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} +${ac_c_conftest_c99_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + ${ac_c_conftest_c99_main} + return ok; +} +" + +# Test code for whether the C compiler supports C89 (complete). +ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_c_conftest_c89_main} + return ok; +} +" + +# Test code for whether the C++ compiler supports C++98 (global declarations) +ac_cxx_conftest_cxx98_globals=' +// Does the compiler advertise C++98 conformance? +#if !defined __cplusplus || __cplusplus < 199711L +# error "Compiler does not advertise C++98 conformance" +#endif + +// These inclusions are to reject old compilers that +// lack the unsuffixed header files. +#include +#include + +// and are *not* freestanding headers in C++98. +extern void assert (int); +namespace std { + extern int strcmp (const char *, const char *); +} + +// Namespaces, exceptions, and templates were all added after "C++ 2.0". +using std::exception; +using std::strcmp; + +namespace { + +void test_exception_syntax() +{ + try { + throw "test"; + } catch (const char *s) { + // Extra parentheses suppress a warning when building autoconf itself, + // due to lint rules shared with more typical C programs. + assert (!(strcmp) (s, "test")); + } +} + +template struct test_template +{ + T const val; + explicit test_template(T t) : val(t) {} + template T add(U u) { return static_cast(u) + val; } +}; + +} // anonymous namespace +' + +# Test code for whether the C++ compiler supports C++98 (body of main) +ac_cxx_conftest_cxx98_main=' + assert (argc); + assert (! argv[0]); +{ + test_exception_syntax (); + test_template tt (2.0); + assert (tt.add (4) == 6.0); + assert (true && !false); +} +' + +# Test code for whether the C++ compiler supports C++11 (global declarations) +ac_cxx_conftest_cxx11_globals=' +// Does the compiler advertise C++ 2011 conformance? +#if !defined __cplusplus || __cplusplus < 201103L +# error "Compiler does not advertise C++11 conformance" +#endif + +namespace cxx11test +{ + constexpr int get_val() { return 20; } + + struct testinit + { + int i; + double d; + }; + + class delegate + { + public: + delegate(int n) : n(n) {} + delegate(): delegate(2354) {} + + virtual int getval() { return this->n; }; + protected: + int n; + }; + + class overridden : public delegate + { + public: + overridden(int n): delegate(n) {} + virtual int getval() override final { return this->n * 2; } + }; + + class nocopy + { + public: + nocopy(int i): i(i) {} + nocopy() = default; + nocopy(const nocopy&) = delete; + nocopy & operator=(const nocopy&) = delete; + private: + int i; + }; + + // for testing lambda expressions + template Ret eval(Fn f, Ret v) + { + return f(v); + } + + // for testing variadic templates and trailing return types + template auto sum(V first) -> V + { + return first; + } + template auto sum(V first, Args... rest) -> V + { + return first + sum(rest...); + } +} +' + +# Test code for whether the C++ compiler supports C++11 (body of main) +ac_cxx_conftest_cxx11_main=' +{ + // Test auto and decltype + auto a1 = 6538; + auto a2 = 48573953.4; + auto a3 = "String literal"; + + int total = 0; + for (auto i = a3; *i; ++i) { total += *i; } + + decltype(a2) a4 = 34895.034; +} +{ + // Test constexpr + short sa[cxx11test::get_val()] = { 0 }; +} +{ + // Test initializer lists + cxx11test::testinit il = { 4323, 435234.23544 }; +} +{ + // Test range-based for + int array[] = {9, 7, 13, 15, 4, 18, 12, 10, 5, 3, + 14, 19, 17, 8, 6, 20, 16, 2, 11, 1}; + for (auto &x : array) { x += 23; } +} +{ + // Test lambda expressions + using cxx11test::eval; + assert (eval ([](int x) { return x*2; }, 21) == 42); + double d = 2.0; + assert (eval ([&](double x) { return d += x; }, 3.0) == 5.0); + assert (d == 5.0); + assert (eval ([=](double x) mutable { return d += x; }, 4.0) == 9.0); + assert (d == 5.0); +} +{ + // Test use of variadic templates + using cxx11test::sum; + auto a = sum(1); + auto b = sum(1, 2); + auto c = sum(1.0, 2.0, 3.0); +} +{ + // Test constructor delegation + cxx11test::delegate d1; + cxx11test::delegate d2(); + cxx11test::delegate d3(45); +} +{ + // Test override and final + cxx11test::overridden o1(55464); +} +{ + // Test nullptr + char *c = nullptr; +} +{ + // Test template brackets + test_template<::test_template> v(test_template(12)); +} +{ + // Unicode literals + char const *utf8 = u8"UTF-8 string \u2500"; + char16_t const *utf16 = u"UTF-8 string \u2500"; + char32_t const *utf32 = U"UTF-32 string \u2500"; +} +' + +# Test code for whether the C compiler supports C++11 (complete). +ac_cxx_conftest_cxx11_program="${ac_cxx_conftest_cxx98_globals} +${ac_cxx_conftest_cxx11_globals} + +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + ${ac_cxx_conftest_cxx11_main} + return ok; +} +" + +# Test code for whether the C compiler supports C++98 (complete). +ac_cxx_conftest_cxx98_program="${ac_cxx_conftest_cxx98_globals} +int +main (int argc, char **argv) +{ + int ok = 0; + ${ac_cxx_conftest_cxx98_main} + return ok; +} +" + + +# Auxiliary files required by this configure script. +ac_aux_files="compile missing install-sh config.guess config.sub" + +# Locations in which to look for auxiliary files. +ac_aux_dir_candidates="${srcdir}${PATH_SEPARATOR}${srcdir}/..${PATH_SEPARATOR}${srcdir}/../.." + +# Search for a directory containing all of the required auxiliary files, +# $ac_aux_files, from the $PATH-style list $ac_aux_dir_candidates. +# If we don't find one directory that contains all the files we need, +# we report the set of missing files from the *first* directory in +# $ac_aux_dir_candidates and give up. +ac_missing_aux_files="" +ac_first_candidate=: +printf "%s\n" "$as_me:${as_lineno-$LINENO}: looking for aux files: $ac_aux_files" >&5 +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in $ac_aux_dir_candidates +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + as_found=: + + printf "%s\n" "$as_me:${as_lineno-$LINENO}: trying $as_dir" >&5 + ac_aux_dir_found=yes + ac_install_sh= + for ac_aux in $ac_aux_files + do + # As a special case, if "install-sh" is required, that requirement + # can be satisfied by any of "install-sh", "install.sh", or "shtool", + # and $ac_install_sh is set appropriately for whichever one is found. + if test x"$ac_aux" = x"install-sh" + then + if test -f "${as_dir}install-sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install-sh found" >&5 + ac_install_sh="${as_dir}install-sh -c" + elif test -f "${as_dir}install.sh"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}install.sh found" >&5 + ac_install_sh="${as_dir}install.sh -c" + elif test -f "${as_dir}shtool"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}shtool found" >&5 + ac_install_sh="${as_dir}shtool install -c" + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} install-sh" + else + break + fi + fi + else + if test -f "${as_dir}${ac_aux}"; then + printf "%s\n" "$as_me:${as_lineno-$LINENO}: ${as_dir}${ac_aux} found" >&5 + else + ac_aux_dir_found=no + if $ac_first_candidate; then + ac_missing_aux_files="${ac_missing_aux_files} ${ac_aux}" + else + break + fi + fi + fi + done + if test "$ac_aux_dir_found" = yes; then + ac_aux_dir="$as_dir" + break + fi + ac_first_candidate=false + + as_found=false +done +IFS=$as_save_IFS +if $as_found +then : + +else $as_nop + as_fn_error $? "cannot find required auxiliary files:$ac_missing_aux_files" "$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. +if test -f "${ac_aux_dir}config.guess"; then + ac_config_guess="$SHELL ${ac_aux_dir}config.guess" +fi +if test -f "${ac_aux_dir}config.sub"; then + ac_config_sub="$SHELL ${ac_aux_dir}config.sub" +fi +if test -f "$ac_aux_dir/configure"; then + ac_configure="$SHELL ${ac_aux_dir}configure" +fi + # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false @@ -1909,12 +2643,12 @@ for ac_var in $ac_precious_vars; do 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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +printf "%s\n" "$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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) @@ -1923,24 +2657,24 @@ $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} 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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +printf "%s\n" "$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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +printf "%s\n" "$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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +printf "%s\n" "$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=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in @@ -1950,11 +2684,12 @@ $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} 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 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' + and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## @@ -1968,55 +2703,30 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu -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 - 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 ${ac_cv_build+:} false; then : - $as_echo_n "(cached) " >&6 -else + # 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 + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +printf %s "checking build system type... " >&6; } +if test ${ac_cv_build+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_build_alias=$build_alias test "x$ac_build_alias" = x && - ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` + 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 +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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +printf "%s\n" "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; @@ -2035,21 +2745,22 @@ 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 ${ac_cv_host+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +printf %s "checking host system type... " >&6; } +if test ${ac_cv_host+y} +then : + printf %s "(cached) " >&6 +else $as_nop 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 + 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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +printf "%s\n" "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; @@ -2069,9 +2780,10 @@ case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac -am__api_version='1.15' +am__api_version='1.16' -# Find a good install program. We prefer a C program (faster), + + # 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 @@ -2085,20 +2797,25 @@ am__api_version='1.15' # 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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +printf %s "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then -if ${ac_cv_path_install+:} false; then : - $as_echo_n "(cached) " >&6 -else +if test ${ac_cv_path_install+y} +then : + printf %s "(cached) " >&6 +else $as_nop 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]/* | \ + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + # Account for fact that we put trailing slashes in our PATH walk. +case $as_dir in #(( + ./ | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; @@ -2108,13 +2825,13 @@ case $as_dir/ in #(( # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then + if as_fn_executable_p "$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 + 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 + 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 @@ -2122,12 +2839,12 @@ case $as_dir/ in #(( 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" && + 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" + ac_cv_path_install="$as_dir$ac_prog$ac_exec_ext -c" break 3 fi fi @@ -2143,7 +2860,7 @@ IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi - if test "${ac_cv_path_install+set}" = set; then + if test ${ac_cv_path_install+y}; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a @@ -2153,8 +2870,8 @@ fi INSTALL=$ac_install_sh fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 -$as_echo "$INSTALL" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +printf "%s\n" "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. @@ -2164,8 +2881,8 @@ 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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +printf %s "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' @@ -2219,8 +2936,8 @@ 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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= @@ -2239,26 +2956,23 @@ test "$program_suffix" != NONE && # 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"` +program_transform_name=`printf "%s\n" "$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 + + if test x"${MISSING+set}" != xset; then + MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " 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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 +printf "%s\n" "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then @@ -2278,11 +2992,12 @@ 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 ${ac_cv_prog_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_STRIP+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else @@ -2290,11 +3005,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2305,11 +3024,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +printf "%s\n" "$STRIP" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2318,11 +3037,12 @@ 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 ${ac_cv_prog_ac_ct_STRIP+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_STRIP+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else @@ -2330,11 +3050,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2345,11 +3069,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +printf "%s\n" "$ac_ct_STRIP" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then @@ -2357,8 +3081,8 @@ fi 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;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP @@ -2370,25 +3094,31 @@ 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; } + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for a race-free mkdir -p" >&5 +printf %s "checking for a race-free mkdir -p... " >&6; } if test -z "$MKDIR_P"; then - if ${ac_cv_path_mkdir+:} false; then : - $as_echo_n "(cached) " >&6 -else + if test ${ac_cv_path_mkdir+y} +then : + printf %s "(cached) " >&6 +else $as_nop 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=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do - as_fn_executable_p "$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) '* | \ + as_fn_executable_p "$as_dir$ac_prog$ac_exec_ext" || continue + case `"$as_dir$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir ('*'coreutils) '* | \ + 'BusyBox '* | \ 'mkdir (fileutils) '4.1*) - ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + ac_cv_path_mkdir=$as_dir$ac_prog$ac_exec_ext break 3;; esac done @@ -2399,7 +3129,7 @@ IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version - if test "${ac_cv_path_mkdir+set}" = set; then + if test ${ac_cv_path_mkdir+y}; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a @@ -2409,18 +3139,19 @@ fi MKDIR_P="$ac_install_sh -d" fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 -$as_echo "$MKDIR_P" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +printf "%s\n" "$MKDIR_P" >&6; } 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 ${ac_cv_prog_AWK+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_AWK+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else @@ -2428,11 +3159,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2443,24 +3178,25 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +printf "%s\n" "$AWK" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +printf %s "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 eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : - $as_echo_n "(cached) " >&6 -else +ac_make=`printf "%s\n" "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if eval test \${ac_cv_prog_make_${ac_make}_set+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @@ -2476,12 +3212,12 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } SET_MAKE= else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi @@ -2495,7 +3231,8 @@ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. -if test "${enable_silent_rules+set}" = set; then : +if test ${enable_silent_rules+y} +then : enableval=$enable_silent_rules; fi @@ -2505,12 +3242,13 @@ case $enable_silent_rules in # ((( *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 -$as_echo_n "checking whether $am_make supports nested variables... " >&6; } -if ${am_cv_make_support_nested_variables+:} false; then : - $as_echo_n "(cached) " >&6 -else - if $as_echo 'TRUE=$(BAR$(V)) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 +printf %s "checking whether $am_make supports nested variables... " >&6; } +if test ${am_cv_make_support_nested_variables+y} +then : + printf %s "(cached) " >&6 +else $as_nop + if printf "%s\n" 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 @@ -2522,8 +3260,8 @@ else am_cv_make_support_nested_variables=no fi fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 -$as_echo "$am_cv_make_support_nested_variables" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 +printf "%s\n" "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' @@ -2555,17 +3293,13 @@ fi # Define the identity of the package. PACKAGE='pcem' - VERSION='v12' + VERSION='v17' -cat >>confdefs.h <<_ACEOF -#define PACKAGE "$PACKAGE" -_ACEOF +printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h -cat >>confdefs.h <<_ACEOF -#define VERSION "$VERSION" -_ACEOF +printf "%s\n" "#define VERSION \"$VERSION\"" >>confdefs.h # Some tools Automake needs. @@ -2585,8 +3319,8 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: -# -# +# +# mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The @@ -2637,7 +3371,7 @@ END Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation -that behaves properly: . +that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM @@ -2648,6 +3382,15 @@ END fi fi + + + + + + + + + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -2656,11 +3399,12 @@ 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 ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2668,11 +3412,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2683,11 +3431,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2696,11 +3444,12 @@ 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 ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2708,11 +3457,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2723,11 +3476,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then @@ -2735,8 +3488,8 @@ fi 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;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2749,11 +3502,12 @@ 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 ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2761,11 +3515,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2776,11 +3534,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2789,11 +3547,12 @@ 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 ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2802,15 +3561,19 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then - if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2826,18 +3589,18 @@ if test $ac_prog_rejected = yes; then # 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+' '}$@" + 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2848,11 +3611,12 @@ if test -z "$CC"; then 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 ${ac_cv_prog_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else @@ -2860,11 +3624,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2875,11 +3643,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2892,11 +3660,12 @@ if test -z "$CC"; then 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 ${ac_cv_prog_ac_ct_CC+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else @@ -2904,11 +3673,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -2919,11 +3692,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -2935,8 +3708,8 @@ done 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;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC @@ -2944,25 +3717,129 @@ esac fi fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. +set dummy ${ac_tool_prefix}clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_CC="${ac_tool_prefix}clang" + printf "%s\n" "$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 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +printf "%s\n" "$CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +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;} +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "clang", so it can be a program name with args. +set dummy clang; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CC+y} +then : + printf %s "(cached) " >&6 +else $as_nop + 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CC="clang" + printf "%s\n" "$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 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +printf "%s\n" "$ac_ct_CC" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$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 + +fi + + +test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$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 +printf "%s\n" "$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 +for ac_option in --version -v -V -qversion -version; 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 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -2972,7 +3849,7 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done @@ -2980,7 +3857,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -2992,9 +3869,9 @@ 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[^ ]*//'` +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +printf %s "checking whether the C compiler works... " >&6; } +ac_link_default=`printf "%s\n" "$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.*" @@ -3015,11 +3892,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$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 : + printf "%s\n" "$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, @@ -3036,7 +3914,7 @@ do # certainly right. break;; *.* ) - if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi @@ -3052,44 +3930,46 @@ do done test "$ac_cv_exeext" = no && ac_cv_exeext= -else +else $as_nop 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 +if test -z "$ac_file" +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +printf "%s\n" "$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;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "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; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +printf %s "checking for C compiler default output file name... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +printf "%s\n" "$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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +printf %s "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 +printf "%s\n" "$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 : + printf "%s\n" "$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 @@ -3103,15 +3983,15 @@ for ac_file in conftest.exe conftest conftest.*; do * ) 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;} +else $as_nop + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext @@ -3120,7 +4000,7 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int -main () +main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; @@ -3132,8 +4012,8 @@ _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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in @@ -3141,10 +4021,10 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in @@ -3152,39 +4032,40 @@ $as_echo "$ac_try_echo"; } >&5 *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$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. + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error 77 "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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +printf "%s\n" "$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 ${ac_cv_objext+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +printf %s "checking for suffix of object files... " >&6; } +if test ${ac_cv_objext+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3198,11 +4079,12 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$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 : + printf "%s\n" "$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 @@ -3211,31 +4093,32 @@ $as_echo "$ac_try_echo"; } >&5 break;; esac done -else - $as_echo "$as_me: failed program was:" >&5 +else $as_nop + printf "%s\n" "$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;} +{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +printf "%s\n" "$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 ${ac_cv_c_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 +printf %s "checking whether the compiler supports GNU C... " >&6; } +if test ${ac_cv_c_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3245,29 +4128,33 @@ main () return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam 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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_c_compiler_gnu + if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi -ac_test_CFLAGS=${CFLAGS+set} +ac_test_CFLAGS=${CFLAGS+y} 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 ${ac_cv_prog_cc_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +printf %s "checking whether $CC accepts -g... " >&6; } +if test ${ac_cv_prog_cc_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no @@ -3276,57 +4163,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_g=yes -else +else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +if ac_fn_c_try_compile "$LINENO" +then : -else +else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_c_try_compile "$LINENO"; then : +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 +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +printf "%s\n" "$ac_cv_prog_cc_g" >&6; } +if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then @@ -3341,94 +4231,144 @@ 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 ${ac_cv_prog_cc_c89+:} false; then : - $as_echo_n "(cached) " >&6 -else +ac_prog_cc_stdc=no +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 +printf %s "checking for $CC option to enable C11 features... " >&6; } +if test ${ac_cv_prog_cc_c11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c11=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c11_program +_ACEOF +for ac_arg in '' -std=gnu11 +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c11" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 +printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } + CC="$CC $ac_cv_prog_cc_c11" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 + ac_prog_cc_stdc=c11 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 +printf %s "checking for $CC option to enable C99 features... " >&6; } +if test ${ac_cv_prog_cc_c99+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cc_c99=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_c_conftest_c99_program +_ACEOF +for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO" +then : + ac_cv_prog_cc_c99=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cc_c99" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC +fi + +if test "x$ac_cv_prog_cc_c99" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c99" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 +printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } + CC="$CC $ac_cv_prog_cc_c99" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 + ac_prog_cc_stdc=c99 +fi +fi +if test x$ac_prog_cc_stdc = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 +printf %s "checking for $CC option to enable C89 features... " >&6; } +if test ${ac_cv_prog_cc_c89+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include -#include -struct stat; -/* 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; -} +$ac_c_conftest_c89_program _ACEOF -for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ - -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +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 : + if ac_fn_c_try_compile "$LINENO" +then : ac_cv_prog_cc_c89=$ac_arg fi -rm -f core conftest.err conftest.$ac_objext +rm -f core conftest.err conftest.$ac_objext conftest.beam 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 : +if test "x$ac_cv_prog_cc_c89" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cc_c89" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } + CC="$CC $ac_cv_prog_cc_c89" +fi + ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 + ac_prog_cc_stdc=c89 +fi fi ac_ext=c @@ -3437,21 +4377,23 @@ 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_ext=c + + 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 -{ $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; } -if ${am_cv_prog_cc_c_o+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 +printf %s "checking whether $CC understands -c and -o together... " >&6; } +if test ${am_cv_prog_cc_c_o+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; @@ -3479,8 +4421,8 @@ _ACEOF rm -f core conftest* unset am_i fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 -$as_echo "$am_cv_prog_cc_c_o" >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 +printf "%s\n" "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. @@ -3499,48 +4441,49 @@ DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" - -am_make=${MAKE-make} -cat > confinc << 'END' +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 +printf %s "checking whether ${MAKE-make} supports the include directive... " >&6; } +cat > confinc.mk << 'END' am__doit: - @echo this is the am__doit target + @echo this is the am__doit target >confinc.out .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 +# BSD make does it like this. +echo '.include "confinc.mk" # ignored' > confmf.BSD +# Other make implementations (GNU, Solaris 10, AIX) do it like this. +echo 'include confinc.mk # ignored' > confmf.GNU +_am_result=no +for s in GNU BSD; do + { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 + (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + case $?:`cat confinc.out 2>/dev/null` in #( + '0:this is the am__doit target') : + case $s in #( + BSD) : + am__include='.include' am__quote='"' ;; #( + *) : + am__include='include' am__quote='' ;; +esac ;; #( + *) : ;; - esac -fi - - -{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 -$as_echo "$_am_result" >&6; } -rm -f confinc confmf +esac + if test "$am__include" != "#"; then + _am_result="yes ($s style)" + break + fi +done +rm -f confinc.* confmf.* +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 +printf "%s\n" "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. -if test "${enable_dependency_tracking+set}" = set; then : +if test ${enable_dependency_tracking+y} +then : enableval=$enable_dependency_tracking; fi @@ -3561,11 +4504,12 @@ 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 ${am_cv_CC_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CC_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop 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 @@ -3672,8 +4616,8 @@ else 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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +printf "%s\n" "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if @@ -3687,6 +4631,12 @@ else fi + + + + + + ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3697,15 +4647,16 @@ if test -z "$CXX"; 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 + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ 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 ${ac_cv_prog_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else @@ -3713,11 +4664,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3728,11 +4683,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +printf "%s\n" "$CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3741,15 +4696,16 @@ fi 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 + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC clang++ 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 ${ac_cv_prog_ac_ct_CXX+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_prog_ac_ct_CXX+y} +then : + printf %s "(cached) " >&6 +else $as_nop if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else @@ -3757,11 +4713,15 @@ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS - test -z "$as_dir" && as_dir=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + if as_fn_executable_p "$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 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done @@ -3772,11 +4732,11 @@ 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; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +printf "%s\n" "$ac_ct_CXX" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi @@ -3788,8 +4748,8 @@ done 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;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX @@ -3799,7 +4759,7 @@ fi fi fi # Provide some information about the compiler. -$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +printf "%s\n" "$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 @@ -3809,7 +4769,7 @@ case "(($ac_try" in *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" -$as_echo "$ac_try_echo"; } >&5 +printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then @@ -3819,20 +4779,21 @@ $as_echo "$ac_try_echo"; } >&5 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err - $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + printf "%s\n" "$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 ${ac_cv_cxx_compiler_gnu+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C++" >&5 +printf %s "checking whether the compiler supports GNU C++... " >&6; } +if test ${ac_cv_cxx_compiler_gnu+y} +then : + printf %s "(cached) " >&6 +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { #ifndef __GNUC__ choke me @@ -3842,29 +4803,33 @@ main () return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_compiler_gnu=yes -else +else $as_nop ac_compiler_gnu=no fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam 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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +printf "%s\n" "$ac_cv_cxx_compiler_gnu" >&6; } +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi -ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_test_CXXFLAGS=${CXXFLAGS+y} 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 ${ac_cv_prog_cxx_g+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +printf %s "checking whether $CXX accepts -g... " >&6; } +if test ${ac_cv_prog_cxx_g+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no @@ -3873,57 +4838,60 @@ else /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : ac_cv_prog_cxx_g=yes -else +else $as_nop CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +if ac_fn_cxx_try_compile "$LINENO" +then : -else +else $as_nop ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int -main () +main (void) { ; return 0; } _ACEOF -if ac_fn_cxx_try_compile "$LINENO"; then : +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 +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +rm -f core conftest.err conftest.$ac_objext conftest.beam 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 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +printf "%s\n" "$ac_cv_prog_cxx_g" >&6; } +if test $ac_test_CXXFLAGS; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then @@ -3938,6 +4906,100 @@ else CXXFLAGS= fi fi +ac_prog_cxx_stdcxx=no +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++11 features" >&5 +printf %s "checking for $CXX option to enable C++11 features... " >&6; } +if test ${ac_cv_prog_cxx_11+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_11=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_cxx_conftest_cxx11_program +_ACEOF +for ac_arg in '' -std=gnu++11 -std=gnu++0x -std=c++11 -std=c++0x -qlanglvl=extended0x -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx11=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx11" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx11" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx11" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx11" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx11" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx11" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx11 + ac_prog_cxx_stdcxx=cxx11 +fi +fi +if test x$ac_prog_cxx_stdcxx = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CXX option to enable C++98 features" >&5 +printf %s "checking for $CXX option to enable C++98 features... " >&6; } +if test ${ac_cv_prog_cxx_98+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_cv_prog_cxx_98=no +ac_save_CXX=$CXX +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_cxx_conftest_cxx98_program +_ACEOF +for ac_arg in '' -std=gnu++98 -std=c++98 -qlanglvl=extended -AA +do + CXX="$ac_save_CXX $ac_arg" + if ac_fn_cxx_try_compile "$LINENO" +then : + ac_cv_prog_cxx_cxx98=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam + test "x$ac_cv_prog_cxx_cxx98" != "xno" && break +done +rm -f conftest.$ac_ext +CXX=$ac_save_CXX +fi + +if test "x$ac_cv_prog_cxx_cxx98" = xno +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +printf "%s\n" "unsupported" >&6; } +else $as_nop + if test "x$ac_cv_prog_cxx_cxx98" = x +then : + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +printf "%s\n" "none needed" >&6; } +else $as_nop + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_cxx98" >&5 +printf "%s\n" "$ac_cv_prog_cxx_cxx98" >&6; } + CXX="$CXX $ac_cv_prog_cxx_cxx98" +fi + ac_cv_prog_cxx_stdcxx=$ac_cv_prog_cxx_cxx98 + ac_prog_cxx_stdcxx=cxx98 +fi +fi + ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' @@ -3946,11 +5008,12 @@ 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 ${am_cv_CXX_dependencies_compiler_type+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +printf %s "checking dependency style of $depcc... " >&6; } +if test ${am_cv_CXX_dependencies_compiler_type+y} +then : + printf %s "(cached) " >&6 +else $as_nop 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 @@ -4057,8 +5120,8 @@ else 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; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +printf "%s\n" "$am_cv_CXX_dependencies_compiler_type" >&6; } CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type if @@ -4076,39 +5139,108 @@ fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable debugging" >&5 -$as_echo_n "checking whether to enable debugging... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to build for release" >&5 +printf %s "checking whether to build for release... " >&6; } +# Check whether --enable-release_build was given. +if test ${enable_release_build+y} +then : + enableval=$enable_release_build; +fi + +if test "$enable_release_build" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + if test "$enable_release_build" = "yes"; then + RELEASE_BUILD_TRUE= + RELEASE_BUILD_FALSE='#' +else + RELEASE_BUILD_TRUE='#' + RELEASE_BUILD_FALSE= +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable debugging" >&5 +printf %s "checking whether to enable debugging... " >&6; } # Check whether --enable-debug was given. -if test "${enable_debug+set}" = set; then : +if test ${enable_debug+y} +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; } + CFLAGS="-Wall -O0 -g -D_DEBUG -fcommon" + CXXFLAGS="-Wall -O0 -g -D_DEBUG -fcommon" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } else - CFLAGS="-O3" - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + CFLAGS="-O3 -fcommon" + CXXFLAGS="-O3 -fcommon" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cpu" >&5 -$as_echo_n "checking for cpu... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to enable networking" >&5 +printf %s "checking whether to enable networking... " >&6; } +# Check whether --enable-networking was given. +if test ${enable_networking+y} +then : + enableval=$enable_networking; +fi + +if test "$enable_networking" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether to use ALSA for MIDI output" >&5 +printf %s "checking whether to use ALSA for MIDI output... " >&6; } +# Check whether --enable-alsa was given. +if test ${enable_alsa+y} +then : + enableval=$enable_alsa; +fi + +if test "$enable_alsa" = "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for cpu" >&5 +printf %s "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 - ;; + i?86) + CPU=i386 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${host_cpu}" >&5 +printf "%s\n" "${host_cpu}" >&6; } + ;; + x86_64) + CPU=x86_64 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${host_cpu}" >&5 +printf "%s\n" "${host_cpu}" >&6; } + ;; + armv7l) + CPU=arm + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${host_cpu}" >&5 +printf "%s\n" "${host_cpu}" >&6; } + ;; + aarch64) + CPU=arm64 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: ${host_cpu}" >&5 +printf "%s\n" "${host_cpu}" >&6; } + ;; + *) + as_fn_error $? "Unsupported CPU. ${host_cpu}" "$LINENO" 5 + ;; esac if test "$CPU" = "i386"; then @@ -4127,403 +5259,1009 @@ else CPU_X86_64_FALSE= fi + if test "$CPU" = "arm"; then + CPU_ARM_TRUE= + CPU_ARM_FALSE='#' +else + CPU_ARM_TRUE='#' + CPU_ARM_FALSE= +fi + + if test "$CPU" = "arm64"; then + CPU_ARM64_TRUE= + CPU_ARM64_FALSE='#' +else + CPU_ARM64_TRUE='#' + CPU_ARM64_FALSE= +fi + + +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for off64_t $CPU" >&5 +printf %s "checking for off64_t $CPU... " >&6; } + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main (void) +{ +off64_t n=0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + has_lfs="yes" +else $as_nop + has_lfs="no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +case "$host" in + *-*-freebsd*) # has off64_t but no fopen64/etc. + has_lfs="no" + ;; +esac +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $has_lfs" >&5 +printf "%s\n" "$has_lfs" >&6; } #AC_MSG_CHECKING([for libz]) #AX_CHECK_ZLIB - if test "$OS" = "win"; then - OS_WIN_TRUE= - OS_WIN_FALSE='#' + if test "$enable_wx" = "yes"; then + USE_WX_TRUE= + USE_WX_FALSE='#' else - OS_WIN_TRUE='#' - OS_WIN_FALSE= + USE_WX_TRUE='#' + USE_WX_FALSE= fi - if test "$OS" = "linux"; then - OS_LINUX_TRUE= - OS_LINUX_FALSE='#' + if test "$enable_networking" = "yes"; then + USE_NETWORKING_TRUE= + USE_NETWORKING_FALSE='#' else - OS_LINUX_TRUE='#' - OS_LINUX_FALSE= + USE_NETWORKING_TRUE='#' + USE_NETWORKING_FALSE= +fi + + if test "$enable_alsa" = "yes"; then + USE_ALSA_TRUE= + USE_ALSA_FALSE='#' +else + USE_ALSA_TRUE='#' + USE_ALSA_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" + if test "$has_lfs" = "yes"; then + HAS_OFF64T_TRUE= + HAS_OFF64T_FALSE='#' else - ALLEGRO_CONFIG_prefix="" + HAS_OFF64T_TRUE='#' + HAS_OFF64T_FALSE= 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 +SDL_VERSION=2.0.1 - 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 ${ac_cv_path_ALLEGRO_CONFIG+:} false; then : - $as_echo_n "(cached) " >&6 -else - case $ALLEGRO_CONFIG in + + + + +if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. +set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $PKG_CONFIG in [\\/]* | ?:[\\/]*) - ac_cv_path_ALLEGRO_CONFIG="$ALLEGRO_CONFIG" # Let the user override the test with a path. + ac_cv_path_PKG_CONFIG="$PKG_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=. + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac for ac_exec_ext in '' $ac_executable_extensions; do - if as_fn_executable_p "$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 + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$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; } +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +printf "%s\n" "$PKG_CONFIG" >&6; } else - { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 -$as_echo "no" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "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" +fi +if test -z "$ac_cv_path_PKG_CONFIG"; then + ac_pt_PKG_CONFIG=$PKG_CONFIG + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_ac_pt_PKG_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $ac_pt_PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_ac_pt_PKG_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + ;; +esac +fi +ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG +if test -n "$ac_pt_PKG_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 +printf "%s\n" "$ac_pt_PKG_CONFIG" >&6; } else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + if test "x$ac_pt_PKG_CONFIG" = x; then + PKG_CONFIG="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + PKG_CONFIG=$ac_pt_PKG_CONFIG + fi +else + PKG_CONFIG="$ac_cv_path_PKG_CONFIG" +fi + +fi +if test -n "$PKG_CONFIG"; then + _pkg_min_version=0.9.0 + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 +printf %s "checking pkg-config is at least version $_pkg_min_version... " >&6; } + if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + PKG_CONFIG="" + fi +fi + +# Check whether --with-sdl-prefix was given. +if test ${with_sdl_prefix+y} +then : + withval=$with_sdl_prefix; sdl_prefix="$withval" +else $as_nop + sdl_prefix="" +fi + + +# Check whether --with-sdl-exec-prefix was given. +if test ${with_sdl_exec_prefix+y} +then : + withval=$with_sdl_exec_prefix; sdl_exec_prefix="$withval" +else $as_nop + sdl_exec_prefix="" +fi + +# Check whether --enable-sdltest was given. +if test ${enable_sdltest+y} +then : + enableval=$enable_sdltest; +else $as_nop + enable_sdltest=yes +fi + +# Check whether --enable-sdlframework was given. +if test ${enable_sdlframework+y} +then : + enableval=$enable_sdlframework; +else $as_nop + search_sdl_framework=yes +fi + + + + + min_sdl_version=$SDL_VERSION + + if test "x$sdl_prefix$sdl_exec_prefix" = x ; then + +pkg_failed=no +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sdl2 >= $min_sdl_version" >&5 +printf %s "checking for sdl2 >= $min_sdl_version... " >&6; } + +if test -n "$SDL_CFLAGS"; then + pkg_cv_SDL_CFLAGS="$SDL_CFLAGS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sdl2 >= \$min_sdl_version\""; } >&5 + ($PKG_CONFIG --exists --print-errors "sdl2 >= $min_sdl_version") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SDL_CFLAGS=`$PKG_CONFIG --cflags "sdl2 >= $min_sdl_version" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi +if test -n "$SDL_LIBS"; then + pkg_cv_SDL_LIBS="$SDL_LIBS" + elif test -n "$PKG_CONFIG"; then + if test -n "$PKG_CONFIG" && \ + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sdl2 >= \$min_sdl_version\""; } >&5 + ($PKG_CONFIG --exists --print-errors "sdl2 >= $min_sdl_version") 2>&5 + ac_status=$? + printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then + pkg_cv_SDL_LIBS=`$PKG_CONFIG --libs "sdl2 >= $min_sdl_version" 2>/dev/null` + test "x$?" != "x0" && pkg_failed=yes +else + pkg_failed=yes +fi + else + pkg_failed=untried +fi + + + +if test $pkg_failed = yes; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + +if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then + _pkg_short_errors_supported=yes +else + _pkg_short_errors_supported=no +fi + if test $_pkg_short_errors_supported = yes; then + SDL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sdl2 >= $min_sdl_version" 2>&1` + else + SDL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sdl2 >= $min_sdl_version" 2>&1` + fi + # Put the nasty error message in config.log where it belongs + echo "$SDL_PKG_ERRORS" >&5 + + sdl_pc=no +elif test $pkg_failed = untried; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + sdl_pc=no +else + SDL_CFLAGS=$pkg_cv_SDL_CFLAGS + SDL_LIBS=$pkg_cv_SDL_LIBS + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + sdl_pc=yes +fi + else + sdl_pc=no + if test x$sdl_exec_prefix != x ; then + sdl_config_args="$sdl_config_args --exec-prefix=$sdl_exec_prefix" + if test x${SDL2_CONFIG+set} != xset ; then + SDL2_CONFIG=$sdl_exec_prefix/bin/sdl2-config + fi + fi + if test x$sdl_prefix != x ; then + sdl_config_args="$sdl_config_args --prefix=$sdl_prefix" + if test x${SDL2_CONFIG+set} != xset ; then + SDL2_CONFIG=$sdl_prefix/bin/sdl2-config + fi + fi + fi + + if test "x$sdl_pc" = xyes ; then + no_sdl="" + SDL2_CONFIG="pkg-config sdl2" + else + as_save_PATH="$PATH" + if test "x$prefix" != xNONE && test "$cross_compiling" != yes; then + PATH="$prefix/bin:$prefix/usr/bin:$PATH" + fi + # Extract the first word of "sdl2-config", so it can be a program name with args. +set dummy sdl2-config; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_SDL2_CONFIG+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $SDL2_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_SDL2_CONFIG="$SDL2_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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_SDL2_CONFIG="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$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_SDL2_CONFIG" && ac_cv_path_SDL2_CONFIG="no" + ;; +esac +fi +SDL2_CONFIG=$ac_cv_path_SDL2_CONFIG +if test -n "$SDL2_CONFIG"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $SDL2_CONFIG" >&5 +printf "%s\n" "$SDL2_CONFIG" >&6; } +else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + PATH="$as_save_PATH" + no_sdl="" + + if test "$SDL2_CONFIG" = "no" -a "x$search_sdl_framework" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SDL2.framework" >&5 +printf %s "checking for SDL2.framework... " >&6; } + if test "x$SDL2_FRAMEWORK" != x; then + sdl_framework=$SDL2_FRAMEWORK + else + for d in / ~/ /System/; do + if test -d "$dLibrary/Frameworks/SDL2.framework"; then + sdl_framework="$dLibrary/Frameworks/SDL2.framework" + fi + done + fi + + if test x"$sdl_framework" != x && test -d "$sdl_framework"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $sdl_framework" >&5 +printf "%s\n" "$sdl_framework" >&6; } + sdl_framework_dir=`dirname $sdl_framework` + SDL_CFLAGS="-F$sdl_framework_dir -Wl,-framework,SDL2 -I$sdl_framework/include" + SDL_LIBS="-F$sdl_framework_dir -Wl,-framework,SDL2" + else + no_sdl=yes + fi + fi + + if test "$SDL2_CONFIG" != "no"; then + if test "x$sdl_pc" = "xno"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for SDL - version >= $min_sdl_version" >&5 +printf %s "checking for SDL - version >= $min_sdl_version... " >&6; } + SDL_CFLAGS=`$SDL2_CONFIG $sdl_config_args --cflags` + SDL_LIBS=`$SDL2_CONFIG $sdl_config_args --libs` + fi + + sdl_major_version=`$SDL2_CONFIG $sdl_config_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + sdl_minor_version=`$SDL2_CONFIG $sdl_config_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + sdl_micro_version=`$SDL2_CONFIG $sdl_config_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + if test "x$enable_sdltest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_CXXFLAGS="$CXXFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $SDL_CFLAGS" + CXXFLAGS="$CXXFLAGS $SDL_CFLAGS" + LIBS="$LIBS $SDL_LIBS" + rm -f conf.sdltest + if test "$cross_compiling" = yes +then : + echo $ac_n "cross compiling; assumed OK... $ac_c" +else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include #include +#include #include -#include +#include "SDL.h" -int -main() +char* +my_strdup (char *str) +{ + char *new_str; + + if (str) + { + new_str = (char *)malloc ((strlen (str) + 1) * sizeof(char)); + strcpy (new_str, str); + } + else + new_str = NULL; + + return new_str; +} + +int main (int argc, char *argv[]) { - 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"); + /* This hangs on some systems (?) + system ("touch conf.sdltest"); + */ + { FILE *fp = fopen("conf.sdltest", "a"); if ( fp ) fclose(fp); } - /* Capture allegro-config output via autoconf/configure variables */ /* HP/UX 9 (%@#!) writes to sscanf strings */ - tmp_version = (char *)strdup("$min_allegro_version"); + tmp_version = my_strdup("$min_sdl_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); + printf("%s, bad version string\n", "$min_sdl_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)) + if (($sdl_major_version > major) || + (($sdl_major_version == major) && ($sdl_minor_version > minor)) || + (($sdl_major_version == major) && ($sdl_minor_version == minor) && ($sdl_micro_version >= micro))) { - 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 0; + } + else + { + printf("\n*** 'sdl2-config --version' returned %d.%d.%d, but the minimum version\n", $sdl_major_version, $sdl_minor_version, $sdl_micro_version); + printf("*** of SDL required is %d.%d.%d. If sdl2-config is correct, then it is\n", major, minor, micro); + printf("*** best to upgrade to the required version.\n"); + printf("*** If sdl2-config was wrong, set the environment variable SDL2_CONFIG\n"); + printf("*** to point to the correct copy of sdl2-config, and remove the file\n"); + printf("*** config.cache before re-running configure\n"); 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 : +if ac_fn_c_try_run "$LINENO" +then : -else - no_allegro=yes +else $as_nop + no_sdl=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 + CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" - 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; } + fi + if test "x$sdl_pc" = "xno"; then + if test "x$no_sdl" = "xyes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + fi + fi + fi + fi + if test "x$no_sdl" = x ; then : 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." + if test "$SDL2_CONFIG" = "no" ; then + echo "*** The sdl2-config script installed by SDL could not be found" + echo "*** If SDL was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the SDL2_CONFIG environment variable to the" + echo "*** full path to sdl2-config." else - if test -f conf.allegrotest ; then + if test -f conf.sdltest ; then : else - echo "*** Could not run Allegro test program, checking why..." - CFLAGS="$CFLAGS $allegro_CFLAGS" - LIBS="$LIBS $allegro_LIBS" + echo "*** Could not run SDL test program, checking why..." + CFLAGS="$CFLAGS $SDL_CFLAGS" + CXXFLAGS="$CXXFLAGS $SDL_CFLAGS" + LIBS="$LIBS $SDL_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ -#include #include +#include "SDL.h" + +int main(int argc, char *argv[]) +{ return 0; } +#undef main +#define main K_and_R_C_main int -main () +main (void) { - allegro_error; return 0; + return 0; ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +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 "*** that the run-time linker is not finding SDL or finding the wrong" + echo "*** version of SDL. If it is not finding SDL, 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 "***" 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 +else $as_nop 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" + echo "*** exact error that occured. This usually means SDL was incorrectly installed" + echo "*** or that you have moved SDL since it was installed. In the latter case, you" + echo "*** may want to edit the sdl2-config script: $SDL2_CONFIG" fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext CFLAGS="$ac_save_CFLAGS" + CXXFLAGS="$ac_save_CXXFLAGS" LIBS="$ac_save_LIBS" fi fi + SDL_CFLAGS="" + SDL_LIBS="" + as_fn_error $? "*** SDL version $SDL_VERSION not found!" "$LINENO" 5 - allegro_CFLAGS="" - allegro_LIBS="" - as_fn_error $? "building PCem requires Allegro to be installed" "$LINENO" 5 fi - rm -f conf.allegrotest + rm -f conf.sdltest + + + +# Check whether --with-wxdir was given. +if test ${with_wxdir+y} +then : + withval=$with_wxdir; wx_config_name="$withval/wx-config" + wx_config_args="--inplace" fi -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alGetError in -lopenal" >&5 -$as_echo_n "checking for alGetError in -lopenal... " >&6; } -if ${ac_cv_lib_openal_alGetError+:} false; then : - $as_echo_n "(cached) " >&6 + +# Check whether --with-wx-config was given. +if test ${with_wx_config+y} +then : + withval=$with_wx_config; wx_config_name="$withval" +fi + + +# Check whether --with-wx-prefix was given. +if test ${with_wx_prefix+y} +then : + withval=$with_wx_prefix; wx_config_prefix="$withval" +else $as_nop + wx_config_prefix="" +fi + + +# Check whether --with-wx-exec-prefix was given. +if test ${with_wx_exec_prefix+y} +then : + withval=$with_wx_exec_prefix; wx_config_exec_prefix="$withval" +else $as_nop + wx_config_exec_prefix="" +fi + + +reqwx=3.0.0 + + + if test x${WX_CONFIG_NAME+set} != xset ; then + WX_CONFIG_NAME=wx-config + fi + + if test "x$wx_config_name" != x ; then + WX_CONFIG_NAME="$wx_config_name" + fi + + if test x$wx_config_exec_prefix != x ; then + wx_config_args="$wx_config_args --exec-prefix=$wx_config_exec_prefix" + WX_LOOKUP_PATH="$wx_config_exec_prefix/bin" + fi + if test x$wx_config_prefix != x ; then + wx_config_args="$wx_config_args --prefix=$wx_config_prefix" + WX_LOOKUP_PATH="$WX_LOOKUP_PATH:$wx_config_prefix/bin" + fi + if test "$cross_compiling" = "yes"; then + wx_config_args="$wx_config_args --host=$host_alias" + fi + + if test -x "$WX_CONFIG_NAME" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wx-config" >&5 +printf %s "checking for wx-config... " >&6; } + WX_CONFIG_PATH="$WX_CONFIG_NAME" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 +printf "%s\n" "$WX_CONFIG_PATH" >&6; } + else + # Extract the first word of "$WX_CONFIG_NAME", so it can be a program name with args. +set dummy $WX_CONFIG_NAME; ac_word=$2 +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +printf %s "checking for $ac_word... " >&6; } +if test ${ac_cv_path_WX_CONFIG_PATH+y} +then : + printf %s "(cached) " >&6 +else $as_nop + case $WX_CONFIG_PATH in + [\\/]* | ?:[\\/]*) + ac_cv_path_WX_CONFIG_PATH="$WX_CONFIG_PATH" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_dummy=""$WX_LOOKUP_PATH:$PATH"" +for as_dir in $as_dummy +do + IFS=$as_save_IFS + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then + ac_cv_path_WX_CONFIG_PATH="$as_dir$ac_word$ac_exec_ext" + printf "%s\n" "$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_WX_CONFIG_PATH" && ac_cv_path_WX_CONFIG_PATH="no" + ;; +esac +fi +WX_CONFIG_PATH=$ac_cv_path_WX_CONFIG_PATH +if test -n "$WX_CONFIG_PATH"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $WX_CONFIG_PATH" >&5 +printf "%s\n" "$WX_CONFIG_PATH" >&6; } else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } +fi + + + fi + + if test "$WX_CONFIG_PATH" != "no" ; then + WX_VERSION="" + + min_wx_version=$reqwx + if test -z "" ; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version" >&5 +printf %s "checking for wxWidgets version >= $min_wx_version... " >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets version >= $min_wx_version ()" >&5 +printf %s "checking for wxWidgets version >= $min_wx_version ()... " >&6; } + fi + + WX_CONFIG_WITH_ARGS="$WX_CONFIG_PATH $wx_config_args " + + WX_VERSION=`$WX_CONFIG_WITH_ARGS --version 2>/dev/null` + wx_config_major_version=`echo $WX_VERSION | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + wx_config_minor_version=`echo $WX_VERSION | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + wx_config_micro_version=`echo $WX_VERSION | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + + wx_requested_major_version=`echo $min_wx_version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + wx_requested_minor_version=`echo $min_wx_version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + wx_requested_micro_version=`echo $min_wx_version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + + + wx_ver_ok="" + if test "x$WX_VERSION" != x ; then + if test $wx_config_major_version -gt $wx_requested_major_version; then + wx_ver_ok=yes + else + if test $wx_config_major_version -eq $wx_requested_major_version; then + if test $wx_config_minor_version -gt $wx_requested_minor_version; then + wx_ver_ok=yes + else + if test $wx_config_minor_version -eq $wx_requested_minor_version; then + if test $wx_config_micro_version -ge $wx_requested_micro_version; then + wx_ver_ok=yes + fi + fi + fi + fi + fi + fi + + + if test -n "$wx_ver_ok"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes (version $WX_VERSION)" >&5 +printf "%s\n" "yes (version $WX_VERSION)" >&6; } + + wx_optional_libs="" + + wx_ver_ok="" + if test "x$WX_VERSION" != x ; then + if test $wx_config_major_version -gt 2; then + wx_ver_ok=yes + else + if test $wx_config_major_version -eq 2; then + if test $wx_config_minor_version -gt 9; then + wx_ver_ok=yes + else + if test $wx_config_minor_version -eq 9; then + if test $wx_config_micro_version -ge 0; then + wx_ver_ok=yes + fi + fi + fi + fi + fi + fi + + if test -n "$wx_ver_ok" -a -n ""; then + wx_optional_libs="--optional-libs " + fi + WX_LIBS=`$WX_CONFIG_WITH_ARGS --libs $wx_optional_libs` + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for wxWidgets static library" >&5 +printf %s "checking for wxWidgets static library... " >&6; } + WX_LIBS_STATIC=`$WX_CONFIG_WITH_ARGS --static --libs $wx_optional_libs 2>/dev/null` + if test "x$WX_LIBS_STATIC" = "x"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +printf "%s\n" "yes" >&6; } + fi + + wx_has_cppflags="" + if test $wx_config_major_version -gt 2; then + wx_has_cppflags=yes + else + if test $wx_config_major_version -eq 2; then + if test $wx_config_minor_version -gt 2; then + wx_has_cppflags=yes + else + if test $wx_config_minor_version -eq 2; then + if test $wx_config_micro_version -ge 6; then + wx_has_cppflags=yes + fi + fi + fi + fi + fi + + wx_has_rescomp="" + if test $wx_config_major_version -gt 2; then + wx_has_rescomp=yes + else + if test $wx_config_major_version -eq 2; then + if test $wx_config_minor_version -ge 7; then + wx_has_rescomp=yes + fi + fi + fi + if test "x$wx_has_rescomp" = x ; then + WX_RESCOMP= + else + WX_RESCOMP=`$WX_CONFIG_WITH_ARGS --rescomp` + fi + + if test "x$wx_has_cppflags" = x ; then + WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags ` + WX_CPPFLAGS=$WX_CFLAGS + WX_CXXFLAGS=$WX_CFLAGS + + WX_CFLAGS_ONLY=$WX_CFLAGS + WX_CXXFLAGS_ONLY=$WX_CFLAGS + else + WX_CPPFLAGS=`$WX_CONFIG_WITH_ARGS --cppflags ` + WX_CXXFLAGS=`$WX_CONFIG_WITH_ARGS --cxxflags ` + WX_CFLAGS=`$WX_CONFIG_WITH_ARGS --cflags ` + + WX_CFLAGS_ONLY=`echo $WX_CFLAGS | sed "s@^$WX_CPPFLAGS *@@"` + WX_CXXFLAGS_ONLY=`echo $WX_CXXFLAGS | sed "s@^$WX_CFLAGS *@@"` + fi + + wxWin=1 + + else + + if test "x$WX_VERSION" = x; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 +printf "%s\n" "no" >&6; } + else + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (version $WX_VERSION is not new enough)" >&5 +printf "%s\n" "no (version $WX_VERSION is not new enough)" >&6; } + fi + + WX_CFLAGS="" + WX_CPPFLAGS="" + WX_CXXFLAGS="" + WX_LIBS="" + WX_LIBS_STATIC="" + WX_RESCOMP="" + + if test ! -z ""; then + + wx_error_message=" + The configuration you asked for $PACKAGE_NAME requires a wxWidgets + build with the following settings: + + but such build is not available. + + To see the wxWidgets builds available on this system, please use + 'wx-config --list' command. To use the default build, returned by + 'wx-config --selected-config', use the options with their 'auto' + default values." + + fi + + wx_error_message=" + The requested wxWidgets build couldn't be found. + $wx_error_message + + If you still get this error, then check that 'wx-config' is + in path, the directory where wxWidgets libraries are installed + (returned by 'wx-config --libs' command) is in LD_LIBRARY_PATH + or equivalent variable and wxWidgets version is $reqwx or above." + + as_fn_error $? "$wx_error_message" "$LINENO" 5 + + fi + else + + WX_CFLAGS="" + WX_CPPFLAGS="" + WX_CXXFLAGS="" + WX_LIBS="" + WX_LIBS_STATIC="" + WX_RESCOMP="" + + : + + fi + + + + + + + + + + + + WX_VERSION_MAJOR="$wx_config_major_version" + WX_VERSION_MINOR="$wx_config_minor_version" + WX_VERSION_MICRO="$wx_config_micro_version" + + + + + +if test "$wxWin" != 1; then + as_fn_error $? " + wxWidgets must be installed on your system. + + Please check that wx-config is in path, the directory + where wxWidgets libraries are installed (returned by + 'wx-config --libs' or 'wx-config --static --libs' command) + is in LD_LIBRARY_PATH or equivalent variable and + wxWidgets version is $reqwx or above. + " "$LINENO" 5 +fi + +if test "$enable_alsa" == "yes"; then + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for snd_pcm_open in -lasound" >&5 +printf %s "checking for snd_pcm_open in -lasound... " >&6; } +if test ${ac_cv_lib_asound_snd_pcm_open+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS -LIBS="-lopenal $LIBS" +LIBS="-lasound $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 (); +char snd_pcm_open (); int -main () +main (void) { -return alGetError (); +return snd_pcm_open (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : - ac_cv_lib_openal_alGetError=yes -else - ac_cv_lib_openal_alGetError=no +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_asound_snd_pcm_open=yes +else $as_nop + ac_cv_lib_asound_snd_pcm_open=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ 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" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBOPENAL 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_asound_snd_pcm_open" >&5 +printf "%s\n" "$ac_cv_lib_asound_snd_pcm_open" >&6; } +if test "x$ac_cv_lib_asound_snd_pcm_open" = xyes +then : + printf "%s\n" "#define HAVE_LIBASOUND 1" >>confdefs.h - LIBS="-lopenal $LIBS" + LIBS="-lasound $LIBS" -else - \ - echo "You need to install the OpenAL library." - exit -1 +else $as_nop + echo "You need to install the ALSA 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 ${ac_cv_lib_alut_alutInit+:} false; 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" = xyes; 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 ${ac_cv_lib_pthread_pthread_create+:} false; then : - $as_echo_n "(cached) " >&6 -else +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +printf %s "checking for pthread_create in -lpthread... " >&6; } +if test ${ac_cv_lib_pthread_pthread_create+y} +then : + printf %s "(cached) " >&6 +else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -4532,39 +6270,476 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* 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 () +main (void) { return pthread_create (); ; return 0; } _ACEOF -if ac_fn_c_try_link "$LINENO"; then : +if ac_fn_c_try_link "$LINENO" +then : ac_cv_lib_pthread_pthread_create=yes -else +else $as_nop ac_cv_lib_pthread_pthread_create=no fi -rm -f core conftest.err conftest.$ac_objext \ +rm -f core conftest.err conftest.$ac_objext conftest.beam \ 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" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_LIBPTHREAD 1 -_ACEOF +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +printf "%s\n" "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = xyes +then : + printf "%s\n" "#define HAVE_LIBPTHREAD 1" >>confdefs.h LIBS="-lpthread $LIBS" fi +build_macosx="no" +build_linux="no" +build_win="no" +build_other="no" + +case "$host" in + *-*-darwin*) + LIBS="$LIBS -framework OpenGL" + LIBS="$LIBS -framework OpenAL" + build_macosx="yes" + CFLAGS="$CFLAGS -DHAVE_UNISTD_H" + ;; + *-*-cygwin* | *-*-mingw32*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for main in -lopengl32" >&5 +printf %s "checking for main in -lopengl32... " >&6; } +if test ${ac_cv_lib_opengl32_main+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lopengl32 $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +int +main (void) +{ +return main (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_opengl32_main=yes +else $as_nop + ac_cv_lib_opengl32_main=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_opengl32_main" >&5 +printf "%s\n" "$ac_cv_lib_opengl32_main" >&6; } +if test "x$ac_cv_lib_opengl32_main" = xyes +then : + printf "%s\n" "#define HAVE_LIBOPENGL32 1" >>confdefs.h + + LIBS="-lopengl32 $LIBS" + +else $as_nop + \ + echo "You need to install the OpenGL library." + exit -1 +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for alGetError in -lopenal" >&5 +printf %s "checking for alGetError in -lopenal... " >&6; } +if test ${ac_cv_lib_openal_alGetError+y} +then : + printf %s "(cached) " >&6 +else $as_nop + 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. */ +char alGetError (); +int +main (void) +{ +return alGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_openal_alGetError=yes +else $as_nop + ac_cv_lib_openal_alGetError=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_openal_alGetError" >&5 +printf "%s\n" "$ac_cv_lib_openal_alGetError" >&6; } +if test "x$ac_cv_lib_openal_alGetError" = xyes +then : + printf "%s\n" "#define HAVE_LIBOPENAL 1" >>confdefs.h + + LIBS="-lopenal $LIBS" + +else $as_nop + \ + echo "You need to install the OpenAL library." + exit -1 +fi + + build_win="yes" + SET_MAKE='MAKE=mingw32-make' + + ;; + *-*-linux*) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for glGetError in -lGL" >&5 +printf %s "checking for glGetError in -lGL... " >&6; } +if test ${ac_cv_lib_GL_glGetError+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGL $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. */ +char glGetError (); +int +main (void) +{ +return glGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_GL_glGetError=yes +else $as_nop + ac_cv_lib_GL_glGetError=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_GL_glGetError" >&5 +printf "%s\n" "$ac_cv_lib_GL_glGetError" >&6; } +if test "x$ac_cv_lib_GL_glGetError" = xyes +then : + printf "%s\n" "#define HAVE_LIBGL 1" >>confdefs.h + + LIBS="-lGL $LIBS" + +else $as_nop + \ + echo "You need to install the OpenGL library." + exit -1 +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for alGetError in -lopenal" >&5 +printf %s "checking for alGetError in -lopenal... " >&6; } +if test ${ac_cv_lib_openal_alGetError+y} +then : + printf %s "(cached) " >&6 +else $as_nop + 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. */ +char alGetError (); +int +main (void) +{ +return alGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_openal_alGetError=yes +else $as_nop + ac_cv_lib_openal_alGetError=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_openal_alGetError" >&5 +printf "%s\n" "$ac_cv_lib_openal_alGetError" >&6; } +if test "x$ac_cv_lib_openal_alGetError" = xyes +then : + printf "%s\n" "#define HAVE_LIBOPENAL 1" >>confdefs.h + + LIBS="-lopenal $LIBS" + +else $as_nop + \ + echo "You need to install the OpenAL library." + exit -1 +fi + + build_linux="yes" + ;; + *-*-freebsd*) + CFLAGS="$CFLAGS -I/usr/local/include" + CXXFLAGS="$CXXFLAGS -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib" + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for glGetError in -lGL" >&5 +printf %s "checking for glGetError in -lGL... " >&6; } +if test ${ac_cv_lib_GL_glGetError+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGL $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. */ +char glGetError (); +int +main (void) +{ +return glGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_GL_glGetError=yes +else $as_nop + ac_cv_lib_GL_glGetError=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_GL_glGetError" >&5 +printf "%s\n" "$ac_cv_lib_GL_glGetError" >&6; } +if test "x$ac_cv_lib_GL_glGetError" = xyes +then : + printf "%s\n" "#define HAVE_LIBGL 1" >>confdefs.h + + LIBS="-lGL $LIBS" + +else $as_nop + \ + echo "You need to install the OpenGL library." + exit -1 +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for alGetError in -lopenal" >&5 +printf %s "checking for alGetError in -lopenal... " >&6; } +if test ${ac_cv_lib_openal_alGetError+y} +then : + printf %s "(cached) " >&6 +else $as_nop + 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. */ +char alGetError (); +int +main (void) +{ +return alGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_openal_alGetError=yes +else $as_nop + ac_cv_lib_openal_alGetError=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_openal_alGetError" >&5 +printf "%s\n" "$ac_cv_lib_openal_alGetError" >&6; } +if test "x$ac_cv_lib_openal_alGetError" = xyes +then : + printf "%s\n" "#define HAVE_LIBOPENAL 1" >>confdefs.h + + LIBS="-lopenal $LIBS" + +else $as_nop + \ + echo "You need to install the OpenAL library." + exit -1 +fi + + build_other="yes" + ;; + *) + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for glGetError in -lGL" >&5 +printf %s "checking for glGetError in -lGL... " >&6; } +if test ${ac_cv_lib_GL_glGetError+y} +then : + printf %s "(cached) " >&6 +else $as_nop + ac_check_lib_save_LIBS=$LIBS +LIBS="-lGL $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. */ +char glGetError (); +int +main (void) +{ +return glGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_GL_glGetError=yes +else $as_nop + ac_cv_lib_GL_glGetError=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_GL_glGetError" >&5 +printf "%s\n" "$ac_cv_lib_GL_glGetError" >&6; } +if test "x$ac_cv_lib_GL_glGetError" = xyes +then : + printf "%s\n" "#define HAVE_LIBGL 1" >>confdefs.h + + LIBS="-lGL $LIBS" + +else $as_nop + \ + echo "You need to install the OpenGL library." + exit -1 +fi + + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for alGetError in -lopenal" >&5 +printf %s "checking for alGetError in -lopenal... " >&6; } +if test ${ac_cv_lib_openal_alGetError+y} +then : + printf %s "(cached) " >&6 +else $as_nop + 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. */ +char alGetError (); +int +main (void) +{ +return alGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO" +then : + ac_cv_lib_openal_alGetError=yes +else $as_nop + ac_cv_lib_openal_alGetError=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.beam \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_openal_alGetError" >&5 +printf "%s\n" "$ac_cv_lib_openal_alGetError" >&6; } +if test "x$ac_cv_lib_openal_alGetError" = xyes +then : + printf "%s\n" "#define HAVE_LIBOPENAL 1" >>confdefs.h + + LIBS="-lopenal $LIBS" + +else $as_nop + \ + echo "You need to install the OpenAL library." + exit -1 +fi + + build_other="yes" + ;; +esac + +CFLAGS="$CFLAGS $SDL_CFLAGS" +LIBS="$LIBS $WX_LIBS $SDL_LIBS" + + if test "$build_linux" = "yes"; then + OS_LINUX_TRUE= + OS_LINUX_FALSE='#' +else + OS_LINUX_TRUE='#' + OS_LINUX_FALSE= +fi + + if test "$build_win" = "yes"; then + OS_WINDOWS_TRUE= + OS_WINDOWS_FALSE='#' +else + OS_WINDOWS_TRUE='#' + OS_WINDOWS_FALSE= +fi + + if test "$build_other" = "yes"; then + OS_OTHER_TRUE= + OS_OTHER_FALSE='#' +else + OS_OTHER_TRUE='#' + OS_OTHER_FALSE= +fi + + if test "$build_macosx" = "yes"; then + OS_MACOSX_TRUE= + OS_MACOSX_FALSE='#' +else + OS_MACOSX_TRUE='#' + OS_MACOSX_FALSE= +fi + + ac_config_files="$ac_config_files Makefile src/Makefile" cat >confcache <<\_ACEOF @@ -4594,8 +6769,8 @@ _ACEOF 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;} ;; + *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( @@ -4625,15 +6800,15 @@ $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; /^ac_cv_env_/b end t clear :clear - s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ 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 if test "x$cache_file" != "x/dev/null"; then - { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 -$as_echo "$as_me: updating cache $cache_file" >&6;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else @@ -4647,8 +6822,8 @@ $as_echo "$as_me: updating cache $cache_file" >&6;} fi fi 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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache @@ -4701,7 +6876,7 @@ U= 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"` + ac_i=`printf "%s\n" "$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" @@ -4712,14 +6887,14 @@ LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs -{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 -$as_echo_n "checking that generated files are newer than configure... " >&6; } +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 +printf %s "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi - { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 -$as_echo "done" >&6; } + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: done" >&5 +printf "%s\n" "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' @@ -4740,6 +6915,10 @@ 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 "${RELEASE_BUILD_TRUE}" && test -z "${RELEASE_BUILD_FALSE}"; then + as_fn_error $? "conditional \"RELEASE_BUILD\" 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 @@ -4748,21 +6927,53 @@ 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. +if test -z "${CPU_ARM_TRUE}" && test -z "${CPU_ARM_FALSE}"; then + as_fn_error $? "conditional \"CPU_ARM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CPU_ARM64_TRUE}" && test -z "${CPU_ARM64_FALSE}"; then + as_fn_error $? "conditional \"CPU_ARM64\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_WX_TRUE}" && test -z "${USE_WX_FALSE}"; then + as_fn_error $? "conditional \"USE_WX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_NETWORKING_TRUE}" && test -z "${USE_NETWORKING_FALSE}"; then + as_fn_error $? "conditional \"USE_NETWORKING\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${USE_ALSA_TRUE}" && test -z "${USE_ALSA_FALSE}"; then + as_fn_error $? "conditional \"USE_ALSA\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAS_OFF64T_TRUE}" && test -z "${HAS_OFF64T_FALSE}"; then + as_fn_error $? "conditional \"HAS_OFF64T\" 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 +if test -z "${OS_WINDOWS_TRUE}" && test -z "${OS_WINDOWS_FALSE}"; then + as_fn_error $? "conditional \"OS_WINDOWS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OS_OTHER_TRUE}" && test -z "${OS_OTHER_FALSE}"; then + as_fn_error $? "conditional \"OS_OTHER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OS_MACOSX_TRUE}" && test -z "${OS_MACOSX_FALSE}"; then + as_fn_error $? "conditional \"OS_MACOSX\" 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;} +{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL @@ -4785,14 +6996,16 @@ cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh -if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : +as_nop=: +if test ${ZSH_VERSION+y} && (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 +else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( @@ -4802,46 +7015,46 @@ esac fi + +# Reset variables that may have inherited troublesome values from +# the environment. + +# IFS needs to be set, to space, tab, and newline, in precisely that order. +# (If _AS_PATH_WALK were called with IFS unset, it would have the +# side effect of setting IFS to empty, thus disabling word splitting.) +# Quoting is to prevent editors from complaining about space-tab. 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 +IFS=" "" $as_nl" + +PS1='$ ' +PS2='> ' +PS4='+ ' + +# Ensure predictable behavior from utilities with locale-dependent output. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# We cannot yet rely on "unset" to work, but we need these variables +# to be unset--not just set to an empty or harmless value--now, to +# avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct +# also avoids known problems related to "unset" and subshell syntax +# in other old shells (e.g. bash 2.01 and pdksh 5.2.14). +for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH +do eval test \${$as_var+y} \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done + +# Ensure that fds 0, 1, and 2 are open. +if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi +if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. -if test "${PATH_SEPARATOR+set}" != set; then +if ${PATH_SEPARATOR+false} :; 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 || @@ -4850,13 +7063,6 @@ if test "${PATH_SEPARATOR+set}" != set; then 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. as_myself= case $0 in #(( @@ -4865,8 +7071,12 @@ case $0 in #(( 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 + case $as_dir in #((( + '') as_dir=./ ;; + */) ;; + *) as_dir=$as_dir/ ;; + esac + test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS @@ -4878,30 +7088,10 @@ 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 + printf "%s\n" "$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 STATUS ERROR [LINENO LOG_FD] @@ -4914,13 +7104,14 @@ as_fn_error () as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi - $as_echo "$as_me: error: $2" >&2 + printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error + # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. @@ -4947,18 +7138,20 @@ 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 : +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 +else $as_nop as_fn_append () { eval $1=\$$1\$2 @@ -4970,12 +7163,13 @@ fi # as_fn_append # 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 : +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null +then : eval 'as_fn_arith () { as_val=$(( $* )) }' -else +else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` @@ -5006,7 +7200,7 @@ as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || -$as_echo X/"$0" | +printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q @@ -5028,6 +7222,10 @@ as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits + +# Determine whether it's possible to make 'echo' print without a newline. +# These variables are no longer used directly by Autoconf, but are AC_SUBSTed +# for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) @@ -5041,6 +7239,12 @@ case `echo -n x` in #((((( ECHO_N='-n';; esac +# For backward compatibility with old third-party macros, we provide +# the shell variables $as_echo and $as_echo_n. New code should use +# AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. +as_echo='printf %s\n' +as_echo_n='printf %s' + rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file @@ -5082,7 +7286,7 @@ as_fn_mkdir_p () as_dirs= while :; do case $as_dir in #( - *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" @@ -5091,7 +7295,7 @@ $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" | +printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -5153,8 +7357,8 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # 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 v12, which was -generated by GNU Autoconf 2.69. Invocation command line was +This file was extended by PCem $as_me v17, which was +generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -5204,17 +7408,19 @@ $config_files Configuration commands: $config_commands -Report bugs to >." +Report bugs to >." _ACEOF +ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` +ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 -ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ -PCem config.status v12 -configured by $0, generated by GNU Autoconf 2.69, +PCem config.status v17 +configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" -Copyright (C) 2012 Free Software Foundation, Inc. +Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -5254,21 +7460,21 @@ do -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 ;; + printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) - $as_echo "$ac_cs_config"; exit ;; + printf "%s\n" "$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"` ;; + *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) - $as_echo "$ac_cs_usage"; exit ;; + printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; @@ -5296,7 +7502,7 @@ 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 + \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" @@ -5310,7 +7516,7 @@ exec 5>>config.log sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX - $as_echo "$ac_log" + printf "%s\n" "$ac_log" } >&5 _ACEOF @@ -5318,7 +7524,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # -AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" +AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF @@ -5342,8 +7548,8 @@ done # 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 + test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files + test ${CONFIG_COMMANDS+y} || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree @@ -5571,7 +7777,7 @@ do esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac - case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done @@ -5579,17 +7785,17 @@ do # 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' + printf "%s\n" "$*" | 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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +printf "%s\n" "$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" | + ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac @@ -5606,7 +7812,7 @@ $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" | +printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -5630,9 +7836,9 @@ $as_echo X"$ac_file" | case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) - ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + ac_dir_suffix=/`printf "%s\n" "$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|/||'` + ac_top_builddir_sub=`printf "%s\n" "$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/ ;; @@ -5694,8 +7900,8 @@ ac_sed_dataroot=' 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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +printf "%s\n" "$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=' @@ -5739,9 +7945,9 @@ test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && - { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' + { printf "%s\n" "$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' +printf "%s\n" "$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 "$ac_tmp/stdin" @@ -5753,8 +7959,8 @@ which seems to be undefined. Please make sure it is defined" >&2;} ;; - :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 -$as_echo "$as_me: executing $ac_file commands" >&6;} + :C) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +printf "%s\n" "$as_me: executing $ac_file commands" >&6;} ;; esac @@ -5764,29 +7970,35 @@ $as_echo "$as_me: executing $ac_file commands" >&6;} # Older Autoconf 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 + # TODO: see whether this extra hack can be removed once we start + # requiring Autoconf 2.70 or later. + case $CONFIG_FILES in #( + *\'*) : + eval set x "$CONFIG_FILES" ;; #( + *) : + set x $CONFIG_FILES ;; #( + *) : + ;; +esac shift - for mf + # Used to flag and report bootstrapping failures. + am_rc=0 + for am_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 + am_mf=`printf "%s\n" "$am_mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile which includes + # dependency-tracking related rules and includes. + # Grep'ing the whole file directly is not great: 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 -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ + || continue + am_dirpart=`$as_dirname -- "$am_mf" || +$as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$am_mf" : 'X\(//\)[^/]' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -5804,53 +8016,50 @@ $as_echo X"$mf" | 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"` - # 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'`; 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\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + am_filepart=`$as_basename -- "$am_mf" || +$as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ + X"$am_mf" : 'X\(//\)$' \| \ + X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || +printf "%s\n" X/"$am_mf" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } - /^X\(\/\/\)[^/].*/{ + /^X\/\(\/\/\)$/{ s//\1/ q } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ + /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` - as_dir=$dirpart/$fdir; as_fn_mkdir_p - # echo "creating $dirpart/$file" - echo '# dummy' > "$dirpart/$file" - done + { echo "$as_me:$LINENO: cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles" >&5 + (cd "$am_dirpart" \ + && sed -e '/# am--include-marker/d' "$am_filepart" \ + | $MAKE -f - am--depfiles) >&5 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } || am_rc=$? done + if test $am_rc -ne 0; then + { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error $? "Something went wrong bootstrapping makefile fragments + for automatic dependency tracking. If GNU make was not used, consider + re-running the configure script with MAKE=\"gmake\" (or whatever is + necessary). You can also try re-running configure with the + '--disable-dependency-tracking' option to at least be able to build + the package (albeit without support for automatic dependency tracking). +See \`config.log' for more details" "$LINENO" 5; } + fi + { am_dirpart=; unset am_dirpart;} + { am_filepart=; unset am_filepart;} + { am_mf=; unset am_mf;} + { am_rc=; unset am_rc;} + rm -f conftest-deps.mk } ;; @@ -5887,7 +8096,8 @@ if test "$no_create" != yes; then $ac_cs_success || as_fn_exit 1 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;} + { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi + diff --git a/configure.ac b/configure.ac index 2e38eca..408ac13 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # AC_PREREQ([2.61]) -AC_INIT(PCem, v12, Sarah Walker , pcem) +AC_INIT(PCem, v17, Sarah Walker , pcem) AC_CANONICAL_HOST @@ -13,58 +13,185 @@ 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_CHECKING([whether to build for release]) +AC_ARG_ENABLE(release_build, + AC_HELP_STRING([--enable-release-build], [build for release])) +if test "$enable_release_build" = "yes"; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi +AM_CONDITIONAL(RELEASE_BUILD, [test "$enable_release_build" = "yes"]) + +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="$CFLAGS -Wall -O0 -g -D_DEBUG -fcommon" + CXXFLAGS="$CXXFLAGS -Wall -O0 -g -D_DEBUG -fcommon" + AC_MSG_RESULT([yes]) +else + CFLAGS="$CFLAGS -O3 -fcommon" + CXXFLAGS="$CXXFLAGS -O3 -fcommon" + AC_MSG_RESULT([no]) +fi + +AC_MSG_CHECKING([whether to enable networking]) +AC_ARG_ENABLE(networking, + AC_HELP_STRING([--enable-networking], [enable networking])) +if test "$enable_networking" = "yes"; then + AC_MSG_RESULT([yes]) +else + AC_MSG_RESULT([no]) +fi + +AC_MSG_CHECKING([whether to use ALSA for MIDI output]) +AC_ARG_ENABLE(alsa, + AC_HELP_STRING([--enable-alsa], [use ALSA for MIDI])) +if test "$enable_alsa" = "yes"; then 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.]) - ;; + i?86) + CPU=i386 + AC_MSG_RESULT(${host_cpu}) + ;; + x86_64) + CPU=x86_64 + AC_MSG_RESULT(${host_cpu}) + ;; + armv7l) + CPU=arm + AC_MSG_RESULT(${host_cpu}) + ;; + aarch64) + CPU=arm64 + AC_MSG_RESULT(${host_cpu}) + ;; + *) + AC_MSG_ERROR([Unsupported CPU. ${host_cpu}]) + ;; esac AM_CONDITIONAL(CPU_I386, test "$CPU" = "i386") AM_CONDITIONAL(CPU_X86_64, test "$CPU" = "x86_64") +AM_CONDITIONAL(CPU_ARM, test "$CPU" = "arm") +AM_CONDITIONAL(CPU_ARM64, test "$CPU" = "arm64") + +AC_MSG_CHECKING([for off64_t $CPU]) +AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include ]],[[off64_t n=0;]])],[has_lfs="yes"],[has_lfs="no"]) +case "$host" in + *-*-freebsd*) # has off64_t but no fopen64/etc. + has_lfs="no" + ;; +esac +AC_MSG_RESULT($has_lfs) #AC_MSG_CHECKING([for libz]) #AX_CHECK_ZLIB -AM_CONDITIONAL(OS_WIN, test "$OS" = "win") -AM_CONDITIONAL(OS_LINUX, test "$OS" = "linux") +AM_CONDITIONAL(USE_WX, test "$enable_wx" = "yes") +AM_CONDITIONAL(USE_NETWORKING, test "$enable_networking" = "yes") +AM_CONDITIONAL(USE_ALSA, test "$enable_alsa" = "yes") -# 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 - AC_CONFIG_MACRO_DIR([./]) - AM_PATH_ALLEGRO(, , AC_MSG_ERROR(building PCem requires Allegro to be installed)) +AM_CONDITIONAL(HAS_OFF64T, test "$has_lfs" = "yes") + +SDL_VERSION=2.0.1 +AM_PATH_SDL2($SDL_VERSION, + :, + AC_MSG_ERROR([*** SDL version $SDL_VERSION not found!]) +) + +AM_OPTIONS_WXCONFIG +reqwx=3.0.0 +AM_PATH_WXCONFIG($reqwx, wxWin=1) +if test "$wxWin" != 1; then + AC_MSG_ERROR([ + wxWidgets must be installed on your system. + + Please check that wx-config is in path, the directory + where wxWidgets libraries are installed (returned by + 'wx-config --libs' or 'wx-config --static --libs' command) + is in LD_LIBRARY_PATH or equivalent variable and + wxWidgets version is $reqwx or above. + ]) 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]) +if test "$enable_alsa" == "yes"; then + AC_CHECK_LIB(asound, snd_pcm_open, + [], + [echo "You need to install the ALSA library." + exit -1]) +fi AC_CHECK_LIB([pthread], [pthread_create]) +build_macosx="no" +build_linux="no" +build_win="no" +build_other="no" + +case "$host" in + *-*-darwin*) + LIBS="$LIBS -framework OpenGL" + LIBS="$LIBS -framework OpenAL" + build_macosx="yes" + CFLAGS="$CFLAGS -DHAVE_UNISTD_H" + ;; + *-*-cygwin* | *-*-mingw32*) + AC_CHECK_LIB([opengl32], [main], [], \ + [echo "You need to install the OpenGL library." + exit -1]) + AC_CHECK_LIB([openal], [alGetError], [], \ + [echo "You need to install the OpenAL library." + exit -1]) + build_win="yes" + AC_SUBST(SET_MAKE, 'MAKE=mingw32-make') + ;; + *-*-linux*) + AC_CHECK_LIB([GL], [glGetError], [], \ + [echo "You need to install the OpenGL library." + exit -1]) + AC_CHECK_LIB([openal], [alGetError], [], \ + [echo "You need to install the OpenAL library." + exit -1]) + build_linux="yes" + CFLAGS="$CFLAGS -DHAVE_UNISTD_H" + ;; + *-*-freebsd*) + CFLAGS="$CFLAGS -I/usr/local/include" + CXXFLAGS="$CXXFLAGS -I/usr/local/include" + LDFLAGS="$LDFLAGS -L/usr/local/lib" + AC_CHECK_LIB([GL], [glGetError], [], \ + [echo "You need to install the OpenGL library." + exit -1]) + AC_CHECK_LIB([openal], [alGetError], [], \ + [echo "You need to install the OpenAL library." + exit -1]) + build_other="yes" + CFLAGS="$CFLAGS -DHAVE_UNISTD_H" + ;; + *) + AC_CHECK_LIB([GL], [glGetError], [], \ + [echo "You need to install the OpenGL library." + exit -1]) + AC_CHECK_LIB([openal], [alGetError], [], \ + [echo "You need to install the OpenAL library." + exit -1]) + build_other="yes" + ;; +esac + +CFLAGS="$CFLAGS $SDL_CFLAGS" +LIBS="$LIBS $WX_LIBS $SDL_LIBS" + +AM_CONDITIONAL(OS_LINUX, [test "$build_linux" = "yes"]) +AM_CONDITIONAL(OS_WINDOWS, [test "$build_win" = "yes"]) +AM_CONDITIONAL(OS_OTHER, [test "$build_other" = "yes"]) +AM_CONDITIONAL(OS_MACOSX, [test "$build_macosx" = "yes"]) + AC_OUTPUT([Makefile src/Makefile]) diff --git a/install-sh b/install-sh old mode 100644 new mode 100755 diff --git a/nvr/aha1542c.nvr b/nvr/aha1542c.nvr new file mode 100644 index 0000000..f62cc4b Binary files /dev/null and b/nvr/aha1542c.nvr differ diff --git a/nvr/ami386dx_opti495.nvr b/nvr/ami386dx_opti495.nvr index dca4bd2..b6de20e 100644 Binary files a/nvr/ami386dx_opti495.nvr and b/nvr/ami386dx_opti495.nvr differ diff --git a/nvr/default/430vx.nvr b/nvr/default/430vx.nvr new file mode 100644 index 0000000..17ac54e Binary files /dev/null and b/nvr/default/430vx.nvr differ diff --git a/nvr/default/acer386.nvr b/nvr/default/acer386.nvr new file mode 100644 index 0000000..22bff6c Binary files /dev/null and b/nvr/default/acer386.nvr differ diff --git a/nvr/default/adgold.bin b/nvr/default/adgold.bin new file mode 100644 index 0000000..566bffc Binary files /dev/null and b/nvr/default/adgold.bin differ diff --git a/nvr/default/aha1542c.nvr b/nvr/default/aha1542c.nvr new file mode 100644 index 0000000..f62cc4b Binary files /dev/null and b/nvr/default/aha1542c.nvr differ diff --git a/nvr/default/ami286.nvr b/nvr/default/ami286.nvr new file mode 100644 index 0000000..bfb993f Binary files /dev/null and b/nvr/default/ami286.nvr differ diff --git a/nvr/default/ami386.nvr b/nvr/default/ami386.nvr new file mode 100644 index 0000000..2256301 Binary files /dev/null and b/nvr/default/ami386.nvr differ diff --git a/nvr/default/ami386dx_opti495.nvr b/nvr/default/ami386dx_opti495.nvr new file mode 100644 index 0000000..b6de20e Binary files /dev/null and b/nvr/default/ami386dx_opti495.nvr differ diff --git a/nvr/default/ami486.nvr b/nvr/default/ami486.nvr new file mode 100644 index 0000000..7055279 Binary files /dev/null and b/nvr/default/ami486.nvr differ diff --git a/nvr/default/at.nvr b/nvr/default/at.nvr new file mode 100644 index 0000000..b5c94c1 Binary files /dev/null and b/nvr/default/at.nvr differ diff --git a/nvr/default/award286.nvr b/nvr/default/award286.nvr new file mode 100644 index 0000000..223aa99 Binary files /dev/null and b/nvr/default/award286.nvr differ diff --git a/nvr/default/cmdpc30.nvr b/nvr/default/cmdpc30.nvr new file mode 100644 index 0000000..3e65518 Binary files /dev/null and b/nvr/default/cmdpc30.nvr differ diff --git a/nvr/default/dell200.nvr b/nvr/default/dell200.nvr new file mode 100644 index 0000000..b16f184 Binary files /dev/null and b/nvr/default/dell200.nvr differ diff --git a/nvr/default/deskpro386.nvr b/nvr/default/deskpro386.nvr new file mode 100644 index 0000000..95ab63b Binary files /dev/null and b/nvr/default/deskpro386.nvr differ diff --git a/nvr/default/endeavor.nvr b/nvr/default/endeavor.nvr new file mode 100644 index 0000000..ade1a43 Binary files /dev/null and b/nvr/default/endeavor.nvr differ diff --git a/nvr/default/europc.nvr b/nvr/default/europc.nvr new file mode 100644 index 0000000..6757695 Binary files /dev/null and b/nvr/default/europc.nvr differ diff --git a/nvr/default/gw286ct.nvr b/nvr/default/gw286ct.nvr new file mode 100644 index 0000000..8a712f9 Binary files /dev/null and b/nvr/default/gw286ct.nvr differ diff --git a/nvr/default/hot-433.nvr b/nvr/default/hot-433.nvr new file mode 100644 index 0000000..104e711 Binary files /dev/null and b/nvr/default/hot-433.nvr differ diff --git a/nvr/default/ibmps1_2011.nvr b/nvr/default/ibmps1_2011.nvr new file mode 100644 index 0000000..2029c7b Binary files /dev/null and b/nvr/default/ibmps1_2011.nvr differ diff --git a/nvr/default/ibmps1_2121.nvr b/nvr/default/ibmps1_2121.nvr new file mode 100644 index 0000000..0501a36 Binary files /dev/null and b/nvr/default/ibmps1_2121.nvr differ diff --git a/nvr/default/ibmps2_m50.nvr b/nvr/default/ibmps2_m50.nvr new file mode 100644 index 0000000..9d63cdc Binary files /dev/null and b/nvr/default/ibmps2_m50.nvr differ diff --git a/nvr/default/ibmps2_m55sx.nvr b/nvr/default/ibmps2_m55sx.nvr new file mode 100644 index 0000000..e83ab4f Binary files /dev/null and b/nvr/default/ibmps2_m55sx.nvr differ diff --git a/nvr/default/ibmps2_m60.nvr b/nvr/default/ibmps2_m60.nvr new file mode 100644 index 0000000..33c5fb6 Binary files /dev/null and b/nvr/default/ibmps2_m60.nvr differ diff --git a/nvr/default/ibmps2_m65sx.nvr b/nvr/default/ibmps2_m65sx.nvr new file mode 100644 index 0000000..7bee33c Binary files /dev/null and b/nvr/default/ibmps2_m65sx.nvr differ diff --git a/nvr/default/ibmps2_m70.nvr b/nvr/default/ibmps2_m70.nvr new file mode 100644 index 0000000..c4c5578 Binary files /dev/null and b/nvr/default/ibmps2_m70.nvr differ diff --git a/nvr/default/ibmps2_m70_sec.nvr b/nvr/default/ibmps2_m70_sec.nvr new file mode 100644 index 0000000..4ed6224 Binary files /dev/null and b/nvr/default/ibmps2_m70_sec.nvr differ diff --git a/nvr/default/ibmps2_m80.nvr b/nvr/default/ibmps2_m80.nvr new file mode 100644 index 0000000..4e26e24 Binary files /dev/null and b/nvr/default/ibmps2_m80.nvr differ diff --git a/nvr/default/ibmps2_m80_sec.nvr b/nvr/default/ibmps2_m80_sec.nvr new file mode 100644 index 0000000..e7e171e Binary files /dev/null and b/nvr/default/ibmps2_m80_sec.nvr differ diff --git a/nvr/default/ibmxt286.nvr b/nvr/default/ibmxt286.nvr new file mode 100644 index 0000000..b5c94c1 Binary files /dev/null and b/nvr/default/ibmxt286.nvr differ diff --git a/nvr/default/kmxc02.nvr b/nvr/default/kmxc02.nvr new file mode 100644 index 0000000..0b281a8 Binary files /dev/null and b/nvr/default/kmxc02.nvr differ diff --git a/nvr/default/megapc.nvr b/nvr/default/megapc.nvr new file mode 100644 index 0000000..3892761 Binary files /dev/null and b/nvr/default/megapc.nvr differ diff --git a/nvr/default/mr386dx_opti495.nvr b/nvr/default/mr386dx_opti495.nvr new file mode 100644 index 0000000..9146987 Binary files /dev/null and b/nvr/default/mr386dx_opti495.nvr differ diff --git a/nvr/default/pb570.nvr b/nvr/default/pb570.nvr new file mode 100644 index 0000000..cc21f81 Binary files /dev/null and b/nvr/default/pb570.nvr differ diff --git a/nvr/default/pc1512.nvr b/nvr/default/pc1512.nvr new file mode 100644 index 0000000..b1f758b Binary files /dev/null and b/nvr/default/pc1512.nvr differ diff --git a/nvr/default/pc1640.nvr b/nvr/default/pc1640.nvr new file mode 100644 index 0000000..7171e74 Binary files /dev/null and b/nvr/default/pc1640.nvr differ diff --git a/nvr/default/pc200.nvr b/nvr/default/pc200.nvr new file mode 100644 index 0000000..fcb1cb6 --- /dev/null +++ b/nvr/default/pc200.nvr @@ -0,0 +1 @@ +X \ No newline at end of file diff --git a/nvr/default/pc2086.nvr b/nvr/default/pc2086.nvr new file mode 100644 index 0000000..40f5636 Binary files /dev/null and b/nvr/default/pc2086.nvr differ diff --git a/nvr/default/pc3086.nvr b/nvr/default/pc3086.nvr new file mode 100644 index 0000000..f340d66 Binary files /dev/null and b/nvr/default/pc3086.nvr differ diff --git a/nvr/default/revenge.nvr b/nvr/default/revenge.nvr new file mode 100644 index 0000000..c10c53c Binary files /dev/null and b/nvr/default/revenge.nvr differ diff --git a/nvr/default/sis496.nvr b/nvr/default/sis496.nvr new file mode 100644 index 0000000..6d35a3c Binary files /dev/null and b/nvr/default/sis496.nvr differ diff --git a/nvr/default/spc4200p.nvr b/nvr/default/spc4200p.nvr new file mode 100644 index 0000000..e1602c2 Binary files /dev/null and b/nvr/default/spc4200p.nvr differ diff --git a/nvr/default/spc4216p.nvr b/nvr/default/spc4216p.nvr new file mode 100644 index 0000000..f1ab56d Binary files /dev/null and b/nvr/default/spc4216p.nvr differ diff --git a/nvr/default/tandy1000hx.bin b/nvr/default/tandy1000hx.bin new file mode 100644 index 0000000..e69de4f Binary files /dev/null and b/nvr/default/tandy1000hx.bin differ diff --git a/nvr/default/tandy1000sl2.bin b/nvr/default/tandy1000sl2.bin new file mode 100644 index 0000000..e69de4f Binary files /dev/null and b/nvr/default/tandy1000sl2.bin differ diff --git a/nvr/default/win486.nvr b/nvr/default/win486.nvr new file mode 100644 index 0000000..9722138 Binary files /dev/null and b/nvr/default/win486.nvr differ diff --git a/nvr/ibmps2_m50.nvr b/nvr/ibmps2_m50.nvr new file mode 100644 index 0000000..9d63cdc Binary files /dev/null and b/nvr/ibmps2_m50.nvr differ diff --git a/nvr/ibmps2_m55sx.nvr b/nvr/ibmps2_m55sx.nvr new file mode 100644 index 0000000..e83ab4f Binary files /dev/null and b/nvr/ibmps2_m55sx.nvr differ diff --git a/nvr/ibmps2_m80.nvr b/nvr/ibmps2_m80.nvr new file mode 100644 index 0000000..4e26e24 Binary files /dev/null and b/nvr/ibmps2_m80.nvr differ diff --git a/nvr/ibmps2_m80_sec.nvr b/nvr/ibmps2_m80_sec.nvr new file mode 100644 index 0000000..e7e171e Binary files /dev/null and b/nvr/ibmps2_m80_sec.nvr differ diff --git a/readme.html b/readme.html new file mode 100644 index 0000000..8694110 --- /dev/null +++ b/readme.html @@ -0,0 +1,1467 @@ + + + + + + + readme + + + + +

PCem

+

Download: Windows/Linux

+

Latest version: v17 Changelog

+

PCem is licensed under GPL v2.0, see COPYING for more details.

+

You can submit patches on our forum. Before you do, please note the guidelines for submitting patches.

+

Note: NO COPYRIGHTED ROM FILES ARE INCLUDED NOR WILL THEY BE. PLEASE DO NOT ASK FOR THEM.

+

BSD and Linux supplement (v17)

+

You will need the following libraries (and their dependencies):

+
    +
  • SDL2
  • +
  • wxWidgets 3.x
  • +
  • OpenAL
  • +
+

Open a terminal window, navigate to the PCem directory then enter:

+

Linux

+
./configure --enable-release
+make
+

BSD

+
./configure --enable-release-build
+gmake
+

then ./pcem to run.

+

The Linux/BSD versions store BIOS ROM images, configuration files, and other data in ~/.pcem

+

configure options are :

+
  --enable-release-build : Generate release build. Recommended for regular use.
+  --enable-debug         : Compile with debugging enabled.
+  --enable-networking    : Build with networking support.
+  --enable-alsa          : Build with support for MIDI output through ALSA. Requires libasound.
+

The menu is a pop-up menu in the Linux/BSD port. Right-click on the main window when mouse is not captured.

+

CD-ROM support currently only accesses /dev/cdrom. It has not been heavily tested.

+ +

PCem emulates the following hardware (as of v17):

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HardwareLinks
Systems8088
8086
286
386
486
Pentium
Super Socket 7
GraphicsBasic
Unaccelerated (S)VGA cards
2D accelerated SVGA cards
3D accelerated SVGA cards
3D only cards
SoundCards
HDD ControllerCards
MiscCards
+

Software Tested (list)

+ +
+ +

Systems

+

8088 based

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReleaseMachineROM file needed
(within ./roms/ folder)
1981IBM PC
8088 at 4.77 MHz
16KB - 640KB RAM (min. 64KB)
ibmpc/pc102782.bin
ibmpc/basicc11.f6
ibmpc/basicc11.f8
ibmpc/basicc11.fa
ibmpc/basicc11.fc
1983Compaq Portable Plus
8088 at 4.77 MHz
128KB - 640KB RAM
compaq_pip/Compaq Portable Plus 100666-001 Rev C.bin
1983IBM XT
8088 at 4.77 MHz
64KB - 640KB RAM
ibmxt/5000027.u19
ibmxt/1501512.u18
1983Leading Edge Model M
8088 at 7.16 MHz
128KB - 704KB RAM
leadingedge_modelm/Leading Edge - Model M - BIOS ROM - Version 4.71.bin
1984IBM PCjr [5]
8088 at 4.77 MHz
64KB - 640KB RAM (min. 128KB)
Built-in 16 colour graphics
3 voice sound
Not generally PC compatible.
ibmpcjr/bios.rom
1984Tandy 1000 [5]
8088 at 4.77 MHz
128KB - 640KB RAM
Built-in 16 colour graphics
3 voice sound
tandy/tandy1t1.020
1985NCR PC4i
8088 at 4.77 MHz
256KB - 640KB RAM
ncr_pc4i/NCR_PC4i_BIOSROM_1985.BIN
1986DTK Clone XT
8088 at 8/10 MHz
64KB - 640KB RAM
dtk/dtk_erso_2.42_2764.bin
1986Phoenix XT clone
8088 at 8/10 MHz
64KB - 640KB RAM
pxxt/000p001.bin
1987Tandy 1000HX
8088 at 7.16 MHz
256KB - 640KB RAM
Built-in 16 colour graphics
3 voice sound
Has DOS 2.11 in ROM
tandy1000hx/v020000.u12
1987Thomson TO16 PC
8088 at 9.54 MHz
512KB - 640KB RAM
to16_pc/TO16_103.bin
1987Toshiba T1000 [1] [5]
8088 at 4.77 MHz
512KB - 1024KB RAM
CGA on built-in LCD
t1000/t1000.rom
t1000/t1000font.rom
1987VTech Laser Turbo XT
8088 at 10 MHz
640KB RAM
ltxt/27c64.bin
1987Zenith Data SupersPort
8088 at 8 MHz
128KB - 640KB RAM
Built-in LCD video is not currently emulated
zdsupers/z184m v3.1d.10d
1988?©Anonymous Generic Turbo XT BIOS
8088 at 8+ MHz
64KB - 640KB RAM
genxt/pcxt.rom
1988Atari PC3
8088 at 8 MHz
640KB RAM
ataripc3/AWARD_ATARI_PC_BIOS_3.08.BIN
1988Juko XT clonejukopc/000o001.bin
1988Schneider Euro PC
8088 at 9.54 MHz
512KB - 640KB RAM
europc/50145
europc/50146
1989AMI XT clone
8088 at 8+ MHz
64KB - 640KB RAM
amixt/ami_8088_bios_31jan89.bin
2015Xi8088
8088 at 4.77-13.33 MHz
640KB RAM
xi8088/bios-xi8088.bin
+

8086 based

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReleaseMachineROM file needed
(within ./roms/ folder)
1984Compaq Deskpro
8086 at 8 MHz
128KB - 640KB RAM
deskpro/Compaq - BIOS - Revision J - 106265-002.bin
1984Olivetti M24 [5]
8086 at 8 MHz
128KB - 640KB RAM
Built-in enhanced CGA (supports 640x400x2)
olivetti_m24/olivetti_m24_version_1.43_low.bin
olivetti_m24/olivetti_m24_version_1.43_high.bin
1986Amstrad PC1512 [5]
8086 at 8 MHz
512KB - 640KB RAM
Enhanced CGA (supports 640x200x16)
Custom mouse port
pc1512/40043.v1
pc1512/40044.v2
pc1512/40078.ic127
1987Amstrad PC1640 [5]
8086 at 8 MHz
640KB RAM
Built-in Paradise EGA
Custom mouse port
pc1640/40043.v3
pc1640/40044.v3
pc1640/40100
1987Toshiba T1200 [1] [5]
8086 at 9.54 MHz
1MB - 2MB RAM
CGA on built-in LCD
t1200/t1200_019e.ic15.bin
t1200/t1000font.rom
1988Amstrad PPC512/640 [5]
8086 at 8 MHz
512KB - 640KB RAM
Built-in CGA w/ plasma display
ppc512/40107.v2
ppc512/40108.v2
ppc512/40109.bin
1988Sinclair PC200/Amstrad PC20 [5]
8086 at 8 MHz
512KB - 640KB RAM
Built-in CGA (supports TV-out 50hz PAL)
pc200/pc20v2.0
pc200/pc20v2.1
pc200/40109.bin
1988VTech Laser XT3
8086 at 10 MHz
512KB - 1152KB RAM
lxt3/27c64d.bin
1989Amstrad PC2086 [5]
8086 at 8 MHz
640KB RAM
Built-in VGA
pc2086/40179.ic129
pc2086/40180.ic132
pc2086/40186.ic171
1989Tandy 1000SL/2 [5]
8086 at 9.54 MHz
512KB - 768KB RAM
Built-in 16 colour graphics
4 voice sound
tandy1000sl2/8079047.hu1
tandy1000sl2/8079048.hu2
1990Amstrad PC3086 [5]
8086 at 8 MHz
640KB RAM
Built-in VGA
pc3086/fc00.bin
pc3086/c000.bin
1991Amstrad PC5086
8086 at 8 MHz
640KB RAM
pc5086/sys_rom.bin
+

286 based

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReleaseMachineROM file needed
(within ./roms/ folder)
1984IBM AT
286 at 6 or 8 MHz
256KB - 16MB RAM
ibmat/at111585.0
ibmat/at111585.1
1986Compaq Portable II
286 at 8 MHz
256KB - 15MB RAM
compaq_pii/109739-001.rom
compaq_pii/109740-001.rom
1986IBM XT Model 286
286 at 6 MHz
256KB - 16MB RAM
ibmxt286/BIOS_5162_21APR86_U34_78X7460_27256.BIN
ibmxt286/BIOS_5162_21APR86_U35_78X7461_27256.BIN
1986Toshiba T3100e [1] [5]
286 at 12 MHz
1MB - 5MB RAM
CGA on gas-plasma display
t3100e/t3100e_font.bin
t3100e/t3100e.rom
1987IBM PS/2 Model 50 [5]
286 at 10 MHz
1MB - 16MB RAM
Built-in VGA
MCA bus
i8550021/90x7420.zm13
i8550021/90x7423.zm14
i8550021/90x7426.zm16
i8550021/90x7429.zm18
1988Bull Micral 45
286 at 12 MHz
1MB - 6MB RAM
bull_micral_45/even.fil
bull_micral_45/odd.fil
1988Commodore PC30-III
286 at 12 MHz
512KB - 16MB RAM
cmdpc30/commodore pc 30 iii even.bin
cmdpc30/commodore pc 30 iii odd.bin
1988IBM PS/2 Model 30-286
286 at 10 MHz
1MB - 16MB RAM
Built-in VGA
MCA bus
ibmps2_m30_286/33f5381a.bin
1989Epson PC AX
286
256KB - 16MB RAM
epson_pcax/EVAX
epson_pcax/ODAX
1989Epson PC AX2e
286 at 12 MHz
256KB - 16MB RAM
epson_pcax2e/EVAX
epson_pcax2e/ODAX
1990AMI 286 clone
286 at 8+ MHz
512KB - 16MB RAM
ami286/amic206.bin
1990Award 286 clone
286 at 8+ MHz
512KB - 16MB RAM
award286/award.bin
1990Dell System 200
286 at 12 MHz
640KB - 16MB RAM
dells200/dell0.bin
dells200/dell1.bin
1990IBM PS/1 Model 2011 [5]
286 at 10 MHz
512KB - 16MB RAM
Built-in VGA
DOS 4.01 + GUI menu system in ROM
ibmps1/f80000.bin
?Goldstar GDC-212M
286 at 12 MHz
512KB - 4MB RAM
gdc212m/gdc212m_72h.bin
?GW-286CT GEAR
286 at 8+ MHz
512KB - 16MB RAM
gw286ct/2ctc001.bin
?Hyundai Super-286TR
286 at 12 MHz
1MB - 4MB RAM
super286tr/award.bin
?Samsung SPC-4200P
286 at 12 MHz
512KB - 2MB RAM
spc4200p/u8.01
?Samsung SPC-4216P
286 at 12 MHz
1MB - 5MB RAM
spc4216p/phoenix.bin
   or
spc4216p/7101.u8
spc4216p/ac64.u10
?Samsung SPC-4620P
286 at 12 MHz
1MB - 5MB RAM
Built-in Korean ATI-28800
spc4620p/31005h.u8
spc4620p/31005h.u10
spc4620p/svb6120a_font.rom
spc4620p/31005h.u8
spc4620p/31005h.u10
?Tulip AT Compact
286
640KB - 16MB RAM
tulip_tc7/tc7be.bin
tulip_tc7/tc7bo.bin
+

386 based

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReleaseMachineROM file needed
(within ./roms/ folder)
1987IBM PS/2 Model 80 [5]
386DX at 20 MHz
1MB - 12MB RAM
Built-in VGA
MCA bus
i8580111/15f6637.bin
i8580111/15f6639.bin
1988ECS 386/32
386DX at 20 MHz
1MB - 16MB RAM
ecs386_32/386_32_even.bin
ecs386_32/386_32_odd.bin
1989IBM PS/2 Model 70 (type 3) [5]
386DX at 25 MHz
2MB - 16MB RAM
Built-in VGA
MCA bus
ibmps2_m70_type3/70-a_even.bin
ibmps2_m70_type3/70-a_odd.bin
1989Compaq Deskpro 386
386DX at 20 MHz
1MB - 15MB RAM
deskpro386/109592-005.u11.bin
deskpro386/109591-005.u13.bin
1989Epson PC AX3
386SX at 16 MHz
256KB - 16MB RAM
epson_pcax3/EVAX3
epson_pcax3/ODAX3
1989IBM PS/2 Model 55SX
386SX at 16 MHz
1MB - 8MB RAM
Built-in VGA
MCA bus
i8555081/33f8146.zm41
i8555081/33f8145.zm40
1990DTK 386SX clone
386SX
512KB - 16MB RAM
dtk386/3cto001.bin
1990IBM PS/1 Model 2121 [5]
386SX at 20 MHz
1MB - 16MB RAM
Built-in VGA
ibmps1_2121/fc0000.bin
1990Samsung SPC-6000A
386DX
1MB - 32 MB RAM
spc6000a/3c80.u27
spc6000a/9f80.u26
1992Acermate 386SX/25N [5]
386SX at 25 MHz
2MB - 16MB RAM
Built-in Oak SVGA
acer386/acer386.bin
acer386/oti067.bin
1992Amstrad MegaPC [2] [5]
386SX at 25 MHz
1MB - 16MB RAM
Built-in VGA
megapc/41651-bios lo.u18
megapc/211253-bios hi.u19
1992Commodore SL386SX-25 [5]
386SX at 25 MHz
1MB - 16MB RAM
Built-in AVGA2
cbm_sl386sx25/f000.bin
cbm_sl386sx25/c000.bin
1992Packard Bell Legend 300SX
386SX at 16 MHz
1MB - 16MB RAM
pb_l300sx/pb_l300sx.bin
1992Samsung SPC-6033P
386SX at 33 MHz
2MB - 12 MB RAM
spc6033p/phoenix.bin
spc6033p/svb6120a_font.rom
1994AMI 386DX clone
386DX at 40 MHz
1MB - 32MB RAM
ami386dx/opt495sx.ami
1994AMI 386SX clone
386SX at 25 MHz
1MB - 16MB RAM
ami386/ami386.bin
1994MR 386DX clone
This is a generic 386DX clone with an MR BIOS
mr386dx/opt495sx.mr
?KMX-C-02
386SX
512KB - 16MB RAM
kmxc02/3ctm005.bin
+

486 based

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReleaseMachine
(+ addl. hardware)
CPU(s) SupportedROM file needed
(within ./roms/ folder)
1990IBM PS/2 Model 70 (type 4) [3]
2MB - 16MB RAM
Built-in VGA
MCA bus
486DX at 25 MHzibmps2_m70_type3/70-a_even.bin
ibmps2_m70_type3/70-a_odd.bin
1993AMI 486 clone
1MB - 32MB RAM
486 at 16-66 MHzami486/ami486.bin
1993Elonex PC-425X [5]
1MB - 256MB RAM
Built-in Trident TGUI9440CXi
486SX at 25 MHzelx_pc425x/elx_pc425x.bin
   or
elx_pc425x/elx_pc425x_bios.bin
elx_pc425x/elx_pc425x_vbios.bin
1993IBM PS/1 Model 2133 (EMEA 451)
2MB - 64MB RAM
Built-in Cirrus Logic GD5426
486SX at 25 MHzibmps1_2133/PS1_2133_52G2974_ROM.bin
1993Packard Bell PB410A [5]
1MB - 64MB RAM
Built-in HT-216 video
486 at 25-120 MHz
Am5x86 at 133-160 MHz
Cx5x86 at 100-133 MHz
Pentium Overdrive at 63-83 MHz
pb410a/PB410A.080337.4ABF.U25.bin
1994AMI WinBIOS 486 clone
1MB - 32MB RAM
486 at 16-66 MHzwin486/ali1429g.amw
1995Award SiS 496/497
1MB - 64MB RAM
486 at 16-120 MHz
Am5x86 at 133-160 MHz
Cx5x86 at 100-133 MHz
Pentium Overdrive at 63-83 MHz
sis496/sis496-1.awa
+

Pentium based

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ReleaseMachine
(+ addl. hardware)
CPU(s) SupportedROM file needed
(within ./roms/ folder)
1994Intel Premiere/PCI (Batman's Revenge)
1MB - 128MB RAM
Pentium at 60-66 MHz
Pentium Overdrive at 120-133 MHz
revenge/1009af2_.bi0
revenge/1009af2_.bi1
1995Intel Advanced/EV (Endeavor) [4]
1MB - 128MB RAM
Pentium at 75-133 MHz
Pentium Overdrive at 125-200 MHz
endeavor/1006cb0_.bi0
endeavor/1006cb0_.bi1
1995Intel Advanced/ZP (Zappa)
1MB - 128MB RAM
Pentium at 75-133 MHz
Pentium Overdrive at 125-200 MHz
zappa/1006bs0_.bio
zappa/1006bs0_.bi1
1995Packard Bell PB520R (Robin LC) [5]
1MB - 128MB RAM
Built-in Cirrus Logic GD-5434
Pentium at 60-66 MHz
Pentium Overdrive at 120-133 MHz
pb520r/1009bc0r.bio
pb520r/1009bc0r.bi1
pb520r/gd5434.bin
1995Packard Bell PB570 (Hillary) [5]
1MB - 128MB RAM
Built-in Cirrus Logic GD-5430
Pentium at 75-133 MHz
Pentium Overdrive at 125-200 MHz
pb570/1007by0r.bio
pb570/1007by0r.bi1
pb570/gd5430.bin
1996ASUS P/I-P55TVP4
1MB - 128MB RAM
Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT Winchip 2 at 200-240 MHz
IDT Winchip 2A at 200-233 MHz
AMD K6 at 166-300 MHz
AMD K6-2 (AFR-66) at 233-300 MHz
p55tvp4/tv5i0204.awd
1996ASUS P/I-P55T2P4
1MB - 512MB RAM
Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT Winchip 2 at 200-240 MHz
IDT Winchip 2A at 200-233 MHz
AMD K6 at 166-300 MHz
AMD K6-2 (AFR-66) at 233-300 MHz
p55t2p4/0207_j2.bin
1996Award 430VX PCI
1MB - 128MB RAM
Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT Winchip 2 at 200-240 MHz
IDT Winchip 2A at 200-233 MHz
AMD K6 at 166-300 MHz
AMD K6-2 (AFR-66) at 233-300 MHz
430vx/55xwuq0e.bin
1996Itautec Infoway Multimidia
8MB - 128MB RAM
Pentium at 75-133 MHz
Pentium Overdrive at 125-200 MHz
infowaym/1006bs0_.bio
infowaym/1006bs0_.bi1
1997Epox P55-VA
1MB - 128MB RAM
Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT Winchip 2 at 200-240 MHz
IDT Winchip 2A at 200-233 MHz
AMD K6 at 166-300 MHz
AMD K6-2 (AFR-66) at 233-300 MHz
p55va/va021297.bin
+

Super Socket 7 based

+ + + + + + + + + + + + + + + + + +
ReleaseMachine
(+ addl. hardware)
CPU(s) SupportedROM file needed
(within ./roms/ folder)
1998FIC VA-503+
1MB - 512MB RAM
AMD K6 at 166-300 MHz
AMD K6-2 at 233-550 MHz
AMD K6-2+ at 450-550 MHz
AMD K6-III at 400-450 MHz
AMD K6-III+ at 400-500 MHz
Pentium at 75-200 MHz
Pentium MMX at 166-233 MHz
Mobile Pentium MMX at 120-300 MHz
Cyrix 6x86 at PR90(80 MHz)-PR200(200 MHz)
Cyrix 6x86MX/MII at PR166(133 MHz)-PR400(285 MHz)
IDT WinChip at 75-240 MHz
IDT WinChip2 at 200-250 MHz
IDT Winchip 2A at PR200(200 MHz)-PR300(250 MHz)
fic_va503p/je4333.bin
+

Socket 8 based

+ + + + + + + + + + + + + + + + + +
ReleaseMachine
(+ addl. hardware)
CPU(s) SupportedROM file needed
(within ./roms/ folder)
1996Intel VS440FX
8MB - 256 MB RAM
Pentium Pro at 150-200 MHz
Pentium II Overdrive at 300-333 MHz
vs440fx/1018CS1_.BI1
vs440fx/1018CS1_.BI2
vs440fx/1018CS1_.BI3
vs440fx/1018CS1_.BIO
vs440fx/1018CS1_.RCV
+

Slot 1 based

+ + + + + + + + + + + + + + + + + +
ReleaseMachine
(+ addl. hardware)
CPU(s) SupportedROM file needed
(within ./roms/ folder)
1998Gigabyte GA-686BX
8MB - 512MB RAM
Pentium II at 233-450 MHz
Celeron at 266-533 MHz
Cyrix IIIat 500 MHz
ga686bx/6BX.F2a
+

Additional Notes

+

[1] Toshiba Button Mapping: PCem maps [Fn] to right-Ctrl and right-Alt. The following functions are supported: Key Combo | Function ---|--- Fn + Num Lock | toggle numpad Fn + Home | Internal LCD display Fn + Page Down | Turbo on Fn + Right | Toggle LCD font Fn + End | External CRT display Fn + SysRQ | Toggle window

+

[2] Amstrad MegaPC (386SX): The original machine had a built-in Sega MegaDrive. This is not emulated in PCem.

+

[3] IBM PS/2 Model 70 (type 4) (486DX): PCem's FPU emulation is not bit accurate and can not pass IBM's floating point tests. As a result, this machine will always print 12903 and 162 errors on bootup. These can be ignored - F1 will boot the machine.

+

[4] Intel Advanced/EV (Endeavor) (Pentium): The real board has a Sound Blaster 16 onboard and optionally an S3 Trio64V+. Neither are emulated as onboard devices.

+

[5] Some systems have fixed graphics adapters:
** = Can use external video card.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SystemGraphicsAddl. Info**
Amstrad MegaPCParadise 90C11A development of the PVGA1 with 512KB VRAM
Acer 386SX/25NOak OTI-067Another 512KB SVGA clone
Amstrad PC1512CGAHas a new mode (640x200x16)X
Amstrad PC1640Paradise EGA 
Amstrad PC2086/PC3086Paradise PVGA1An early SVGA clone with 256KB VRAM
Amstrad PPC512/640CGA/MDAOutputs to 640x200 plasma display
Commodore SL386SX-25AVGA2256KB - 512KB VRAMX
Elonex PC-425XTrident TGUI9400CXi512KB VRAMX
IBM PCjrCGAHas various new modes:
160x200 x 16
320x200 x 16
640x200 x 4
X
IBM PS/1 Model 2011Stock VGA256KB VRAMX
IBM PS/1 Model 2121Basic (and unknown) SVGA256KB VRAMX
IBM PS/2 machinesStock VGA256KB VRAMX
Olivetti M24 [6]CGAHas double-res text modes + 640x400 modeX
Packard Bell PB410AHeadland HT-216 
Packard Bell PB520RCirrus Logic GD-5434 
Packard Bell PB570Cirrus Logic GD-5430 
Sinclair PC200CGACan output to TV @ 50hz (UK)
Tandy 1000Clone of PCjr videoWidely supported in 80s gamesX
Tandy 1000 SL/2Improved Tandy 1000Has support for 640x200x16X
Toshiba T-seriesCGAOutputs to built-in LCD or plasma displayX
+

[6] Olivetti M24 (display): 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.

+
+ +

Graphics Cards

+

Basic cards

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HardwareAddl. InfoROM file needed
(within ./roms/ folder)
MDA (1981)80x25 monochrome text(none)
CGA (1981)40x25 and 80x25 text
320x200 in 4 colours
620x200 in 2 colours
Supports composite output for ~16 colours.
(none)
Hercules (1982)80x25 monochrome text
720x348 in monochrome
(none)
Plantronics ColorPlusAn enhanced CGA board with support for 320x200x16 and 640x200x4(none)
Wyse WY-700A CGA-compatible board with support for a 1280x800 mode(none)
MDSI GeniusMono portrait board with support for a 728x1008 mode8x12.bin
IBM EGA (1984)Text up to 80x43
Graphics up to 640x350 in 16 colours
ibm_6277356_ega_card_u44_27128.bin
ATI EGA Wonder 800+An enhanced EGA-compatible board with support for up to 800x600 in 16 coloursATI EGA Wonder 800+ N1.00.BIN
Hercules InColorAn enhanced Hercules with a custom 720x350 16 colour mode(none)
+

Unaccelerated (S)VGA cards

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HardwareAddl. InfoROM file needed
(within ./roms/ folder)
ATI Korean VGAATI-28800 based.
512KB VRAM
Supports up to 8-bit colour
Korean font support
atikorvga.bin
ati_ksc5601.rom
ATI VGA Edge-16ATI-18800 based
512KB VRAM
Supports up to 8-bit colour
vgaedge16.vbi
ATI VGA ChargerATI-28800 based
512KB VRAM
Supports up to 8-bit colour
bios.bin
AVGA2Also known as Cirrus Logic GD5402
256KB - 512KB VRAM
Supports up to 8-bit colour
avga2vram.vbi
IBM VGA (1987)256KB VRAM
Text up to 80x50
Graphics up to 320x200 in 256 colours or 640x480 in 16 colours
ibm_vga.bin
Kasan Hangulmadang-16ET4000AX based
1MB VRAM
Supports up to 8-bit colour
Korean font support
et4000_kasan16.bin
kasan_ksc5601.rom
OAK OTI-037C256KB VRAM
Supports up to 8-bit colour
oti037/bios.bin
OAK OTI-067256KB - 512KB VRAM
Supports up to 8-bit colour
oti067/bios.bin
Olivetti GO481 (Paradise PVGA1A)256KB VRAM
Supports up to 8-bit colour
oli_go481_lo.bin
oli_go481_hi.bin
Trident 8900D SVGA256KB - 1MB VRAM
Supports up to 24-bit colour
trident.bin
Trident 9000B SVGA512KB VRAM
Supports up to 8-bit colour
tvga9000b/BIOS.BIN
Trident TGUI9400CXi1MB - 2MB VRAM
Supports up to 24-bit colour
9440.vbi
Trigem Korean VGAET4000AX based
1MB VRAM
Supports up to 8-bit colour
Korean font support
tgkorvga.bin
tg_ksc5601.rom
Tseng ET4000AX SVGA1MB VRAM
Supports up to 8-bit colour
et4000.bin
+

2D Accelerated SVGA cards

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HardwareAddl. InfoROM file needed
(within ./roms/ folder)
ATI Graphics Pro TurboMach64GX based
1MB - 4MB VRAM
mach64gx/bios.bin
ATI Video XpressionMach64VT2 based
2MB - 4MB VRAM
Has video acceleration
atimach64vt2pci.bin
Cirrus Logic GD-54281MB - 2MB VRAMMachspeed_VGA_GUI_2100_VLB.vbi
Cirrus Logic GD-54291MB - 2MB VRAM5429.vbi
Cirrus Logic GD-54301MB - 2MB VRAMgd5430/pci.bin
Cirrus Logic GD-5434 [1]2MB - 4MB VRAMgd5434.bin
Diamond Stealth 32 SVGAET4000/W32p based
1MB - 2MB VRAM
et4000w32.bin
IBM 1MB SVGA Adapter/ACirrus Logic GD5428 based
1 MB VRAM
Only supported on PS/2 models
SVGA141.ROM
Number Nine 9FXS3 Trio64 based
1MB - 2MB VRAM
s3_764.bin
Paradise Bahamas 64S3 Vision864 based
1MB - 4MB VRAM
bahamas64.bin
Phoenix S3 Trio32S3 Trio32 based
512KB - 2MB VRAM
86c732p.bin
Phoenix S3 Trio64S3 Trio64 based
1MB - 4MB VRAM
86c764x1.bin
Trident TGUI94401MB - 2MB VRAM9440.vbi
+

3D Accelerated SVGA cards

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HardwareAddl. InfoROM file needed
(within ./roms/ folder)
3DFX Voodoo Banshee (reference)Voodoo Banshee based
8MB - 16MB VRAM
pci_sg.rom
3DFX Voodoo 3 2000Voodoo 3 based
16MB VRAM
voodoo3_2000/2k11sd.rom
3DFX Voodoo 3 3000Voodoo 3 based
16MB VRAM
voodoo3_3000/3k12sd.rom
Creative Labs 3D Blaster BansheeVoodoo Banshee based
16MB VRAM
blasterpci.rom
Diamond Stealth 3D 2000 [2]S3 ViRGE/325 based
2MB - 4MB VRAM
s3virge.bin
S3 ViRGE/DX [3]S3 ViRGE/DX based
2MB - 4MB VRAM
86c375_1.bin
+

3D only cards

+ + + + + + + + + + + + + + + + + + + + + +
HardwareAddl. Info
3DFX Voodoo Graphics [4]3D accelerator. Widely supported in late 90s games.
Obsidian SB50 [5]Voodoo with 2 TMUs
3DFX Voodoo 2 [6]Improved Voodoo Graphics
Higher clocks
2 TMUs
Triangle setup, etc.
+

Additional Notes

+

[1] Cirrus Logic GD-5434: Real chip also supports 1MB configurations, however this is not currently supported in PCem.

+

[2] Diamond Stealth 3D 2000: 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.

+

[3] S3 ViRGE/DX: 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).

+

[4] 3DFX Voodoo Graphics: PCem emulates this in software. The emulation is a lot faster than in v10 (thanks to a new dynamic recompiler) and should be capable of hitting Voodoo 1 performance on most machines when two render threads are used. As before, the emulated CPU is the bottleneck for most games.

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.

+

[5] Obsidian SB50: Drivers for this are a bit limited - the official drivers don't support 2 TMUs in Direct3D.

+

[6] 3DFX Voodoo 2: PCem can emulate both 8 and 12 MB configurations. It can also emulate 6 and 10 MB configurations (with 2MB framebuffer memory), which were never sold into the PC market but do exist for arcade systems.

+
+ +

Sound Cards

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HardwareNotes
PC speakerThe standard beeper on all PCs. Supports samples/RealSound.
Tandy PSGThe 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). PCem emulates the differences between the SN76496 (PCjr and Tandy 1000), and the NCR8496 (currently assigned to the Tandy 1000HX). Maniac Mansion and Zak McKraken will only sound correct on the latter.
Tandy PSSJUsed on the Tandy 1000SL/2, this clones the NCR8496, adding an addition frequency divider (did any software actually use this?) and an 8-bit DAC.
PS/1 audio cardAn SN76496 clone plus an 8-bit DAC. The SN76496 isn't at the same address as PCjr/Tandy, so most software doesn't support it.
GameblasterThe 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!
AdlibHas a Yamaha YM3812, giving 9 voices of 2 op FM, or 6 voices plus a rhythm section. PCem uses the DOSBox dbopl emulator.
Adlib GoldOPL3 with YM318Z 12-bit digital section. Possibly some bugs (not a lot of software to test). The surround module is now emulated.
Sound Blaster [1]See linked note for more details.
Gravis Ultrasound32 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 System16-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)
Aztech Sound Galaxy Pro 16 AB (Washington)SB compatible + WSS compatible
Innovation SSI-2001SID6581. Emulated using resid-fp. Board is fixed to port 280.
Ensoniq AudioPCI (ES1371)
Sound Blaster PCI 128
Basic PCI sound card. Emulates Sound Blaster in software.
+

Additional Notes

+

[1] 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 cards 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.

+
+ +

HDD Controller Cards

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Int.HardwareNotesROM file needed
(within ./roms/ folder)
MFMFixed Disk Adapter (Xebec)MFM controller originally included in the IBM XT. This controller only supports HD types 0, 2, 13, and 16.ibm_xebec_62x0822_1985.bin
MFMDTC 5150X8-bit MFM controller.
To configure drive types, run DEBUG.EXE and enter g=c800:5.
dtc_cxd21a.bin
MFMAT Fixed Disk AdapterMFM controller originally included in the IBM AT. Supported by all AT-compatible BIOSes.(none)
ESDIWestern Digital WD1007V-SE116-bit ESDI controller62-000279-061.bin
ESDIIBM ESDI Fixed Disk ControllerMCA ESDI controller. Only supported on PS/2 models.90x8969.bin
90x8970.bin
IDEStandard IDEStandard IDE controller. Supported by all AT-compatible BIOSes. Use this if in any doubt!(none)
IDEXTIDE8-bit IDE controller. The BIOS is available here.
v2.0.0 beta 1 is the version I've mostly tested. v2.0.0 beta 3 is known to have some issues.
ide_xt.bin
IDEXTIDE (AT)16-bit IDE controller.ide_at.bin
IDEXTIDE (PS/1)IDE controller for the PS/1 model 2033. For this machine you will need BIOS version 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.ide_at_1_1_5.bin
SCSILongshine LCS-6821N8-bit SCSI controller.Longshine LCS-6821N - BIOS version 1.04.bin
SCSIRancho RT1000B8-bit SCSI controller.Rancho_RT1000_RTBios_version_8.10R.bin
SCSITrantor T130B8-bit SCSI controller.trantor_t130b_bios_v2.14.bin
SCSIIBM SCSI Adapter with CacheMCA SCSI controller. Only supported on PS/2 models.92F2244.U68
92F2245.U69
SCSIAdaptec AHA-1542C16-bit SCSI controller.adaptec_aha1542c_bios_534201-00.bin
SCSIBusLogic BT-545S16-bit SCSI controller.BusLogic_BT-545S_U15_27128_5002026-4.50.bin
+
+ +

Misc Cards

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HardwareNote
Serial mouseA Microsoft compatible serial mouse on COM1. Compatible drivers are all over the place for this.
M24 mouseI haven't seen a DOS mouse driver for this yet but the regular scancode mode works as does the Windows 1.x driver.
PC1512 mouseThe PC1512's perculiar quadrature mouse. You need Amstrad's actual driver for this one.
PS/2 mouseA standard 2 button PS/2 mouse. As with serial, compatible drivers are common.
Microsoft PS/2 IntellimouseA PS/2 mouse with mouse wheel.
ATAPI CD-ROMWorks with OAKCDROM.SYS, VDD-IDE.SYS, and the internal drivers of every OS I've tried.
+ + diff --git a/readme.txt b/readme.txt deleted file mode 100644 index 95b22e3..0000000 --- a/readme.txt +++ /dev/null @@ -1,894 +0,0 @@ -PCem v12 - -PCem is licensed under the GPL, see COPYING for more details. - -Changes since v11: - -- New machines added - AMI 386DX, MR 386DX -- New graphics cards - Plantronics ColorPlus, Wyse WY-700, Obsidian SB50, Voodoo 2 -- CPU optimisations - up to 50% speedup seen -- 3DFX optimisations -- Improved joystick emulation - analogue joystick up to 8 buttons, CH Flightstick Pro, ThrustMaster FCS, SideWinder pad(s) -- Mouse can be selected between serial, PS/2, and IntelliMouse -- Basic 286/386 prefetch emulation - 286 & 386 performance much closer to real systems -- Improved CGA/PCjr/Tandy composite emulation -- Various bug fixes - - -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 (1984) -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 - - -Tandy 1000HX (1987) -A Tandy 1000 with a faster 7.16 MHz 8088, and DOS in ROM. - -ROM files needed: - -tandy1000hx\v020000.u12 - - -Tandy 1000SL/2 (1989) -An enhanced Tandy 1000 with a 9.54 MHz 8086, and enhanced graphics and sound. - -ROM files needed: - -tandy1000sl2\8079047.hu1 -tandy1000sl2\8079048.hu2 - - -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. - -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 - - -Award 286 clone (1990) -This is a generic 286 clone with an Award BIOS. - -ROM files needed: - -award286\award.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 - - -IBM PS/1 Model 2121 (1990) -This is a 386SX with integrated VGA. - -ROM files needed: - -ibmps1_2121\fc0000.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 - - -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 386SX clone (1994) -This is a generic 386SX clone with an AMI BIOS. - -ROM files needed: - -ami386\ami386.bin - - -MR 386DX clone (1994) -This is a generic 386DX clone with an MR BIOS. - -ROM files needed: - -mr386dx\opt495sx.mr - - -AMI 386DX clone (1994) -This is a generic 386DX clone with an AMI BIOS. This is the only currently emulated 386DX system -to support an external cache. - -ROM files needed: - -ami386dx\opt495sx.ami - - -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. - -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. - -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. - - -Plantronics ColorPlus -An enhanced CGA board, with support for 320x200x16 and 640x200x4. - - -Wyse WY-700 -A CGA-compatible board, with support for a 1280x800 mode - - -IBM EGA -The original 1984 IBM EGA card, with 256k VRAM. - -ROM files needed: -ibm_6277356_ega_card_u44_27128.bin - - -Hercules InColor -An enhanced Hercules with a custom 720x350 16 colour mode. - - -IBM VGA -The original VGA card. - -ROM files needed: -ibm_vga.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. - -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 is a lot faster than in v10 (thanks to a new -dynamic recompiler) and should be capable of hitting Voodoo 1 performance on most machines -when two render threads are used. As before, the emulated CPU is the bottleneck for most games. - -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. - - -Obsidian SB50 -Voodoo Graphics with 2 TMUs. Drivers for this are a bit limited - the official drivers don't -support 2 TMUs in Direct3D. - - -Voodoo 2 -Improved Voodoo Graphics - higher clocks, 2 TMUs, triangle setup etc. - -PCem can emulate both 8 and 12 MB configurations. It can also emulate 6 and 10 MB configurations -(with 2MB framebuffer memory), which were never sold into the PC market but do exist for arcade -systems. - - -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. - -Tandy 1000 SL/2 -Improvement of Tandy 1000, with support for 640x200x16. - -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. - -IBM PS/1 Model 2121 -Basic (and unknown) SVGA 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). -v11 now emulates the differences between the SN76496 (PCjr and Tandy 1000), and the NCR8496 -(currently assigned to the Tandy 1000HX). Maniac Mansion and Zak McKraken will only sound -correct on the latter. - -Tandy PSSJ -Used on the Tandy 1000SL/2, this clones the NCR8496, adding an addition frequency divider (did any -software actually use this?) and an 8-bit DAC. - -PS/1 audio card -An SN76496 clone plus an 8-bit DAC. The SN76496 isn't at the same address as PCjr/Tandy, so most -software doesn't support it. - -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). -The surround module is now emulated. - -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 standard 2 button PS/2 mouse. As with serial, compatible drivers are common. - -Microsoft PS/2 Intellimouse -A PS/2 mouse with mouse wheel. - -ATAPI CD-ROM -Works with OAKCDROM.SYS, VDD-IDE.SYS, and the internal drivers of every OS I've tried. - - -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 1.25 -MS-DOS 2.11 -MS-DOS 3.31 -Compaq DOS 3.31 -MS-DOS 5.0 -MS-DOS 6.22 - -DR-DOS 6.0 - -Windows 1.03 -Windows 2.03 -Windows/386 2.11 -Windows 3.0 -Windows 3.1 -Windows for Workgroups 3.11 -Windows 95 -Windows 95 OSR 2 -Windows 98 -Windows 98 SE -Windows ME - -Windows NT 3.51 -Windows NT 4 -Windows 2000 -Windows XP - -OS/2 v1.1 -OS/2 v1.2 -OS/2 v1.3 -OS/2 v2.1 -OS/2 Warp 3 -OS/2 Warp 4 - -GEM 3.11 - -Corel Linux 1.2 -Ubuntu 10.04 (very slow, does not support serial mouse) - -BeOS 5.0 Professional - -Adobe Photoshop 3.0.4 -CorelDRAW! 2.5 (OS/2) -CorelDRAW! 5.0 -FastTracker v2.08 -Lotus 1-2-3 2.1 (OS/2) -Microsoft Excel 3.0 (OS/2) -Microsoft Word 1.1 (OS/2) -Microsoft Word for Windows 6.1 -Microsoft Works for Windows 3.0 -Microsoft Visual Basic 3.0 -Microsoft Visual C++ 1.0 -Microsoft Visual C++ 6.0 -StarOffice 3.1 (OS/2) - -Age of Empires -Alien vs Predator (3DFX) -Blake Stone -Breakneck (3DFX) -Caesar III -Civilization -Civilization II -Colin McRae Rally (3DFX) -Colonization -Command & Conquer : Red Alert -Command & Conquer : Red Alert 2 -Commander Keen : Goodbye Galaxy -Commander Keen : Invasion of the Vorticons -Croc (3DFX) -Curse of Monkey Island -Dawn Patrol -Deus Ex (3DFX, slow) -Discworld II -Doom -Doom II -Duke Nukem 3D -Dune -Dune II -Epic Pinball -Grand Theft Auto (3DFX) -GTA 2 (3DFX) -Half-Life (3DFX) -Heretic -House of the Dead 2 (3DFX) -Icon -Incoming (3DFX) -Indiana Jones and the Last Crusade -Jetpack -King's Quest (PCjr, Tandy) -King's Quest II (Tandy) -Klotz -Lemmings -Lemmings 2 -Little Big Adventure 2 -Lotus III -Maniac Mansion -Microsoft Arcade -Monkey Island 2 -Mystic Towers -Need for Speed II SE (3DFX) -Need for Speed III (3DFX) -Network Q RAC Rally -Oddworld : Abe's Oddysee -Overlord -Populous : The Beginning (3DFX) -Pro Pinball : Big Race USA -Pro Pinball : The Web -Psycho Pinball -Resident Evil 2 (3DFX) -Rollercoaster Tycoon -Quake (3DFX) -Quake II (3DFX) -Quake III Arena (3DFX) -Scorched Earth -Screamer -Screamer Rally (not 3DFX) -Secret of Monkey Island -SimCity (DOS, OS/2) -SimCity 2000 (DOs, Windows, OS/2) -SimCity 3000 -Spear of Destiny -Star Goose -Stargunner -Stunt Island -System Shock -System Shock 2 (3DFX) -Terminal Velocity -The Humans -Theme Hospital -Tomb Raider (3DFX) -Tomb Raider III (3DFX) -Tony Hawk's Pro Skater 2 (3DFX) -Total Annihilation -Transport Tycoon -Turok (3DFX) -Turok 2 (3DFX) -Tyrian -UFO : Enemy Unknown -Unreal (3DFX) -Unreal Tournament (3DFX) -Wacky Wheels -Wing Commander -Wolfenstein 3D -World Cup 98 (3DFX) -Worms -Worms 2 -X-Com : Apocalypse -X-Com : Terror From The Deep -X-Wing -Zone 66 - -Complex - Cyboman 2 -EMF - Verses -Future Crew - Second Reality -Gazebo - Cyboman! -KFMF - Trip (3DFX) -Logic Design - Fashion -Orange - X14 -Renaissance - Amnesia -Skull - Putrefaction -Tran - Ambience (flickery with a host display at 60 Hz) -Tran - Timeless -Triton - Crystal Dream -Triton - Crystal Dream II (visual artifacts in titles) -Ultraforce - Vectdemo -Witan - Witan House - -BeebInC v0.99f -Fellow v0.33 -Kgen98 v0.4b -PacifiST v0.48 -SNES9x v0.96 -vMac v0.1.9.1 diff --git a/src/386.c b/src/386.c index 8a03cc4..fc9cb3b 100644 --- a/src/386.c +++ b/src/386.c @@ -2,7 +2,6 @@ #include #include #include "ibm.h" -#include "386.h" #include "x86.h" #include "x87.h" #include "mem.h" @@ -10,58 +9,18 @@ #include "fdc.h" #include "pic.h" #include "timer.h" +#include "nmi.h" #include "386_common.h" +#include "codegen.h" +#undef CPU_BLOCK_END #define CPU_BLOCK_END() -extern int codegen_flags_changed; - -extern int nmi_enable; - -int inscounts[256]; -uint32_t oldpc2; - -int trap; - - - -extern int cpl_override; - -int has_fpu; -extern int fpucount; -uint16_t rds; -uint16_t ea_rseg; - -int is486; -int cgate32; - - - -uint8_t romext[32768]; -uint8_t *ram,*rom; - -uint32_t rmdat32; -#define rmdat rmdat32 -#define fetchdat rmdat32 -uint32_t backupregs[16]; -extern int oddeven; -int inttype; - - -uint32_t oldcs2; -uint32_t oldecx; - -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 = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; if (cpu_rm == 4) { uint8_t sib = rmdat >> 8; @@ -88,8 +47,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat) else if ((sib & 6) == 4 && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } if (((sib >> 3) & 7) != 4) cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); @@ -102,8 +60,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat) if (cpu_rm == 5 && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } if (cpu_mod == 1) { @@ -134,8 +91,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; - if (!cpu_mod && cpu_rm == 6) + if (!cpu_mod && cpu_rm == 6) { cpu_state.eaaddr = getword(); } @@ -157,8 +113,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat) if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } cpu_state.eaaddr &= 0xFFFF; } @@ -181,19 +136,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat) #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 @@ -202,13 +145,6 @@ extern int dontprint; #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; @@ -216,73 +152,56 @@ void exec386(int cycs) int tempi; int cycdiff; int oldcyc; - int cycle_period = cycs / 2000; /*Use a 5us timing granularity*/ cycles+=cycs; // output=3; while (cycles>0) { + int cycle_period = (timer_target - (uint32_t)tsc) + 1; + + x86_was_reset = 0; cycdiff=0; oldcyc=cycles; - timer_start_period(cycles << TIMER_SHIFT); // pclog("%i %02X\n", ins, ram[8]); while (cycdiff < cycle_period) { - /* 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; - - oldcs=CS; + int ins_cycles = cycles; + cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; cpu_state.op32 = use32; -dontprint=0; - - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; cpu_state.ssegs = 0; fetchdat = fastreadl(cs + cpu_state.pc); if (!cpu_state.abrt) - { - trap = flags & T_FLAG; - opcode = fetchdat & 0xFF; + { + uint8_t opcode = fetchdat & 0xFF; fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; 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]); + 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\n",CS,cs,cpu_state.pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,cpu_state.flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask); } cpu_state.pc++; x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + if (x86_was_reset) + break; } - if (!use32) cpu_state.pc &= 0xffff; - if (cpu_state.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 = cpu_state.abrt; + tempi = cpu_state.abrt & ABRT_MASK; cpu_state.abrt = 0; x86_doabrt(tempi); if (cpu_state.abrt) { cpu_state.abrt = 0; - CS = oldcs; cpu_state.pc = cpu_state.oldpc; pclog("Double fault %i\n", ins); pmodeint(8, 0); @@ -295,34 +214,36 @@ dontprint=0; } } } - cycdiff=oldcyc-cycles; - if (trap) + if (cpu_state.smi_pending) + { + cpu_state.smi_pending = 0; + x86_smi_enter(); + } + else if (trap) { flags_rebuild(); // oldpc=pc; -// oldcs=CS; if (msw&1) { pmodeint(1,0); } else { - writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); } } - else if (nmi && nmi_enable) + else if (nmi && nmi_enable && nmi_mask) { cpu_state.oldpc = cpu_state.pc; - oldcs = CS; // pclog("NMI\n"); x86_int(2); nmi_enable = 0; @@ -332,7 +253,7 @@ dontprint=0; nmi = 0; } } - else if ((flags&I_FLAG) && pic_intpending) + else if ((cpu_state.flags & I_FLAG) && pic_intpending) { temp=picinterrupt(); if (temp!=0xFF) @@ -348,14 +269,13 @@ dontprint=0; } else { - writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); // if (temp==0x76) pclog("INT to %04X:%04X\n",CS,pc); @@ -367,6 +287,11 @@ dontprint=0; ins++; insc++; + ins_cycles -= cycles; + tsc += ins_cycles; + + cycdiff=oldcyc-cycles; + if (timetolive) { timetolive--; @@ -375,8 +300,7 @@ dontprint=0; } } - tsc += cycdiff; - - timer_end_period(cycles << TIMER_SHIFT); + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); } } diff --git a/src/386.h b/src/386.h deleted file mode 100644 index d78be84..0000000 --- a/src/386.h +++ /dev/null @@ -1,15 +0,0 @@ -extern void cpu_386_flags_extract(); -extern void cpu_386_flags_rebuild(); - -void pmodeint(int num, int soft); -void loadcscall(uint16_t seg); -void loadcsjmp(uint16_t seg, uint32_t oxpc); -void pmoderetf(int is32, uint16_t off); -void pmodeiret(int is32); -void x86_int_sw(int num); - -int divl(uint32_t val); -int idivl(int32_t val); - -int rep386(int fv); - diff --git a/src/386_common.c b/src/386_common.c new file mode 100644 index 0000000..4d0a761 --- /dev/null +++ b/src/386_common.c @@ -0,0 +1,252 @@ +#include "ibm.h" +#include "x86.h" +#include "386_common.h" +#include "x86_flags.h" +#include "codegen.h" + +x86seg gdt, ldt, idt, tr; + +uint32_t cr2, cr3, cr4; +uint32_t dr[8]; + +uint16_t sysenter_cs; +uint32_t sysenter_eip, sysenter_esp; + +uint32_t use32; +int stack32; +int optype; + +int trap; + +uint32_t rmdat; + +uint32_t *eal_r, *eal_w; + +int nmi_enable = 1; + +int cpl_override=0; + +int fpucount=0; + +uint16_t cpu_cur_status = 0; + +uint32_t pccache; +uint8_t *pccache2; + +void x86_int(int num) +{ + uint32_t addr; +// pclog("x86_int %02x %04x:%04x\n", num, CS,pc); + flags_rebuild(); + cpu_state.pc=cpu_state.oldpc; + if (msw&1) + { + pmodeint(num,0); + } + else + { + addr = (num << 2) + idt.base; + + if ((num << 2) + 3 > idt.limit) + { + if (idt.limit < 35) + { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); + pclog("Triple fault in real mode - reset\n"); + } + else + x86_int(8); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,cpu_state.flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + 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 + { + addr = (num << 2) + idt.base; + + if ((num << 2) + 3 > idt.limit) + { + x86_int(13); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,cpu_state.flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= timing_int_rm; + } + } + trap = 0; + CPU_BLOCK_END(); +} + +int x86_int_sw_rm(int num) +{ + uint32_t addr; + uint16_t new_pc, new_cs; + + flags_rebuild(); + cycles -= timing_int; + + addr = num << 2; + new_pc = readmemw(0, addr); + new_cs = readmemw(0, addr + 2); + + if (cpu_state.abrt) return 1; + + writememw(ss,((SP-2)&0xFFFF),cpu_state.flags); if (cpu_state.abrt) {pclog("abrt5\n"); return 1; } + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); if (cpu_state.abrt) {pclog("abrt6\n"); return 1; } + SP-=6; + + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags &= ~T_FLAG; + cpu_state.pc = new_pc; + loadcs(new_cs); + + cycles -= timing_int_rm; + trap = 0; + CPU_BLOCK_END(); + + return 0; +} + +void x86illegal() +{ +// pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode); + +// if (output) +// { +// dumpregs(); +// exit(-1); +// } + x86_int(6); +} + +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 (cpu_state.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 = readmembl(tr.base + t + (port >> 3)); +// d=readmemb(tr.base,t+(port>>3)); + cpl_override = 0; +// pclog("%02X %02X\n",d,d&(1<<(port&7))); + return d&(1<<(port&7)); +} + +#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(); +} diff --git a/src/386_common.h b/src/386_common.h index bbcfaa0..143984a 100644 --- a/src/386_common.h +++ b/src/386_common.h @@ -1,51 +1,61 @@ -extern uint16_t ea_rseg; +#ifndef _386_COMMON_H_ +#define _386_COMMON_H_ -#undef readmemb -#undef writememb +#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1)?readmembl((s)+(a)): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) ) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 1))?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)+(a)) & 3))?readmemll((s)+(a)):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (((s)+(a)) & 7))?readmemql((s)+(a)):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) - -#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 +#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1) writemembl((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)+(a)) & 1)) 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)+(a)) & 3)) 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)+(a)) & 7)) writememql((s)+(a),v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v int checkio(int port); -#define check_io_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ +#define check_io_perm(port) if (!IOPLp || (cpu_state.eflags&VM_FLAG)) \ { \ int tempi = checkio(port); \ if (cpu_state.abrt) return 1; \ if (tempi) \ { \ - x86gpf(NULL,0); \ + if (cpu_state.eflags & VM_FLAG) \ + x86gpf_expected(NULL,0); \ + else \ + x86gpf(NULL,0); \ return 1; \ } \ } -#define checkio_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ - { \ - tempi = checkio(port); \ - if (cpu_state.abrt) break; \ - if (tempi) \ - { \ - x86gpf(NULL,0); \ - break; \ - } \ - } +#define SEG_CHECK_READ(seg) \ + do \ + { \ + if ((seg)->base == 0xffffffff) \ + { \ + x86gpf("Segment can't read", 0);\ + return 1; \ + } \ + } while (0) + +#define SEG_CHECK_WRITE(seg) \ + do \ + { \ + if ((seg)->base == 0xffffffff) \ + { \ + x86gpf("Segment can't write", 0);\ + return 1; \ + } \ + } while (0) #define CHECK_READ(seg, low, high) \ - if ((low < (seg)->limit_low) || (high > (seg)->limit_high)) \ + if ((low < (seg)->limit_low) || (high > (seg)->limit_high) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && (((seg)->access & 10) == 8))) \ { \ x86gpf("Limit check", 0); \ return 1; \ } #define CHECK_WRITE(seg, low, high) \ - if ((low < (seg)->limit_low) || (high > (seg)->limit_high) || !((seg)->access & 2)) \ + if ((low < (seg)->limit_low) || (high > (seg)->limit_high) || !((seg)->access & 2) || ((msw & 1) && !(cpu_state.eflags & VM_FLAG) && ((seg)->access & 8))) \ { \ x86gpf("Limit check", 0); \ return 1; \ @@ -59,7 +69,7 @@ int checkio(int port); } -#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ +#define NOTRM if (!(msw & 1) || (cpu_state.eflags & VM_FLAG))\ { \ x86_int(6); \ return 1; \ @@ -88,8 +98,8 @@ static inline uint16_t fastreadw(uint32_t a) uint16_t val; if ((a&0xFFF)>0xFFE) { - val = readmemb(0, a); - val |= (readmemb(0, a + 1) << 8); + val = fastreadb(a); + val |= (fastreadb(a + 1) << 8); return val; } if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); @@ -119,13 +129,22 @@ static inline uint32_t fastreadl(uint32_t 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); + val = fastreadw(a); + val |= (fastreadw(a + 2) << 16); return val; } +static inline void *get_ram_ptr(uint32_t a) +{ + if ((a >> 12) == pccache) + return &pccache2[a]; + else + { + uint8_t *t = getpccache(a); + return &t[a]; + } +} + static inline uint8_t getbyte() { cpu_state.pc++; @@ -158,32 +177,30 @@ static inline uint8_t geteab() return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm&3].b.l; if (eal_r) return *(uint8_t *)eal_r; - return readmemb(easeg, cpu_state.eaaddr); + return readmemb(easeg,cpu_state.eaaddr); } static inline uint16_t geteaw() { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].w; -// cycles-=3; if (eal_r) return *(uint16_t *)eal_r; - return readmemw(easeg, cpu_state.eaaddr); + return readmemw(easeg,cpu_state.eaaddr); } static inline uint32_t geteal() { if (cpu_mod == 3) return cpu_state.regs[cpu_rm].l; -// cycles-=3; if (eal_r) return *eal_r; - return readmeml(easeg, cpu_state.eaaddr); + return readmeml(easeg,cpu_state.eaaddr); } static inline uint64_t geteaq() { - return readmemq(easeg, cpu_state.eaaddr); + return readmemq(easeg,cpu_state.eaaddr); } static inline uint8_t geteab_mem() @@ -204,24 +221,20 @@ static inline uint32_t geteal_mem() static inline void seteaq(uint64_t v) { - writememql(easeg, cpu_state.eaaddr, v); + writememql(easeg+cpu_state.eaaddr, v); } -#define seteab(v) if (cpu_mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v -#define seteaw(v) if (cpu_mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v -#define seteal(v) if (cpu_mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v +#define seteab(v) if (cpu_mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v +#define seteaw(v) if (cpu_mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v +#define seteal(v) if (cpu_mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v -#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); -#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); -#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); +#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writemembl(easeg+cpu_state.eaaddr,v); +#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg+cpu_state.eaaddr,v); +#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg+cpu_state.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); +#endif diff --git a/src/386_dynarec.c b/src/386_dynarec.c index 09894dd..ec56e57 100644 --- a/src/386_dynarec.c +++ b/src/386_dynarec.c @@ -1,15 +1,19 @@ #include #include #include +#if defined(__APPLE__) && defined(__aarch64__) +#include +#endif #include "ibm.h" -#include "386.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" #include "mem.h" #include "codegen.h" +#include "codegen_backend.h" #include "cpu.h" #include "fdc.h" +#include "nmi.h" #include "pic.h" #include "timer.h" @@ -17,57 +21,18 @@ #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_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; -int nmi_enable = 1; -int inscounts[256]; -uint32_t oldpc2; - -int trap; - - - -int cpl_override=0; - -int has_fpu; -int fpucount=0; -uint16_t rds; -uint16_t ea_rseg; - -int is486; -int cgate32; - - -uint8_t romext[32768]; -uint8_t *ram,*rom; - -uint32_t rmdat32; -uint32_t backupregs[16]; -int oddeven=0; -int inttype; - - -uint32_t oldcs2; -uint32_t oldecx; - -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 = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; if (cpu_rm == 4) { uint8_t sib = rmdat >> 8; @@ -94,8 +59,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat) else if ((sib & 6) == 4 && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } if (((sib >> 3) & 7) != 4) cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); @@ -108,8 +72,7 @@ static inline void fetch_ea_32_long(uint32_t rmdat) if (cpu_rm == 5 && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } if (cpu_mod == 1) { @@ -140,8 +103,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; - if (!cpu_mod && cpu_rm == 6) + if (!cpu_mod && cpu_rm == 6) { cpu_state.eaaddr = getword(); } @@ -163,8 +125,7 @@ static inline void fetch_ea_16_long(uint32_t rmdat) if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) { easeg = ss; - ea_rseg = SS; - cpu_state.ea_seg = &_ss; + cpu_state.ea_seg = &cpu_state.seg_ss; } cpu_state.eaaddr &= 0xFFFF; } @@ -183,95 +144,6 @@ static inline void fetch_ea_16_long(uint32_t rmdat) #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=cpu_state.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() -{ -// pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode); - -// if (output) -// { -// dumpregs(); -// exit(-1); -// } - x86_int(6); -} /*Prefetch emulation is a fairly simplistic model: - All instruction bytes must be fetched before it starts. @@ -343,6 +215,8 @@ static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int } prefetch_prefixes = 0; + if (prefetch_bytes > 16) + prefetch_bytes = 16; } static void prefetch_flush() @@ -353,974 +227,10 @@ static void prefetch_flush() #define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32) \ do { if (cpu_prefetch_cycles) prefetch_run(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32); } while (0) -#define PREFETCH_PREFIX() prefetch_prefixes++ +#define PREFETCH_PREFIX() do { if (cpu_prefetch_cycles) prefetch_prefixes++; } while (0) #define PREFETCH_FLUSH() prefetch_flush() -int rep386(int fv) -{ - uint8_t temp; - uint32_t c;//=CX; - uint8_t temp2; - uint16_t tempw,tempw2,of; - uint32_t ipc = cpu_state.oldpc;//pc-1; - uint32_t rep32 = cpu_state.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); - int reads = 0, reads_l = 0, writes = 0, writes_l = 0, total_cycles = 0; - - if (trap) - cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ - - 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:*/ - cpu_state.ea_seg = &_es; - PREFETCH_PREFIX(); - goto startrep; - break; - case 0x2E: case 0x12E: case 0x22E: case 0x32E: /*CS:*/ - cpu_state.ea_seg = &_cs; - PREFETCH_PREFIX(); - goto startrep; - case 0x36: case 0x136: case 0x236: case 0x336: /*SS:*/ - cpu_state.ea_seg = &_ss; - PREFETCH_PREFIX(); - goto startrep; - case 0x3E: case 0x13E: case 0x23E: case 0x33E: /*DS:*/ - cpu_state.ea_seg = &_ds; - PREFETCH_PREFIX(); - goto startrep; - case 0x64: case 0x164: case 0x264: case 0x364: /*FS:*/ - cpu_state.ea_seg = &_fs; - PREFETCH_PREFIX(); - goto startrep; - case 0x65: case 0x165: case 0x265: case 0x365: /*GS:*/ - cpu_state.ea_seg = &_gs; - PREFETCH_PREFIX(); - goto startrep; - case 0x66: case 0x166: case 0x266: case 0x366: /*Data size prefix*/ - rep32 = (rep32 & 0x200) | ((use32 ^ 0x100) & 0x100); - PREFETCH_PREFIX(); - goto startrep; - case 0x67: case 0x167: case 0x267: case 0x367: /*Address size prefix*/ - rep32 = (rep32 & 0x100) | ((use32 ^ 0x200) & 0x200); - PREFETCH_PREFIX(); - goto startrep; - case 0x6C: case 0x16C: /*REP INSB*/ -// cpu_notreps++; - if (c>0) - { - checkio_perm(DX); - temp2=inb(DX); - writememb(es,DI,temp2); - if (cpu_state.abrt) break; - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles-=15; - reads++; writes++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) EDI--; - else EDI++; - c--; - cycles-=15; - reads++; writes++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles-=15; - reads++; writes++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) DI-=4; - else DI+=4; - c--; - cycles-=15; - reads_l++; writes_l++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) EDI-=2; - else EDI+=2; - c--; - cycles-=15; - reads++; writes++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) EDI-=4; - else EDI+=4; - c--; - cycles-=15; - reads_l++; writes_l++; total_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(cpu_state.ea_seg->base, SI); - if (cpu_state.abrt) break; - checkio_perm(DX); - outb(DX,temp2); - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=14; - reads++; writes++; total_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(cpu_state.ea_seg->base, ESI); - if (cpu_state.abrt) break; - checkio_perm(DX); - outb(DX,temp2); - if (flags&D_FLAG) ESI--; - else ESI++; - c--; - cycles-=14; - reads++; writes++; total_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(cpu_state.ea_seg->base, SI); - if (cpu_state.abrt) break; -// pclog("OUTSW %04X -> %04X\n",SI,tempw); - outw(DX,tempw); - if (flags&D_FLAG) SI-=2; - else SI+=2; - c--; - cycles-=14; - reads++; writes++; total_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(cpu_state.ea_seg->base, SI); - if (cpu_state.abrt) break; - outl(DX, templ); - if (flags & D_FLAG) SI -= 4; - else SI += 4; - c--; - cycles -= 14; - reads_l++; writes_l++; total_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(cpu_state.ea_seg->base, ESI); - if (cpu_state.abrt) break; - outw(DX,tempw); - if (flags&D_FLAG) ESI-=2; - else ESI+=2; - c--; - cycles-=14; - reads++; writes++; total_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(cpu_state.ea_seg->base, ESI); - if (cpu_state.abrt) break; - outl(DX, templ); - if (flags & D_FLAG) ESI -= 4; - else ESI += 4; - c--; - cycles -= 14; - reads_l++; writes_l++; total_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(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) break; - writememb(es,DI,temp2); if (cpu_state.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++; - reads++; writes++; total_cycles += is486 ? 3 : 4; - 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(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) break; - writememb(es,EDI,temp2); if (cpu_state.abrt) break; - if (flags&D_FLAG) { EDI--; ESI--; } - else { EDI++; ESI++; } - c--; - cycles-=(is486)?3:4; - ins++; - reads++; writes++; total_cycles += is486 ? 3 : 4; - 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(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) break; - writememw(es,DI,tempw); if (cpu_state.abrt) break; - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - c--; - cycles-=(is486)?3:4; - ins++; - reads++; writes++; total_cycles += is486 ? 3 : 4; - 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(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) break; -// pclog("MOVSD %08X from %08X to %08X (%04X:%08X)\n", templ, ds+SI, es+DI, CS, pc); - writememl(es,DI,templ); if (cpu_state.abrt) break; - if (flags&D_FLAG) { DI-=4; SI-=4; } - else { DI+=4; SI+=4; } - c--; - cycles-=(is486)?3:4; - ins++; - reads_l++; writes_l++; total_cycles += is486 ? 3 : 4; - 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(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) break; - writememw(es,EDI,tempw); if (cpu_state.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++; - reads++; writes++; total_cycles += is486 ? 3 : 4; - 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(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) break; -// if ((EDI&0xFFFF0000)==0xA0000) cycles-=12; - writememl(es,EDI,templ); if (cpu_state.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++; - reads_l++; writes_l++; total_cycles += is486 ? 3 : 4; - 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(cpu_state.ea_seg->base, SI); - temp2=readmemb(es,DI); - if (cpu_state.abrt) { flags=of; break; } - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } - c--; - cycles-=(is486)?7:9; - reads += 2; total_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(cpu_state.ea_seg->base, ESI); - temp2=readmemb(es,EDI); - if (cpu_state.abrt) { flags=of; break; } - if (flags&D_FLAG) { EDI--; ESI--; } - else { EDI++; ESI++; } - c--; - cycles-=(is486)?7:9; - reads += 2; total_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(cpu_state.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 (cpu_state.abrt) { flags=of; break; } - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } - c--; - cycles-=(is486)?7:9; - reads += 2; total_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(cpu_state.ea_seg->base, SI); - templ2=readmeml(es,DI); - if (cpu_state.abrt) { flags=of; break; } - if (flags&D_FLAG) { DI-=4; SI-=4; } - else { DI+=4; SI+=4; } - c--; - cycles-=(is486)?7:9; - reads_l += 2; total_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(cpu_state.ea_seg->base, ESI); - tempw2=readmemw(es,EDI); - if (cpu_state.abrt) { flags=of; break; } - if (flags&D_FLAG) { EDI-=2; ESI-=2; } - else { EDI+=2; ESI+=2; } - c--; - cycles-=(is486)?7:9; - reads += 2; total_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(cpu_state.ea_seg->base, ESI); - templ2=readmeml(es,EDI); - if (cpu_state.abrt) { flags=of; break; } - if (flags&D_FLAG) { EDI-=4; ESI-=4; } - else { EDI+=4; ESI+=4; } - c--; - cycles-=(is486)?7:9; - reads_l += 2; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles-=(is486)?4:5; - writes++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) EDI--; - else EDI++; - c--; - cycles-=(is486)?4:5; - writes++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) DI-=2; - else DI+=2; - c--; - cycles-=(is486)?4:5; - writes++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) EDI-=2; - else EDI+=2; - c--; - cycles-=(is486)?4:5; - writes++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) DI-=4; - else DI+=4; - c--; - cycles-=(is486)?4:5; - writes_l++; total_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 (cpu_state.abrt) break; - if (flags&D_FLAG) EDI-=4; - else EDI+=4; - c--; - cycles-=(is486)?4:5; - writes_l++; total_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(cpu_state.ea_seg->base, SI); - if (cpu_state.abrt) break; - if (flags&D_FLAG) SI--; - else SI++; - c--; - cycles-=5; - reads++; total_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(cpu_state.ea_seg->base, ESI); - if (cpu_state.abrt) break; - if (flags&D_FLAG) ESI--; - else ESI++; - c--; - cycles-=5; - reads++; total_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(cpu_state.ea_seg->base, SI); - if (cpu_state.abrt) break; - if (flags&D_FLAG) SI-=2; - else SI+=2; - c--; - cycles-=5; - reads++; total_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(cpu_state.ea_seg->base, SI); - if (cpu_state.abrt) break; - if (flags&D_FLAG) SI-=4; - else SI+=4; - c--; - cycles-=5; - reads_l++; total_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(cpu_state.ea_seg->base, ESI); - if (cpu_state.abrt) break; - if (flags&D_FLAG) ESI-=2; - else ESI+=2; - c--; - cycles-=5; - reads++; total_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(cpu_state.ea_seg->base, ESI); - if (cpu_state.abrt) break; - if (flags&D_FLAG) ESI-=4; - else ESI+=4; - c--; - cycles-=5; - reads_l++; total_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 (cpu_state.abrt) { flags=of; break; } - setsub8(AL,temp2); - tempz = (ZF_SET()) ? 1 : 0; - if (flags&D_FLAG) DI--; - else DI++; - c--; - cycles-=(is486)?5:8; - reads++; total_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 (cpu_state.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; - reads++; total_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 (cpu_state.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; - reads++; total_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 (cpu_state.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; - reads_l++; total_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 (cpu_state.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; - reads++; total_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 (cpu_state.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; - reads_l++; total_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(); - PREFETCH_RUN(total_cycles, 1, -1, reads, reads_l, writes, writes_l, 0); - return cpu_state.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 (cpu_state.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; -// pclog("%02X %02X\n",d,d&(1<<(port&7))); - 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) @@ -1328,423 +238,425 @@ int dontprint=0; #include "386_ops.h" -#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG)) +#define CACHE_ON() (!(cr0 & (1 << 30)) && !(cpu_state.flags & T_FLAG)) //#define CACHE_ON() 0 -static int cycles_main = 0; +int cpu_end_block_after_ins = 0; + + +static inline void exec_interpreter(void) +{ + cpu_block_end = 0; + x86_was_reset = 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) + { + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) + { + uint8_t opcode = fetchdat & 0xFF; + fetchdat >>= 8; + trap = cpu_state.flags & T_FLAG; + +// 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 | cpu_state.op32) & 0x3ff](fetchdat); + } + + if (((cs + cpu_state.pc) >> 12) != pccache) + CPU_BLOCK_END(); + + if (cpu_state.abrt) + CPU_BLOCK_END(); + if (cpu_state.smi_pending) + CPU_BLOCK_END(); + if (trap) + CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + if (cpu_end_block_after_ins) + { + cpu_end_block_after_ins--; + if (!cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + + ins++; + insc++; + } + + if (trap) + { + trap = 0; + cpu_state.oldpc = cpu_state.pc; + x86_int(1); + } + + cpu_end_block_after_ins = 0; +} + +static inline void exec_recompiler(void) +{ + uint32_t phys_addr = get_phys(cs+cpu_state.pc); + int hash = HASH(phys_addr); + codeblock_t *block = &codeblock[codeblock_hash[hash]]; + int valid_block = 0; + + if (!cpu_state.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->phys == phys_addr) && !((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); + if (!valid_block) + { + uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + int byte_offset = (phys_addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = 1ull << (PAGE_BYTE_MASK_MASK & 0x3f); + + if ((page->code_present_mask & mask) || (page->byte_code_present_mask[byte_offset] & byte_mask)) + { + /*Walk page tree to see if we find the correct block*/ + codeblock_t *new_block = codeblock_tree_find(phys_addr, cs); + if (new_block) + { + valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) && + (new_block->phys == phys_addr) && !((new_block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((new_block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); + if (valid_block) + { + block = new_block; + codeblock_hash[hash] = get_block_nr(block); + } + } + } + } + + if (valid_block && (block->page_mask & *block->dirty_mask)) + { + codegen_check_flush(page, page->dirty_mask, phys_addr); + if (block->pc == BLOCK_PC_INVALID) + valid_block = 0; + else if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; + } + 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->pc + ((block->flags & CODEBLOCK_BYTE_MASK) ? 0x40 : 0x400)); + 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 & *block->dirty_mask2) + { + codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2); + if (block->pc == BLOCK_PC_INVALID) + valid_block = 0; + else if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; + } + } + if (valid_block && (block->flags & CODEBLOCK_IN_DIRTY_LIST)) + { + block->flags &= ~CODEBLOCK_WAS_RECOMPILED; + if (block->flags & CODEBLOCK_BYTE_MASK) + block->flags |= CODEBLOCK_NO_IMMEDIATES; + else + block->flags |= CODEBLOCK_BYTE_MASK; + } + if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED) && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != (cpu_state.TOP & 7)) + { + /*FPU top-of-stack does not match the value this block was compiled + with, re-compile using dynamic top-of-stack*/ + block->flags &= ~(CODEBLOCK_STATIC_TOP | CODEBLOCK_WAS_RECOMPILED); + } + } + + if (valid_block && (block->flags & CODEBLOCK_WAS_RECOMPILED)) + { + void (*code)() = (void *)&block->data[BLOCK_START]; + +// 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; + + cpu_recomp_blocks++; + } + else if (valid_block && !cpu_state.abrt) + { + uint32_t start_pc = cs+cpu_state.pc; + const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000; + + cpu_block_end = 0; + x86_was_reset = 0; + + cpu_new_blocks++; + +#if defined(__APPLE__) && defined(__aarch64__) + pthread_jit_write_protect_np(0); +#endif + codegen_block_start_recompile(block); + 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) + { + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) + { + uint8_t 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 | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); + + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + + /*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 (((cs+cpu_state.pc) - start_pc) >= max_block_size) + CPU_BLOCK_END(); + if (cpu_state.flags & T_FLAG) + CPU_BLOCK_END(); + if (cpu_state.smi_pending) + CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + if (cpu_end_block_after_ins) + { + cpu_end_block_after_ins--; + if (!cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + + if (cpu_state.abrt) + { + if (!(cpu_state.abrt & ABRT_EXPECTED)) + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + insc++; + } + cpu_end_block_after_ins = 0; + + if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !x86_was_reset) + codegen_block_end_recompile(block); + + if (x86_was_reset) + codegen_reset(); + + codegen_in_recompile = 0; +#if defined(__APPLE__) && defined(__aarch64__) + pthread_jit_write_protect_np(1); +#endif + } + else if (!cpu_state.abrt) + { + /*Mark block but do not recompile*/ + uint32_t start_pc = cs+cpu_state.pc; + const int max_block_size = (block->flags & CODEBLOCK_BYTE_MASK) ? ((128 - 25) - (start_pc & 0x3f)) : 1000; + + cpu_block_end = 0; + x86_was_reset = 0; + + codegen_block_init(phys_addr); + +// 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) + { + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &cpu_state.seg_ds; + cpu_state.ssegs = 0; + + codegen_endpc = (cs + cpu_state.pc) + 8; + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) + { + uint8_t 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++; + + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + + /*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 (((cs+cpu_state.pc) - start_pc) >= max_block_size) + CPU_BLOCK_END(); + if (cpu_state.flags & T_FLAG) + CPU_BLOCK_END(); + if (cpu_state.smi_pending) + CPU_BLOCK_END(); + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + if (cpu_end_block_after_ins) + { + cpu_end_block_after_ins--; + if (!cpu_end_block_after_ins) + CPU_BLOCK_END(); + } + + if (cpu_state.abrt) + { + if (!(cpu_state.abrt & ABRT_EXPECTED)) + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + insc++; + } + cpu_end_block_after_ins = 0; + +// if (!cpu_state.abrt && !x86_was_reset) + if ((!cpu_state.abrt || (cpu_state.abrt & ABRT_EXPECTED)) && !x86_was_reset) + codegen_block_end(); + + if (x86_was_reset) + codegen_reset(); + } + else + cpu_state.oldpc = cpu_state.pc; + +} + + +int cycles_main = 0; void exec386_dynarec(int cycs) { uint8_t temp; - uint32_t addr; int tempi; int cycdiff; int oldcyc; + int cyc_period = cycs / 2000; /*5us*/ -//output = 3; cycles_main += cycs; while (cycles_main > 0) { int cycles_start; - cycles += 1000; + cycles += cyc_period; cycles_start = cycles; - timer_start_period(cycles << TIMER_SHIFT); -// output=3; - while (cycles>0) - { - oldcs = CS; - cpu_state.oldpc = cpu_state.pc; - oldcpl = CPL; - cpu_state.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*/ + while (cycles>0) { - 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; - cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; - cpu_state.op32 = use32; - - cpu_state.ea_seg = &_ds; - cpu_state.ssegs = 0; + oldcyc=cycles; +// if (output && CACHE_ON()) pclog("Block %04x:%04x %04x:%08x\n", CS, pc, SS,ESP); + if (!CACHE_ON()) /*Interpret block*/ + exec_interpreter(); + else + exec_recompiler(); - fetchdat = fastreadl(cs + cpu_state.pc); -// if (!fetchdat) -// fatal("Dead with cache off\n"); - if (!cpu_state.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 | cpu_state.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 (cpu_state.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 && !cpu_state.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, cs); - 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 && block->was_recompiled && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != cpu_state.TOP) - { - /*FPU top-of-stack does not match the value this block was compiled - with, re-compile using dynamic top-of-stack*/ - block->flags &= ~CODEBLOCK_STATIC_TOP; - block->was_recompiled = 0; - } - } - - if (valid_block && block->was_recompiled) - { - 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 (valid_block && !cpu_state.abrt) - { - 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_start_recompile(block); - 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; - cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; - cpu_state.op32 = use32; - - cpu_state.ea_seg = &_ds; - cpu_state.ssegs = 0; - - fetchdat = fastreadl(cs + cpu_state.pc); -// if (fetchdat == 0xffffffff) -// fatal("Dead ffffffff\n"); -// if (!fetchdat) -// fatal("Dead\n"); - if (!cpu_state.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 | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); - - x86_opcodes[(opcode | cpu_state.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 (cpu_state.abrt) - { - codegen_block_remove(); - CPU_BLOCK_END(); - } - - ins++; - insc++; - } - - if (!cpu_state.abrt && !x86_was_reset) - codegen_block_end_recompile(block); - - if (x86_was_reset) - codegen_reset(); - - codegen_in_recompile = 0; -// output &= ~2; - } - else if (!cpu_state.abrt) - { - /*Mark block but do not recompile*/ - 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); - -// 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; - cpu_state.oldpc = cpu_state.pc; - oldcpl=CPL; - cpu_state.op32 = use32; - - cpu_state.ea_seg = &_ds; - cpu_state.ssegs = 0; - - codegen_endpc = (cs + cpu_state.pc) + 8; - fetchdat = fastreadl(cs + cpu_state.pc); - - if (!cpu_state.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++; - - x86_opcodes[(opcode | cpu_state.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 (cpu_state.abrt) - { - codegen_block_remove(); - CPU_BLOCK_END(); - } - - ins++; - insc++; - } - - if (!cpu_state.abrt && !x86_was_reset) - codegen_block_end(); - - if (x86_was_reset) - codegen_reset(); - -// output &= ~2; - } -// if (output && (SP & 1)) -// fatal("odd SP\n"); - } - - cycdiff=oldcyc-cycles; - tsc += cycdiff; - -// timer_end_period(cycles); - - if (cpu_state.abrt) - { - flags_rebuild(); - tempi = cpu_state.abrt; - cpu_state.abrt = 0; - x86_doabrt(tempi); if (cpu_state.abrt) { + flags_rebuild(); + tempi = cpu_state.abrt & ABRT_MASK; cpu_state.abrt = 0; - CS = oldcs; - cpu_state.pc = cpu_state.oldpc; - pclog("Double fault %i\n", ins); - pmodeint(8, 0); + x86_doabrt(tempi); if (cpu_state.abrt) { cpu_state.abrt = 0; - softresetx86(); - cpu_set_edx(); - pclog("Triple fault - reset\n"); + cpu_state.pc = cpu_state.oldpc; + pclog("Double fault %i\n", ins); + pmodeint(8, 0); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); + pclog("Triple fault - reset\n"); + } } } - } - if (trap) - { + if (cpu_state.smi_pending) + { + cpu_state.smi_pending = 0; + x86_smi_enter(); + } + else if (nmi && nmi_enable && nmi_mask) + { + cpu_state.oldpc = cpu_state.pc; +// pclog("NMI\n"); + x86_int(2); + nmi_enable = 0; + if (nmi_auto_clear) + { + nmi_auto_clear = 0; + nmi = 0; + } + } + else if ((cpu_state.flags & I_FLAG) && pic_intpending) + { + temp=picinterrupt(); + if (temp!=0xFF) + { + cpu_state.oldpc = cpu_state.pc; + x86_int(temp); +// pclog("IRQ %02X %04X:%04X %04X:%04X\n", temp, SS, SP, CS, pc); + } + } - 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)); - } + cycdiff=oldcyc-cycles; + tsc += cycdiff; } - 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); + + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); cycles_main -= (cycles_start - cycles); } } diff --git a/src/386_dynarec_ops.c b/src/386_dynarec_ops.c index bef86c8..249909f 100644 --- a/src/386_dynarec_ops.c +++ b/src/386_dynarec_ops.c @@ -1,11 +1,11 @@ #include "ibm.h" #include "cpu.h" -#include "386.h" #include "x86.h" #include "x86_ops.h" #include "x87.h" #include "x86_flags.h" #include "mem.h" +#include "nmi.h" #include "pic.h" #include "codegen.h" @@ -14,14 +14,10 @@ #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 = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; @@ -36,7 +32,6 @@ static inline void fetch_ea_16_long(uint32_t rmdat) { eal_r = eal_w = NULL; easeg = cpu_state.ea_seg->base; - ea_rseg = cpu_state.ea_seg->seg; if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) { uint32_t addr = easeg + cpu_state.eaaddr; @@ -47,8 +42,8 @@ static inline void fetch_ea_16_long(uint32_t rmdat) } } -#define fetch_ea_16(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat); -#define fetch_ea_32(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_32_long(rmdat); +#define fetch_ea_16(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat); +#define fetch_ea_32(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_32_long(rmdat); #define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, read_ls, writes, write_ls, ea32) @@ -56,7 +51,8 @@ static inline void fetch_ea_16_long(uint32_t rmdat) #define PREFETCH_FLUSH() #define OP_TABLE(name) dynarec_ops_ ## name -#define CLOCK_CYCLES(c) +/*Temporary*/ +#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 index 43a7cfd..d59132a 100644 --- a/src/386_ops.h +++ b/src/386_ops.h @@ -104,12 +104,22 @@ static inline uint32_t POP_L_seg(uint32_t seg) return ret; } +static int ILLEGAL(uint32_t fetchdat) +{ + cpu_state.pc = cpu_state.oldpc; + +// fatal("Illegal instruction %08X\n", fetchdat); + x86illegal(); + return 0; +} + #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_cyrix.h" #include "x86_ops_flag.h" #include "x86_ops_fpu.h" #include "x86_ops_inc_dec.h" @@ -118,6 +128,7 @@ static inline uint32_t POP_L_seg(uint32_t seg) #include "x86_ops_jump.h" #include "x86_ops_misc.h" #include "x86_ops_mmx.h" +#include "x86_ops_3dnow.h" #include "x86_ops_mmx_arith.h" #include "x86_ops_mmx_cmp.h" #include "x86_ops_mmx_logic.h" @@ -140,15 +151,6 @@ static inline uint32_t POP_L_seg(uint32_t seg) #include "x86_ops_string.h" #include "x86_ops_xchg.h" -static int ILLEGAL(uint32_t fetchdat) -{ - cpu_state.pc = cpu_state.oldpc; - -// fatal("Illegal instruction %08X\n", fetchdat); - x86illegal(); - return 0; -} - static int op0F_w_a16(uint32_t fetchdat) { int opcode = fetchdat & 0xff; @@ -279,7 +281,7 @@ OpFn OP_TABLE(386_0f)[1024] = /* 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,opMOV_TRx_r_a16,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, @@ -301,7 +303,7 @@ OpFn OP_TABLE(386_0f)[1024] = /* 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,opMOV_TRx_r_a16,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, @@ -323,7 +325,7 @@ OpFn OP_TABLE(386_0f)[1024] = /* 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,opMOV_TRx_r_a32,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, @@ -345,7 +347,7 @@ OpFn OP_TABLE(386_0f)[1024] = /* 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,opMOV_TRx_r_a32,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, @@ -370,7 +372,7 @@ OpFn OP_TABLE(winchip_0f)[1024] = /* 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,opMOV_TRx_r_a16,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, @@ -380,10 +382,10 @@ OpFn OP_TABLE(winchip_0f)[1024] = /*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, +/*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, opRSM, 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, +/*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, @@ -392,7 +394,7 @@ OpFn OP_TABLE(winchip_0f)[1024] = /* 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,opMOV_TRx_r_a16,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, @@ -402,10 +404,10 @@ OpFn OP_TABLE(winchip_0f)[1024] = /*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, +/*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, opRSM, 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, +/*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, @@ -414,7 +416,7 @@ OpFn OP_TABLE(winchip_0f)[1024] = /* 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,opMOV_TRx_r_a32,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, @@ -424,10 +426,10 @@ OpFn OP_TABLE(winchip_0f)[1024] = /*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, +/*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, opRSM, 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, +/*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, @@ -436,7 +438,7 @@ OpFn OP_TABLE(winchip_0f)[1024] = /* 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,opMOV_TRx_r_a32,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, @@ -446,16 +448,107 @@ OpFn OP_TABLE(winchip_0f)[1024] = /*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, +/*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, opRSM, 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, +/*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(pentium_0f)[1024] = +OpFn OP_TABLE(winchip2_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, opPREFETCH_a16, opFEMMS, op3DNOW_a16, +/*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, opRSM, 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, opPREFETCH_a16, opFEMMS, op3DNOW_a16, +/*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, opRSM, 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, opPREFETCH_a32, opFEMMS, op3DNOW_a32, +/*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, opRSM, 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, opPREFETCH_a32, opFEMMS, op3DNOW_a32, +/*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, opRSM, 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(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*/ @@ -471,7 +564,7 @@ OpFn OP_TABLE(pentium_0f)[1024] = /*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, +/*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, opRSM, 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, @@ -493,7 +586,7 @@ OpFn OP_TABLE(pentium_0f)[1024] = /*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, +/*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, opRSM, 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, @@ -515,7 +608,7 @@ OpFn OP_TABLE(pentium_0f)[1024] = /*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, +/*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, opRSM, 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, @@ -537,7 +630,7 @@ OpFn OP_TABLE(pentium_0f)[1024] = /*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, +/*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, opRSM, 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, @@ -546,7 +639,98 @@ OpFn OP_TABLE(pentium_0f)[1024] = /*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, }; -OpFn OP_TABLE(pentiummmx_0f)[1024] = +OpFn OP_TABLE(c6x86_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, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, 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, opRSM, 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, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opSMINT, 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, opRSM, 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, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, 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, opRSM, 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, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opSMINT, 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, opRSM, 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*/ @@ -562,7 +746,7 @@ OpFn OP_TABLE(pentiummmx_0f)[1024] = /*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, +/*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, opRSM, 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, @@ -584,7 +768,7 @@ OpFn OP_TABLE(pentiummmx_0f)[1024] = /*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, +/*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, opRSM, 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, @@ -606,7 +790,7 @@ OpFn OP_TABLE(pentiummmx_0f)[1024] = /*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, +/*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, opRSM, 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, @@ -628,7 +812,7 @@ OpFn OP_TABLE(pentiummmx_0f)[1024] = /*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, +/*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, opRSM, 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, @@ -644,16 +828,16 @@ OpFn OP_TABLE(c6x86mx_0f)[1024] = /*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, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, 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, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a16_cx,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, +/*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, opRSM, 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, @@ -666,16 +850,16 @@ OpFn OP_TABLE(c6x86mx_0f)[1024] = /*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, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a16, opWRSHR_a16, 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, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a16_cx,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, +/*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, opRSM, 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, @@ -688,16 +872,16 @@ OpFn OP_TABLE(c6x86mx_0f)[1024] = /*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, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, 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, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, opSVDC_a32, opRSDC_a32, opSVLDT_a32, opRSLDT_a32, opSVTS_a32, opRSTS_a32, opMOVD_mm_l_a32_cx,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, +/*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, opRSM, 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, @@ -710,16 +894,16 @@ OpFn OP_TABLE(c6x86mx_0f)[1024] = /*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, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, opRDSHR_a32, opWRSHR_a32, 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, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, opSVDC_a16, opRSDC_a16, opSVLDT_a16, opRSLDT_a16, opSVTS_a16, opRSTS_a16, opMOVD_mm_l_a32_cx,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, +/*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, opRSM, 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, @@ -728,7 +912,189 @@ OpFn OP_TABLE(c6x86mx_0f)[1024] = /*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] = +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, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, +/*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, 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*/ 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, opRSM, 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, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, +/*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, 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*/ 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, opRSM, 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, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, +/*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, 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*/ 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, opRSM, 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, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, +/*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, 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*/ 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, opRSM, 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, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, +/*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, opRSM, 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, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, opHINTNOP_a16, +/*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, opRSM, 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, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, +/*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, opRSM, 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, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, opHINTNOP_a32, +/*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, opRSM, 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(286)[1024] = { /*16-bit data, 16-bit addr*/ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ @@ -910,4 +1276,186 @@ OpFn OP_TABLE(386)[1024] = /*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, }; +OpFn OP_TABLE(REPE)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*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, opES_REPE_w_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPE_w_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_w_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPE_w_a16,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*/ 0, 0, 0, 0, opFS_REPE_w_a16,opGS_REPE_w_a16,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSW_a16, opREP_OUTSB_a16,opREP_OUTSW_a16, +/*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, opREP_MOVSB_a16,opREP_MOVSW_a16,opREP_CMPSB_a16_E,opREP_CMPSW_a16_E,0, 0, opREP_STOSB_a16,opREP_STOSW_a16,opREP_LODSB_a16,opREP_LODSW_a16,opREP_SCASB_a16_E,opREP_SCASW_a16_E, +/*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*/ 0, 0, 0, 0, 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*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*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, opES_REPE_l_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPE_l_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_l_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPE_l_a16,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*/ 0, 0, 0, 0, opFS_REPE_l_a16,opGS_REPE_l_a16,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSL_a16, opREP_OUTSB_a16,opREP_OUTSL_a16, +/*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, opREP_MOVSB_a16,opREP_MOVSL_a16,opREP_CMPSB_a16_E,opREP_CMPSL_a16_E,0, 0, opREP_STOSB_a16,opREP_STOSL_a16,opREP_LODSB_a16,opREP_LODSL_a16,opREP_SCASB_a16_E,opREP_SCASL_a16_E, +/*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*/ 0, 0, 0, 0, 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*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*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, opES_REPE_w_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPE_w_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_w_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPE_w_a32,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*/ 0, 0, 0, 0, opFS_REPE_w_a32,opGS_REPE_w_a32,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSW_a32, opREP_OUTSB_a32,opREP_OUTSW_a32, +/*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, opREP_MOVSB_a32,opREP_MOVSW_a32,opREP_CMPSB_a32_E,opREP_CMPSW_a32_E,0, 0, opREP_STOSB_a32,opREP_STOSW_a32,opREP_LODSB_a32,opREP_LODSW_a32,opREP_SCASB_a32_E,opREP_SCASW_a32_E, +/*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*/ 0, 0, 0, 0, 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*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*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, opES_REPE_l_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPE_l_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_l_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPE_l_a32,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*/ 0, 0, 0, 0, opFS_REPE_l_a32,opGS_REPE_l_a32,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSL_a32, opREP_OUTSB_a32,opREP_OUTSL_a32, +/*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, opREP_MOVSB_a32,opREP_MOVSL_a32,opREP_CMPSB_a32_E,opREP_CMPSL_a32_E,0, 0, opREP_STOSB_a32,opREP_STOSL_a32,opREP_LODSB_a32,opREP_LODSL_a32,opREP_SCASB_a32_E,opREP_SCASL_a32_E, +/*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*/ 0, 0, 0, 0, 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*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +OpFn OP_TABLE(REPNE)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*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, opES_REPNE_w_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_w_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_w_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_w_a16,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*/ 0, 0, 0, 0, opFS_REPNE_w_a16,opGS_REPNE_w_a16,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSW_a16, opREP_OUTSB_a16,opREP_OUTSW_a16, +/*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, opREP_MOVSB_a16,opREP_MOVSW_a16,opREP_CMPSB_a16_NE,opREP_CMPSW_a16_NE,0, 0, opREP_STOSB_a16,opREP_STOSW_a16,opREP_LODSB_a16,opREP_LODSW_a16,opREP_SCASB_a16_NE,opREP_SCASW_a16_NE, +/*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*/ 0, 0, 0, 0, 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*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*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, opES_REPNE_l_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_l_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_l_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_l_a16,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*/ 0, 0, 0, 0, opFS_REPNE_l_a16,opGS_REPNE_l_a16,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSL_a16, opREP_OUTSB_a16,opREP_OUTSL_a16, +/*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, opREP_MOVSB_a16,opREP_MOVSL_a16,opREP_CMPSB_a16_NE,opREP_CMPSL_a16_NE,0, 0, opREP_STOSB_a16,opREP_STOSL_a16,opREP_LODSB_a16,opREP_LODSL_a16,opREP_SCASB_a16_NE,opREP_SCASL_a16_NE, +/*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*/ 0, 0, 0, 0, 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*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*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, opES_REPNE_w_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_w_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_w_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_w_a32,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*/ 0, 0, 0, 0, opFS_REPNE_w_a32,opGS_REPNE_w_a32,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSW_a32, opREP_OUTSB_a32,opREP_OUTSW_a32, +/*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, opREP_MOVSB_a32,opREP_MOVSW_a32,opREP_CMPSB_a32_NE,opREP_CMPSW_a32_NE,0, 0, opREP_STOSB_a32,opREP_STOSW_a32,opREP_LODSB_a32,opREP_LODSW_a32,opREP_SCASB_a32_NE,opREP_SCASW_a32_NE, +/*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*/ 0, 0, 0, 0, 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*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*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, opES_REPNE_l_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_l_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_l_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_l_a32,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*/ 0, 0, 0, 0, opFS_REPNE_l_a32,opGS_REPNE_l_a32,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSL_a32, opREP_OUTSB_a32,opREP_OUTSL_a32, +/*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, opREP_MOVSB_a32,opREP_MOVSL_a32,opREP_CMPSB_a32_NE,opREP_CMPSL_a32_NE,0, 0, opREP_STOSB_a32,opREP_STOSL_a32,opREP_LODSB_a32,opREP_LODSL_a32,opREP_SCASB_a32_NE,opREP_SCASL_a32_NE, +/*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*/ 0, 0, 0, 0, 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*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + #include "x87_ops.h" diff --git a/src/8087.h b/src/8087.h new file mode 100644 index 0000000..6e5401a --- /dev/null +++ b/src/8087.h @@ -0,0 +1,98 @@ +/*This file is a series of macros to get the 386+ based x87 emulation working with + the 808x emulation*/ +#define X8087 +#define OP_TABLE(name) ops_808x_ ## name + +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#define fetch_ea_16(fetchdat) +#define fetch_ea_32(fetchdat) +#define SEG_CHECK_READ(seg) +#define SEG_CHECK_WRITE(seg) +#define CHECK_WRITE(seg, addr_lo, addr_hi) +#define PREFETCH_RUN(timing, bytes, rmdat, a, b, c, d, e) + +static uint32_t readmeml(uint32_t seg, uint32_t addr) +{ + return readmemw(seg, addr) | (readmemw(seg, addr+2) << 16); +} +static uint64_t readmemq(uint32_t seg, uint32_t addr) +{ + return (uint64_t)readmemw(seg, addr) | ((uint64_t)readmemw(seg, addr+2) << 16) | + ((uint64_t)readmemw(seg, addr+4) << 32) | + ((uint64_t)readmemw(seg, addr+6) << 48); +} + +static void writememb_8087(uint32_t seg, uint32_t addr, uint8_t val) +{ + writememb(seg+addr, val); +} +static void writememl(uint32_t seg, uint32_t addr, uint32_t val) +{ + writememw(seg, addr, val & 0xffff); + writememw(seg, addr+2, (val >> 16) & 0xffff); +} +static void writememq(uint32_t seg, uint32_t addr, uint64_t val) +{ + writememw(seg, addr, val & 0xffff); + writememw(seg, addr+2, (val >> 16) & 0xffff); + writememw(seg, addr+4, (val >> 32) & 0xffff); + writememw(seg, addr+6, (val >> 48) & 0xffff); +} + +static inline uint32_t geteal() +{ + if (cpu_mod == 3) + fatal("geteal cpu_mod==3\n"); + return readmeml(easeg, cpu_state.eaaddr); +} +static inline uint64_t geteaq() +{ + if (cpu_mod == 3) + fatal("geteaq cpu_mod==3\n"); + return readmemq(easeg, cpu_state.eaaddr); +} +static inline void seteal(uint32_t val) +{ + if (cpu_mod == 3) + fatal("seteal cpu_mod==3\n"); + else + writememl(easeg, cpu_state.eaaddr, val); +} +static inline void seteaq(uint64_t val) +{ + if (cpu_mod == 3) + fatal("seteaq cpu_mod==3\n"); + else + writememq(easeg, cpu_state.eaaddr, val); +} + +#define flags_rebuild() + +#define CF_SET() (cpu_state.flags & C_FLAG) +#define NF_SET() (cpu_state.flags & N_FLAG) +#define PF_SET() (cpu_state.flags & P_FLAG) +#define VF_SET() (cpu_state.flags & V_FLAG) +#define ZF_SET() (cpu_state.flags & Z_FLAG) + +#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 writememb writememb_8087 +#include "x87_ops.h" +#undef writememb diff --git a/src/808x.c b/src/808x.c index 1ff61d0..825d9f9 100644 --- a/src/808x.c +++ b/src/808x.c @@ -23,46 +23,51 @@ #include "timer.h" #include "x86.h" #include "x87.h" +#include "paths.h" -int xt_cpu_multi; +uint64_t xt_cpu_multi; int nmi = 0; int nmi_auto_clear = 0; -int nextcyc=0; -int cycdiff; +int oldcpl; + +int tempc; +static int noint=0; + +int output=0; +int timetolive=0; +int ins=0; + int is8086=0; -int memcycs; -int nopageerrors=0; +static uint32_t oldds; +uint32_t oldss; -void FETCHCOMPLETE(); +static int nextcyc=0; +static int memcycs; -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); +static int cycdiff; +static void FETCHCOMPLETE(); -#undef readmemb -#undef readmemw -uint8_t readmemb(uint32_t a) +#define IRQTEST ((cpu_state.flags & I_FLAG) && (pic.pend&~pic.mask) && !noint) + +static 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) +static 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) +static 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); + if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) return readmemwl(s+a); else return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); } @@ -75,48 +80,28 @@ void refreshread() { /*pclog("Refreshread\n"); */FETCHCOMPLETE(); memcycs+=4; } cpu_rm=rmdat&7; \ if (cpu_mod!=3) fetcheal(); } -void writemembl(uint32_t addr, uint8_t val); -void writememb(uint32_t a, uint8_t v) +static 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) +static 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); + 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; -} -uint16_t oldcs; -int oldcpl; - -int tempc; -uint8_t opcode; -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 fetchcycles=0,memcycs,fetchclocks; +static int fetchcycles=0,fetchclocks; + +static uint8_t prefetchqueue[6]; +static uint16_t prefetchpc; +static int prefetchw=0; -uint8_t prefetchqueue[6]; -uint16_t prefetchpc; -int prefetchw=0; static inline uint8_t FETCH() { uint8_t temp; @@ -201,7 +186,7 @@ static inline void FETCHADD(int c) // if (fetchcycles>24) fetchcycles=24; } -void FETCHCOMPLETE() +static void FETCHCOMPLETE() { // pclog("Fetchcomplete %i %i %i\n",fetchcycles&3,fetchcycles,prefetchw); if (!(fetchcycles&3)) return; @@ -342,9 +327,9 @@ reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit */ uint32_t easeg; -int rmdat; +uint32_t rmdat; -uint16_t zero=0; +static uint16_t zero=0; uint16_t *mod1add[2][8]; uint32_t *mod1seg[8]; @@ -441,7 +426,7 @@ static inline void seteaw(uint16_t val) /*Flags*/ uint8_t znptable8[256]; -uint16_t znptable16[65536]; +static uint16_t znptable16[65536]; void makeznptable() { @@ -461,7 +446,7 @@ void makeznptable() znptable8[c]=0; else znptable8[c]=P_FLAG; - if (c == 0xb1) pclog("znp8 b1 = %i %02X\n", d, znptable8[c]); + 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; } @@ -488,10 +473,6 @@ void makeznptable() // makemod1table(); } -int timetolive=0; - -extern uint32_t oldcs2; -extern uint32_t oldpc2; int indump = 0; @@ -507,8 +488,7 @@ void dumpregs() // return; // savenvr(); // return; -chdir(pcempath); - nopageerrors=1; + chdir(logs_path); /* f=fopen("rram3.dmp","wb"); for (c=0;c<0x8000000;c++) putc(readmemb(c+0x10000000),f); fclose(f);*/ @@ -537,13 +517,13 @@ chdir(pcempath); fclose(f);*/ pclog("Dumping rram4.dmp\n"); f=fopen("rram4.dmp","wb"); - for (c=0;c<0x0050000;c++) + for (c=0;c<0x0050000;c++) { cpu_state.abrt = 0; - putc(readmemb386l(0,c+0x80000000),f); + putc(readmembl(c+0x80000000),f); } fclose(f); - pclog("Dumping done\n"); + pclog("Dumping done\n"); /* f=fopen("rram6.dmp","wb"); for (c=0;c<0x1000000;c++) putc(readmemb(c+0xBF000000),f); fclose(f);*/ @@ -579,22 +559,22 @@ chdir(pcempath); 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,cpu_state.oldpc, oldcs2, oldpc2); + printf("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,cpu_state.flags); + printf("%04X\n",cpu_state.oldpc); printf("%i ins\n",ins); if (is386) - printf("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + printf("In %s mode\n",(msw&1)?((cpu_state.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); + printf("CS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",cs,cpu_state.seg_cs.limit,cpu_state.seg_cs.access, cpu_state.seg_cs.limit_low, cpu_state.seg_cs.limit_high); + printf("DS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ds,cpu_state.seg_ds.limit,cpu_state.seg_ds.access, cpu_state.seg_ds.limit_low, cpu_state.seg_ds.limit_high); + printf("ES : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",es,cpu_state.seg_es.limit,cpu_state.seg_es.access, cpu_state.seg_es.limit_low, cpu_state.seg_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("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",cpu_state.seg_fs.base,cpu_state.seg_fs.limit,cpu_state.seg_fs.access, cpu_state.seg_fs.limit_low, cpu_state.seg_fs.limit_high); + printf("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",gs,cpu_state.seg_gs.limit,cpu_state.seg_gs.access, cpu_state.seg_gs.limit_low, cpu_state.seg_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("SS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ss,cpu_state.seg_ss.limit,cpu_state.seg_ss.access, cpu_state.seg_ss.limit_low, cpu_state.seg_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); @@ -602,7 +582,8 @@ chdir(pcempath); 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("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n",cr0,cr2,cr3, cr4); + pclog("SMBASE=%08x\n", cpu_state.smbase); } printf("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); for (c=0;c<1024*1024;c++) @@ -615,18 +596,16 @@ chdir(pcempath); indump = 0; } -int resets = 0; int x86_was_reset = 0; void resetx86() { pclog("x86 reset\n"); - resets++; ins = 0; use32=0; + cpu_cur_status = 0; stack32=0; // i86_Reset(); // cs=0xFFFF0; - cpu_state.pc=0; msw=0; if (is486) cr0 = 1 << 30; @@ -635,25 +614,35 @@ void resetx86() cpu_cache_int_enabled = 0; cpu_update_waitstates(); cr4 = 0; - eflags=0; + cpu_state.eflags=0; cgate32=0; - loadcs(0xFFFF); - rammask = AT ? 0xFFFFFFFF : 0xfffff; + if (AT) + { + loadcs(0xF000); + cpu_state.pc = 0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } + else + { + loadcs(0xFFFF); + cpu_state.pc = 0; + rammask = 0xfffff; + } idt.base = 0; - flags=2; + idt.limit = is386 ? 0x03FF : 0xFFFF; + cpu_state.flags=2; + EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; makeznptable(); resetreadlookup(); makemod1table(); FETCHCLEAR(); x87_reset(); cpu_set_edx(); - EAX = 0; - ESP=0; mmu_perm=4; - memset(inscounts, 0, sizeof(inscounts)); x86seg_reset(); codegen_reset(); x86_was_reset = 1; + cpu_state.smbase = 0x30000; } void softresetx86() @@ -662,151 +651,220 @@ void softresetx86() // exit(-1); use32=0; stack32=0; + cpu_cur_status = 0; // i86_Reset(); // cs=0xFFFF0; - cpu_state.pc=0; msw=0; - cr0=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); cr4 = 0; - eflags=0; + cpu_state.eflags=0; cgate32=0; - loadcs(0xFFFF); + if (AT) + { + loadcs(0xF000); + cpu_state.pc = 0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } + else + { + loadcs(0xFFFF); + cpu_state.pc = 0; + rammask = 0xfffff; + } //rammask=0xFFFFFFFF; - flags=2; + cpu_state.flags=2; idt.base = 0; + if (is386) + { + idt.limit = 0x03FF; + EAX = EBX = ECX = EDX = ESI = EDI = EBP = ESP = 0; + } + else + { + idt.limit = 0xFFFF; + } x86seg_reset(); + flushmmucache(); x86_was_reset = 1; + FETCHCLEAR(); } static void setznp8(uint8_t val) { - flags&=~0xC4; - flags|=znptable8[val]; + cpu_state.flags &= ~0xC4; + cpu_state.flags |= znptable8[val]; } static void setznp16(uint16_t val) { - flags&=~0xC4; - flags|=znptable16[val]; + cpu_state.flags &= ~0xC4; + cpu_state.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; + uint16_t c = (uint16_t)a + (uint16_t)b; + cpu_state.flags &= ~0x8D5; + cpu_state.flags |= znptable8[c&0xFF]; + if (c & 0x100) + cpu_state.flags |= C_FLAG; + if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80)) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + cpu_state.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; + uint16_t c = (uint16_t)a + (uint16_t)b; + cpu_state.flags &= ~0x8D4; + cpu_state.flags |= znptable8[c&0xFF]; + if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80)) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + cpu_state.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; + uint16_t c = (uint16_t)a + (uint16_t)b+tempc; + cpu_state.flags &= ~0x8D5; + cpu_state.flags |= znptable8[c&0xFF]; + if (c & 0x100) + cpu_state.flags |= C_FLAG; + if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80)) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + cpu_state.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; + uint32_t c = (uint32_t)a + (uint32_t)b; + cpu_state.flags &= ~0x8D5; + cpu_state.flags |= znptable16[c&0xFFFF]; + if (c & 0x10000) + cpu_state.flags |= C_FLAG; + if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000)) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + cpu_state.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; + uint32_t c = (uint32_t)a + (uint32_t)b; + cpu_state.flags &= ~0x8D4; + cpu_state.flags |= znptable16[c&0xFFFF]; + if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000)) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + cpu_state.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; + uint32_t c = (uint32_t)a + (uint32_t)b+tempc; + cpu_state.flags &= ~0x8D5; + cpu_state.flags |= znptable16[c&0xFFFF]; + if (c & 0x10000) + cpu_state.flags |= C_FLAG; + if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000)) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + cpu_state.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; + uint16_t c = (uint16_t)a - (uint16_t)b; + cpu_state.flags &= ~0x8D5; + cpu_state.flags |= znptable8[c&0xFF]; + if (c & 0x100) + cpu_state.flags |= C_FLAG; + if ((a ^ b) & (a ^ c) & 0x80) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + cpu_state.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; + uint16_t c = (uint16_t)a - (uint16_t)b; + cpu_state.flags &= ~0x8D4; + cpu_state.flags |= znptable8[c&0xFF]; + if ((a ^ b) & (a ^ c) & 0x80) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + cpu_state.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; + uint16_t c = (uint16_t)a - (((uint16_t)b) + tempc); + cpu_state.flags &= ~0x8D5; + cpu_state.flags |= znptable8[c&0xFF]; + if (c & 0x100) + cpu_state.flags |= C_FLAG; + if ((a ^ b) & (a ^ c) & 0x80) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + cpu_state.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; + uint32_t c = (uint32_t)a - (uint32_t)b; + cpu_state.flags &= ~0x8D5; + cpu_state.flags |= znptable16[c&0xFFFF]; + if (c & 0x10000) + cpu_state.flags |= C_FLAG; + if ((a ^ b) & (a ^ c) & 0x8000) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + cpu_state.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; + uint32_t c = (uint32_t)a - (uint32_t)b; + cpu_state.flags &= ~0x8D4; + cpu_state.flags |= (znptable16[c&0xFFFF]&~4); + cpu_state.flags |= (znptable8[c&0xFF]&4); + if ((a ^ b) & (a ^ c) & 0x8000) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + cpu_state.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; + uint32_t c = (uint32_t)a - (((uint32_t)b) + tempc); + cpu_state.flags &= ~0x8D5; + cpu_state.flags |= (znptable16[c&0xFFFF]&~4); + cpu_state.flags |= (znptable8[c&0xFF]&4); + if (c & 0x10000) + cpu_state.flags |= C_FLAG; + if ((a ^ b) & (a ^ c) & 0x8000) + cpu_state.flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + cpu_state.flags |= A_FLAG; } int current_diff = 0; -void clockhardware() + +/*XT systems use the XT master oscillator (14.318 MHz) rather than the CPU clock + at the base timer frequency. Because there isn't an integer relationship + between the two frequencies, use fixed point arithmetic when updating TSC.*/ +static uint64_t tsc_frac = 0; + +static void clockhardware() { int diff = cycdiff - cycles - current_diff; current_diff += diff; - - timer_end_period(cycles*xt_cpu_multi); + + tsc_frac += (uint64_t)diff * xt_cpu_multi; + + tsc += (tsc_frac >> 32); + tsc_frac &= 0xffffffff; + if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t)tsc)) + timer_process(); } static int takeint = 0; @@ -814,7 +872,7 @@ static int takeint = 0; int firstrepcycle=1; -void rep(int fv) +static void rep(int fv) { uint8_t temp; int c=CX; @@ -861,8 +919,8 @@ void rep(int fv) { temp2=readmemb(ds+SI); outb(DX,temp2); - if (flags&D_FLAG) SI--; - else SI++; + if (cpu_state.flags & D_FLAG) SI--; + else SI++; c--; cycles-=5; } @@ -875,8 +933,8 @@ void rep(int fv) 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++; } + if (cpu_state.flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } c--; cycles-=17; clockhardware(); @@ -893,8 +951,8 @@ void rep(int fv) memcycs=0; tempw=readmemw(ds,SI); writememw(es,DI,tempw); - if (flags&D_FLAG) { DI-=2; SI-=2; } - else { DI+=2; SI+=2; } + if (cpu_state.flags & D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } c--; cycles-=17; clockhardware(); @@ -906,43 +964,43 @@ void rep(int fv) // } break; case 0xA6: /*REP CMPSB*/ - if (fv) flags|=Z_FLAG; - else flags&=~Z_FLAG; - while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + if (fv) cpu_state.flags |= Z_FLAG; + else cpu_state.flags &= ~Z_FLAG; + while ((c>0) && (fv==((cpu_state.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++; } + if (cpu_state.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 (IRQTEST && c>0 && (fv==((cpu_state.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) + if (fv) cpu_state.flags |= Z_FLAG; + else cpu_state.flags &= ~Z_FLAG; + while ((c>0) && (fv==((cpu_state.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; } + if (cpu_state.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 (IRQTEST && c>0 && (fv==((cpu_state.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); @@ -952,8 +1010,8 @@ void rep(int fv) { memcycs=0; writememb(es+DI,AL); - if (flags&D_FLAG) DI--; - else DI++; + if (cpu_state.flags & D_FLAG) DI--; + else DI++; c--; cycles -= 10; clockhardware(); @@ -968,8 +1026,8 @@ void rep(int fv) { memcycs=0; writememw(es,DI,AX); - if (flags&D_FLAG) DI-=2; - else DI+=2; + if (cpu_state.flags & D_FLAG) DI -= 2; + else DI += 2; c--; cycles -= 10; clockhardware(); @@ -983,8 +1041,8 @@ void rep(int fv) if (c>0) { temp2=readmemb(ds+SI); - if (flags&D_FLAG) SI--; - else SI++; + if (cpu_state.flags & D_FLAG) SI--; + else SI++; c--; cycles-=4; } @@ -995,8 +1053,8 @@ void rep(int fv) if (c>0) { tempw2=readmemw(ds,SI); - if (flags&D_FLAG) SI-=2; - else SI+=2; + if (cpu_state.flags & D_FLAG) SI -= 2; + else SI += 2; c--; cycles-=4; } @@ -1004,37 +1062,37 @@ void rep(int fv) 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))) + if (fv) cpu_state.flags |= Z_FLAG; + else cpu_state.flags &= ~Z_FLAG; + if ((c>0) && (fv==((cpu_state.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++; + if (cpu_state.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 (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + if ((c>0) && (fv==((cpu_state.flags & Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.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))) + if (fv) cpu_state.flags |= Z_FLAG; + else cpu_state.flags &= ~Z_FLAG; + if ((c>0) && (fv==((cpu_state.flags & Z_FLAG)?1:0))) { tempw=readmemw(es,DI); setsub16(AX,tempw); - if (flags&D_FLAG) DI-=2; - else DI+=2; + if (cpu_state.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 (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + if ((c>0) && (fv==((cpu_state.flags & Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } else firstrepcycle=1; break; default: @@ -1053,13 +1111,11 @@ void rep(int fv) } -int inhlt=0; -uint16_t lastpc,lastcs; -int firstrepcycle; -int skipnextprint=0; +static int inhlt=0; +static int skipnextprint=0; + +#include "8087.h" -int instime=0; -//#if 0 void execx86(int cycs) { uint8_t temp,temp2; @@ -1077,25 +1133,20 @@ void execx86(int 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); + uint8_t opcode; + 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; cpu_state.oldpc = cpu_state.pc; opcodestart: opcode=FETCH(); - tempc=flags&C_FLAG; - trap=flags&T_FLAG; + tempc = cpu_state.flags & C_FLAG; + trap = cpu_state.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); @@ -1104,7 +1155,7 @@ void execx86(int cycs) { // 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]); + 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,cpu_state.flags, ins, ram, ram[0x1a925]); skipnextprint=0; // ins++; // } @@ -1174,7 +1225,7 @@ void execx86(int cycs) case 0x07: /*POP ES*/ if (cpu_state.ssegs) ss=oldss; tempw=readmemw(ss,SP); - loadseg(tempw,&_es); + loadseg(tempw,&cpu_state.seg_es); SP+=2; cycles-=12; break; @@ -1184,7 +1235,7 @@ void execx86(int cycs) temp=geteab(); temp|=getr8(cpu_reg); setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteab(temp); cycles-=((cpu_mod==3)?3:24); break; @@ -1193,7 +1244,7 @@ void execx86(int cycs) tempw=geteaw(); tempw|=cpu_state.regs[cpu_reg].w; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteaw(tempw); cycles-=((cpu_mod==3)?3:24); break; @@ -1202,7 +1253,7 @@ void execx86(int cycs) temp=geteab(); temp|=getr8(cpu_reg); setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); setr8(cpu_reg,temp); cycles-=((cpu_mod==3)?3:13); break; @@ -1211,20 +1262,20 @@ void execx86(int cycs) tempw=geteaw(); tempw|=cpu_state.regs[cpu_reg].w; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cpu_state.regs[cpu_reg].w=tempw; cycles-=((cpu_mod==3)?3:13); break; case 0x0C: /*OR AL,#8*/ AL|=FETCH(); setznp8(AL); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.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); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cycles-=4; break; @@ -1237,7 +1288,7 @@ void execx86(int cycs) case 0x0F: /*POP CS - 8088/8086 only*/ if (cpu_state.ssegs) ss=oldss; tempw=readmemw(ss,SP); - loadseg(tempw,&_cs); + loadseg(tempw,&cpu_state.seg_cs); SP+=2; cycles-=12; break; @@ -1296,7 +1347,7 @@ void execx86(int cycs) case 0x17: /*POP SS*/ if (cpu_state.ssegs) ss=oldss; tempw=readmemw(ss,SP); - loadseg(tempw,&_ss); + loadseg(tempw,&cpu_state.seg_ss); SP+=2; noint=1; cycles-=12; @@ -1361,7 +1412,7 @@ void execx86(int cycs) case 0x1F: /*POP DS*/ if (cpu_state.ssegs) ss=oldss; tempw=readmemw(ss,SP); - loadseg(tempw,&_ds); + loadseg(tempw,&cpu_state.seg_ds); if (cpu_state.ssegs) oldds=ds; SP+=2; cycles-=12; @@ -1372,7 +1423,7 @@ void execx86(int cycs) temp=geteab(); temp&=getr8(cpu_reg); setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteab(temp); cycles-=((cpu_mod==3)?3:24); break; @@ -1381,7 +1432,7 @@ void execx86(int cycs) tempw=geteaw(); tempw&=cpu_state.regs[cpu_reg].w; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteaw(tempw); cycles-=((cpu_mod==3)?3:24); break; @@ -1390,7 +1441,7 @@ void execx86(int cycs) temp=geteab(); temp&=getr8(cpu_reg); setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); setr8(cpu_reg,temp); cycles-=((cpu_mod==3)?3:13); break; @@ -1399,20 +1450,20 @@ void execx86(int cycs) tempw=geteaw(); tempw&=cpu_state.regs[cpu_reg].w; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cpu_state.regs[cpu_reg].w=tempw; cycles-=((cpu_mod==3)?3:13); break; case 0x24: /*AND AL,#8*/ AL&=FETCH(); setznp8(AL); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.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); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cycles-=4; break; @@ -1426,19 +1477,20 @@ void execx86(int cycs) // break; case 0x27: /*DAA*/ - if ((flags&A_FLAG) || ((AL&0xF)>9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { - tempi=((uint16_t)AL)+6; - AL+=6; - flags|=A_FLAG; - if (tempi&0x100) flags|=C_FLAG; + tempi = ((uint16_t)AL) + 6; + AL += 6; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) + cpu_state.flags |= C_FLAG; } // else // flags&=~A_FLAG; - if ((flags&C_FLAG) || (AL>0x9F)) + if ((cpu_state.flags & C_FLAG) || (AL > 0x9F)) { - AL+=0x60; - flags|=C_FLAG; + AL += 0x60; + cpu_state.flags |= C_FLAG; } // else // flags&=~C_FLAG; @@ -1500,19 +1552,20 @@ void execx86(int cycs) cycles-=4; goto opcodestart; case 0x2F: /*DAS*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { - tempi=((uint16_t)AL)-6; - AL-=6; - flags|=A_FLAG; - if (tempi&0x100) flags|=C_FLAG; + tempi = ((uint16_t)AL) - 6; + AL -= 6; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) + cpu_state.flags |= C_FLAG; } // else // flags&=~A_FLAG; - if ((flags&C_FLAG)||(AL>0x9F)) + if ((cpu_state.flags & C_FLAG) || (AL > 0x9F)) { - AL-=0x60; - flags|=C_FLAG; + AL -= 0x60; + cpu_state.flags |= C_FLAG; } // else // flags&=~C_FLAG; @@ -1524,7 +1577,7 @@ void execx86(int cycs) temp=geteab(); temp^=getr8(cpu_reg); setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteab(temp); cycles-=((cpu_mod==3)?3:24); break; @@ -1533,7 +1586,7 @@ void execx86(int cycs) tempw=geteaw(); tempw^=cpu_state.regs[cpu_reg].w; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteaw(tempw); cycles-=((cpu_mod==3)?3:24); break; @@ -1542,7 +1595,7 @@ void execx86(int cycs) temp=geteab(); temp^=getr8(cpu_reg); setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); setr8(cpu_reg,temp); cycles-=((cpu_mod==3)?3:13); break; @@ -1551,20 +1604,20 @@ void execx86(int cycs) tempw=geteaw(); tempw^=cpu_state.regs[cpu_reg].w; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cpu_state.regs[cpu_reg].w=tempw; cycles-=((cpu_mod==3)?3:13); break; case 0x34: /*XOR AL,#8*/ AL^=FETCH(); setznp8(AL); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.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); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cycles-=4; break; @@ -1578,16 +1631,16 @@ void execx86(int cycs) // break; case 0x37: /*AAA*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) + if ((cpu_state.flags & A_FLAG)||((AL & 0xF) > 9)) { - AL+=6; + AL += 6; AH++; - flags|=(A_FLAG|C_FLAG); + cpu_state.flags |= (A_FLAG|C_FLAG); } else - flags&=~(A_FLAG|C_FLAG); - AL&=0xF; - cycles-=8; + cpu_state.flags &= ~(A_FLAG|C_FLAG); + AL &= 0xF; + cycles -= 8; break; case 0x38: /*CMP 8,reg*/ @@ -1639,16 +1692,16 @@ void execx86(int cycs) // break; case 0x3F: /*AAS*/ - if ((flags&A_FLAG)||((AL&0xF)>9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { - AL-=6; + AL -= 6; AH--; - flags|=(A_FLAG|C_FLAG); + cpu_state.flags |= (A_FLAG|C_FLAG); } else - flags&=~(A_FLAG|C_FLAG); - AL&=0xF; - cycles-=8; + cpu_state.flags &= ~(A_FLAG|C_FLAG); + AL &= 0xF; + cycles -= 8; break; case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ @@ -1683,105 +1736,105 @@ void execx86(int cycs) case 0x60: /*JO alias*/ case 0x70: /*JO*/ offset=(int8_t)FETCH(); - if (flags&V_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + if (cpu_state.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(); } + if (!(cpu_state.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(); } + if (cpu_state.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(); } + if (!(cpu_state.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(); } + if (cpu_state.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(); } + if (!(cpu_state.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(); } + if (cpu_state.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(); } + if (!(cpu_state.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(); } + if (cpu_state.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(); } + if (!(cpu_state.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(); } + if (cpu_state.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(); } + if (!(cpu_state.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; + temp=(cpu_state.flags & N_FLAG)?1:0; + temp2=(cpu_state.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; + temp=(cpu_state.flags & N_FLAG)?1:0; + temp2=(cpu_state.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(); } + temp=(cpu_state.flags & N_FLAG)?1:0; + temp2=(cpu_state.flags & V_FLAG)?1:0; + if ((cpu_state.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(); } + temp=(cpu_state.flags & N_FLAG)?1:0; + temp2=(cpu_state.flags & V_FLAG)?1:0; + if (!((cpu_state.flags & Z_FLAG) || (temp!=temp2))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } cycles-=4; break; @@ -1799,7 +1852,7 @@ void execx86(int cycs) case 0x08: /*OR b,#8*/ temp|=temp2; setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteab(temp); cycles-=((cpu_mod==3)?4:23); break; @@ -1818,7 +1871,7 @@ void execx86(int cycs) case 0x20: /*AND b,#8*/ temp&=temp2; setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteab(temp); cycles-=((cpu_mod==3)?4:23); break; @@ -1830,7 +1883,7 @@ void execx86(int cycs) case 0x30: /*XOR b,#8*/ temp^=temp2; setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteab(temp); cycles-=((cpu_mod==3)?4:23); break; @@ -1861,7 +1914,7 @@ void execx86(int cycs) case 0x08: /*OR w,#16*/ tempw|=tempw2; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteaw(tempw); cycles-=((cpu_mod==3)?4:23); break; @@ -1875,7 +1928,7 @@ void execx86(int cycs) case 0x20: /*AND w,#16*/ tempw&=tempw2; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteaw(tempw); cycles-=((cpu_mod==3)?4:23); break; @@ -1894,7 +1947,7 @@ void execx86(int cycs) case 0x30: /*XOR w,#16*/ tempw^=tempw2; setznp16(tempw); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); seteaw(tempw); cycles-=((cpu_mod==3)?4:23); break; @@ -1928,7 +1981,7 @@ void execx86(int cycs) tempw|=tempw2; setznp16(tempw); seteaw(tempw); - flags&=~(C_FLAG|A_FLAG|V_FLAG); + cpu_state.flags &= ~(C_FLAG|A_FLAG|V_FLAG); cycles-=((cpu_mod==3)?4:23); break; case 0x10: /*ADC w,#8*/ @@ -1950,7 +2003,7 @@ void execx86(int cycs) setznp16(tempw); seteaw(tempw); cycles-=((cpu_mod==3)?4:23); - flags&=~(C_FLAG|A_FLAG|V_FLAG); + cpu_state.flags &= ~(C_FLAG|A_FLAG|V_FLAG); break; case 0x28: /*SUB w,#8*/ setsub16(tempw,tempw2); @@ -1963,7 +2016,7 @@ void execx86(int cycs) setznp16(tempw); seteaw(tempw); cycles-=((cpu_mod==3)?4:23); - flags&=~(C_FLAG|A_FLAG|V_FLAG); + cpu_state.flags &= ~(C_FLAG|A_FLAG|V_FLAG); break; case 0x38: /*CMP w,#8*/ setsub16(tempw,tempw2); @@ -1982,7 +2035,7 @@ void execx86(int cycs) temp=geteab(); temp2=getr8(cpu_reg); setznp8(temp&temp2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cycles-=((cpu_mod==3)?3:13); break; case 0x85: /*TEST w,reg*/ @@ -1990,7 +2043,7 @@ void execx86(int cycs) tempw=geteaw(); tempw2=cpu_state.regs[cpu_reg].w; setznp16(tempw&tempw2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cycles-=((cpu_mod==3)?3:13); break; case 0x86: /*XCHG b,reg*/ @@ -2067,20 +2120,20 @@ void execx86(int cycs) { case 0x00: /*ES*/ tempw=geteaw(); - loadseg(tempw,&_es); + loadseg(tempw,&cpu_state.seg_es); break; case 0x08: /*CS - 8088/8086 only*/ tempw=geteaw(); - loadseg(tempw,&_cs); + loadseg(tempw,&cpu_state.seg_cs); break; case 0x18: /*DS*/ tempw=geteaw(); - loadseg(tempw,&_ds); + loadseg(tempw,&cpu_state.seg_ds); if (cpu_state.ssegs) oldds=ds; break; case 0x10: /*SS*/ tempw=geteaw(); - loadseg(tempw,&_ss); + loadseg(tempw,&cpu_state.seg_ss); if (cpu_state.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); @@ -2140,22 +2193,22 @@ void execx86(int cycs) break; case 0x9C: /*PUSHF*/ if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss, ((SP-2)&0xFFFF), cpu_state.flags | 0xF000); SP-=2; cycles-=14; break; case 0x9D: /*POPF*/ if (cpu_state.ssegs) ss=oldss; - flags=readmemw(ss,SP)&0xFFF; + cpu_state.flags = readmemw(ss,SP) & 0xFFF; SP+=2; cycles-=12; break; case 0x9E: /*SAHF*/ - flags=(flags&0xFF00)|AH; + cpu_state.flags = (cpu_state.flags & 0xFF00) | AH; cycles-=4; break; case 0x9F: /*LAHF*/ - AH=flags&0xFF; + AH = cpu_state.flags & 0xFF; cycles-=4; break; @@ -2168,7 +2221,7 @@ void execx86(int cycs) addr=getword(); // printf("Reading AX from %05X %04X:%04X\n",ds+addr,ds>>4,addr); AX=readmemw(ds,addr); - cycles-=!4; + cycles-=14; break; case 0xA2: /*MOV (w),AL*/ addr=getword(); @@ -2185,23 +2238,23 @@ void execx86(int cycs) case 0xA4: /*MOVSB*/ temp=readmemb(ds+SI); writememb(es+DI,temp); - if (flags&D_FLAG) { DI--; SI--; } - else { DI++; SI++; } + if (cpu_state.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; } + if (cpu_state.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++; } + if (cpu_state.flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } cycles-=30; break; case 0xA7: /*CMPSW*/ @@ -2209,60 +2262,60 @@ void execx86(int cycs) 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; } + if (cpu_state.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); + cpu_state.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); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cycles-=5; break; case 0xAA: /*STOSB*/ writememb(es+DI,AL); - if (flags&D_FLAG) DI--; - else DI++; + if (cpu_state.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; + if (cpu_state.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++; + if (cpu_state.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; + if (cpu_state.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++; + if (cpu_state.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; + if (cpu_state.flags & D_FLAG) DI -= 2; + else DI += 2; cycles-=19; break; @@ -2329,14 +2382,14 @@ void execx86(int cycs) fetchea(); cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); //geteaw(); tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); //geteaw2(); - loadseg(tempw,&_es); + loadseg(tempw,&cpu_state.seg_es); cycles-=24; break; case 0xC5: /*LDS*/ fetchea(); cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); - loadseg(tempw,&_ds); + loadseg(tempw,&cpu_state.seg_ds); if (cpu_state.ssegs) oldds=ds; cycles-=24; break; @@ -2377,13 +2430,13 @@ void execx86(int cycs) break; case 0xCC: /*INT 3*/ if (cpu_state.ssegs) ss=oldss; - writememw(ss,((SP-2)&0xFFFF),flags|0xF000); - writememw(ss,((SP-4)&0xFFFF),CS); - writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + writememw(ss, ((SP-2)&0xFFFF), cpu_state.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; + cpu_state.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; // printf("CC %04X:%04X ",CS,pc); cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); @@ -2392,15 +2445,13 @@ void execx86(int cycs) cycles-=72; break; case 0xCD: /*INT*/ - lastpc=cpu_state.pc; - lastcs=CS; temp=FETCH(); if (cpu_state.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; + writememw(ss, ((SP-2)&0xFFFF), cpu_state.flags | 0xF000); + writememw(ss, ((SP-4)&0xFFFF), CS); + writememw(ss, ((SP-6)&0xFFFF), cpu_state.pc); + cpu_state.flags &= ~T_FLAG; SP-=6; addr=temp<<2; cpu_state.pc=readmemw(0,addr); @@ -2417,7 +2468,7 @@ void execx86(int cycs) cpu_state.pc=readmemw(ss,SP); // printf("CF\n"); loadcs(readmemw(ss,((SP+2)&0xFFFF))); - flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; + cpu_state.flags = readmemw(ss,((SP+4)&0xFFFF))&0xFFF; SP+=6; cycles-=44; FETCHCLEAR(); @@ -2429,83 +2480,85 @@ void execx86(int cycs) switch (rmdat&0x38) { case 0x00: /*ROL b,1*/ - if (temp&0x80) flags|=C_FLAG; - else flags&=~C_FLAG; + if (temp&0x80) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; temp<<=1; - if (flags&C_FLAG) temp|=1; + if (cpu_state.flags & C_FLAG) + temp |= 1; seteab(temp); // setznp8(temp); - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((cpu_state.flags&C_FLAG) ^ (temp >> 7)) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?2:23); break; case 0x08: /*ROR b,1*/ - if (temp&1) flags|=C_FLAG; - else flags&=~C_FLAG; + if (temp&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; temp>>=1; - if (flags&C_FLAG) temp|=0x80; + if (cpu_state.flags & C_FLAG) + temp |= 0x80; seteab(temp); // setznp8(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((temp^(temp>>1))&0x40) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?2:23); break; case 0x10: /*RCL b,1*/ - temp2=flags&C_FLAG; - if (temp&0x80) flags|=C_FLAG; - else flags&=~C_FLAG; + temp2 = cpu_state.flags & C_FLAG; + if (temp&0x80) cpu_state.flags |= C_FLAG; + else cpu_state.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; + if ((cpu_state.flags & C_FLAG)^(temp>>7)) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?2:23); break; case 0x18: /*RCR b,1*/ - temp2=flags&C_FLAG; - if (temp&1) flags|=C_FLAG; - else flags&=~C_FLAG; + temp2 = cpu_state.flags & C_FLAG; + if (temp&1) cpu_state.flags |= C_FLAG; + else cpu_state.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; + if ((temp^(temp>>1))&0x40) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_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; + if (temp&0x80) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + if ((temp^(temp<<1))&0x80) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; temp<<=1; seteab(temp); setznp8(temp); cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; + cpu_state.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; + if (temp&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + if (temp&0x80) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; temp>>=1; seteab(temp); setznp8(temp); cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; + cpu_state.flags |= A_FLAG; break; case 0x38: /*SAR b,1*/ - if (temp&1) flags|=C_FLAG; - else flags&=~C_FLAG; + if (temp&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; temp>>=1; if (temp&0x40) temp|=0x80; seteab(temp); setznp8(temp); cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - flags&=~V_FLAG; + cpu_state.flags |= A_FLAG; + cpu_state.flags &= ~V_FLAG; break; // default: @@ -2521,83 +2574,83 @@ void execx86(int cycs) switch (rmdat&0x38) { case 0x00: /*ROL w,1*/ - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; + if (tempw&0x8000) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; tempw<<=1; - if (flags&C_FLAG) tempw|=1; + if (cpu_state.flags & C_FLAG) tempw|=1; seteaw(tempw); // setznp16(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((cpu_state.flags & C_FLAG)^(tempw>>15)) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?2:23); break; case 0x08: /*ROR w,1*/ - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; + if (tempw&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; tempw>>=1; - if (flags&C_FLAG) tempw|=0x8000; + if (cpu_state.flags & C_FLAG) tempw|=0x8000; seteaw(tempw); // setznp16(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((tempw^(tempw>>1))&0x4000) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?2:23); break; case 0x10: /*RCL w,1*/ - temp2=flags&C_FLAG; - if (tempw&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; + temp2 = cpu_state.flags & C_FLAG; + if (tempw&0x8000) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; tempw<<=1; if (temp2) tempw|=1; seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((cpu_state.flags & C_FLAG)^(tempw>>15)) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?2:23); break; case 0x18: /*RCR w,1*/ - temp2=flags&C_FLAG; - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; + temp2 = cpu_state.flags & C_FLAG; + if (tempw&1) cpu_state.flags |= C_FLAG; + else cpu_state.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; + if ((tempw^(tempw>>1))&0x4000) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_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; + if (tempw&0x8000) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + if ((tempw^(tempw<<1))&0x8000) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; tempw<<=1; seteaw(tempw); setznp16(tempw); cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; + cpu_state.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; + if (tempw&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + if (tempw&0x8000) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; tempw>>=1; seteaw(tempw); setznp16(tempw); cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; + cpu_state.flags |= A_FLAG; break; case 0x38: /*SAR w,1*/ - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; + if (tempw&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; tempw>>=1; if (tempw&0x4000) tempw|=0x8000; seteaw(tempw); setznp16(tempw); cycles-=((cpu_mod==3)?2:23); - flags|=A_FLAG; - flags&=~V_FLAG; + cpu_state.flags |= A_FLAG; + cpu_state.flags &= ~V_FLAG; break; // default: @@ -2624,12 +2677,12 @@ void execx86(int cycs) c--; cycles-=4; } - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; + if (temp2) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; seteab(temp); // setznp8(temp); - if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((cpu_state.flags & C_FLAG)^(temp>>7)) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?8:28); break; case 0x08: /*ROR b,CL*/ @@ -2641,40 +2694,40 @@ void execx86(int cycs) c--; cycles-=4; } - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; + if (temp2) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; seteab(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((temp^(temp>>1))&0x40) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_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; + templ=cpu_state.flags & C_FLAG; temp2=temp&0x80; temp<<=1; - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; + if (temp2) cpu_state.flags |= C_FLAG; + else cpu_state.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; + if ((cpu_state.flags & C_FLAG)^(temp>>7)) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?8:28); break; case 0x18: /*RCR b,CL*/ while (c>0) { - templ=flags&C_FLAG; + templ=cpu_state.flags & C_FLAG; temp2=temp&1; temp>>=1; - if (temp2) flags|=C_FLAG; - else flags&=~C_FLAG; + if (temp2) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; if (templ) temp|=0x80; c--; cycles-=4; @@ -2682,33 +2735,49 @@ void execx86(int cycs) // if (temp2) flags|=C_FLAG; // else flags&=~C_FLAG; seteab(temp); - if ((temp^(temp>>1))&0x40) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((temp^(temp>>1))&0x40) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_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; + if (c > 8) + { + temp = 0; + cpu_state.flags &= ~C_FLAG; + } + else + { + if ((temp<<(c-1))&0x80) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + temp<<=c; + } seteab(temp); setznp8(temp); cycles-=(c*4); cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; + cpu_state.flags |= A_FLAG; break; case 0x28: /*SHR b,CL*/ - if ((temp>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - temp>>=c; + if (c > 8) + { + temp = 0; + cpu_state.flags &= ~C_FLAG; + } + else + { + if ((temp>>(c-1))&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + temp>>=c; + } seteab(temp); setznp8(temp); cycles-=(c*4); cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; + cpu_state.flags |= A_FLAG; break; case 0x38: /*SAR b,CL*/ - if ((temp>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; + if ((temp>>(c-1))&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; while (c>0) { temp>>=1; @@ -2719,7 +2788,7 @@ void execx86(int cycs) seteab(temp); setznp8(temp); cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; + cpu_state.flags |= A_FLAG; break; // default: @@ -2746,11 +2815,11 @@ void execx86(int cycs) c--; cycles-=4; } - if (temp) flags|=C_FLAG; - else flags&=~C_FLAG; + if (temp) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((cpu_state.flags & C_FLAG)^(tempw>>15)) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?8:28); break; case 0x08: /*ROR w,CL*/ @@ -2761,46 +2830,46 @@ void execx86(int cycs) c--; cycles-=4; } - if (tempw2) flags|=C_FLAG; - else flags&=~C_FLAG; + if (tempw2) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((tempw^(tempw>>1))&0x4000) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_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; + templ = cpu_state.flags & C_FLAG; + if (tempw&0x8000) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; tempw=(tempw<<1)|templ; c--; cycles-=4; } - if (templ) flags|=C_FLAG; - else flags&=~C_FLAG; + if (templ) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; seteaw(tempw); - if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((cpu_state.flags & C_FLAG)^(tempw>>15)) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?8:28); break; case 0x18: /*RCR w,CL*/ while (c>0) { - templ=flags&C_FLAG; + templ = cpu_state.flags & C_FLAG; tempw2=(templ&1)?0x8000:0; - if (tempw&1) flags|=C_FLAG; - else flags&=~C_FLAG; + if (tempw&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; tempw=(tempw>>1)|tempw2; c--; cycles-=4; } - if (tempw2) flags|=C_FLAG; - else flags&=~C_FLAG; + if (tempw2) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; seteaw(tempw); - if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; - else flags&=~V_FLAG; + if ((tempw^(tempw>>1))&0x4000) cpu_state.flags |= V_FLAG; + else cpu_state.flags &= ~V_FLAG; cycles-=((cpu_mod==3)?8:28); break; @@ -2808,36 +2877,44 @@ void execx86(int cycs) if (c>16) { tempw=0; - flags&=~C_FLAG; + cpu_state.flags &= ~C_FLAG; } else { - if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; - else flags&=~C_FLAG; + if ((tempw<<(c-1))&0x8000) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; tempw<<=c; } seteaw(tempw); setznp16(tempw); cycles-=(c*4); cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; + cpu_state.flags |= A_FLAG; break; case 0x28: /*SHR w,CL*/ - if ((tempw>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; - tempw>>=c; + if (c > 16) + { + tempw = 0; + cpu_state.flags &= ~C_FLAG; + } + else + { + if ((tempw>>(c-1))&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; + tempw>>=c; + } seteaw(tempw); setznp16(tempw); cycles-=(c*4); cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; + cpu_state.flags |= A_FLAG; break; case 0x38: /*SAR w,CL*/ tempw2=tempw&0x8000; - if ((tempw>>(c-1))&1) flags|=C_FLAG; - else flags&=~C_FLAG; + if ((tempw>>(c-1))&1) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; while (c>0) { tempw=(tempw>>1)|tempw2; @@ -2847,7 +2924,7 @@ void execx86(int cycs) seteaw(tempw); setznp16(tempw); cycles-=((cpu_mod==3)?8:28); - flags|=A_FLAG; + cpu_state.flags |= A_FLAG; break; // default: @@ -2872,7 +2949,7 @@ void execx86(int cycs) cycles-=60; break; case 0xD6: /*SETALC*/ - AL = (flags & C_FLAG) ? 0xff : 0; + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0; cycles -= 4; break; case 0xD7: /*XLAT*/ @@ -2880,22 +2957,90 @@ void execx86(int cycs) AL=readmemb(ds+addr); cycles-=11; break; - case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ - case 0xDC: case 0xDE: case 0xDF: case 0xD8: + + case 0xd8: fetchea(); - geteab(); + if (hasfpu) + { + uint16_t save_pc = cpu_state.pc; + ops_808x_fpu_d8_a16[rmdat >> 3](rmdat); + cpu_state.pc = save_pc; + } + break; + case 0xd9: + fetchea(); + if (hasfpu) + { + uint16_t save_pc = cpu_state.pc; + ops_808x_fpu_d9_a16[rmdat](rmdat); + cpu_state.pc = save_pc; + } + break; + case 0xda: + fetchea(); + if (hasfpu) + { + uint16_t save_pc = cpu_state.pc; + ops_808x_fpu_da_a16[rmdat](rmdat); + cpu_state.pc = save_pc; + } + break; + case 0xdb: + fetchea(); + if (hasfpu) + { + uint16_t save_pc = cpu_state.pc; + ops_808x_fpu_db_a16[rmdat](rmdat); + cpu_state.pc = save_pc; + } + break; + case 0xdc: + fetchea(); + if (hasfpu) + { + uint16_t save_pc = cpu_state.pc; + ops_808x_fpu_dc_a16[rmdat >> 3](rmdat); + cpu_state.pc = save_pc; + } + break; + case 0xdd: + fetchea(); + if (hasfpu) + { + uint16_t save_pc = cpu_state.pc; + ops_808x_fpu_dd_a16[rmdat](rmdat); + cpu_state.pc = save_pc; + } + break; + case 0xde: + fetchea(); + if (hasfpu) + { + uint16_t save_pc = cpu_state.pc; + ops_808x_fpu_de_a16[rmdat](rmdat); + cpu_state.pc = save_pc; + } + break; + case 0xdf: + fetchea(); + if (hasfpu) + { + uint16_t save_pc = cpu_state.pc; + ops_808x_fpu_df_a16[rmdat](rmdat); + cpu_state.pc = save_pc; + } break; case 0xE0: /*LOOPNE*/ offset=(int8_t)FETCH(); CX--; - if (CX && !(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + if (CX && !(cpu_state.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(); } + if (CX && (cpu_state.flags & Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } cycles-=6; break; case 0xE2: /*LOOP*/ @@ -3002,7 +3147,7 @@ void execx86(int cycs) break; case 0xF4: /*HLT*/ -// printf("IN HLT!!!! %04X:%04X %08X %08X %08X\n",oldcs,oldpc,old8,old82,old83); +// printf("IN HLT!!!! %04X %08X %08X %08X\n",oldpc,old8,old82,old83); /* if (!(flags & I_FLAG)) { pclog("HLT\n"); @@ -3015,7 +3160,7 @@ void execx86(int cycs) cycles-=2; break; case 0xF5: /*CMC*/ - flags^=C_FLAG; + cpu_state.flags ^= C_FLAG; cycles-=2; break; @@ -3029,7 +3174,7 @@ void execx86(int cycs) temp2=FETCH(); temp&=temp2; setznp8(temp); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cycles-=((cpu_mod==3)?5:11); break; case 0x10: /*NOT b*/ @@ -3046,20 +3191,20 @@ void execx86(int cycs) 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); + if (AX) cpu_state.flags &= ~Z_FLAG; + else cpu_state.flags |= Z_FLAG; + if (AH) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.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); + if (AX) cpu_state.flags &= ~Z_FLAG; + else cpu_state.flags |= Z_FLAG; + if (AH) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.flags &= ~(C_FLAG|V_FLAG); cycles-=80; break; case 0x30: /*DIV AL,b*/ @@ -3090,12 +3235,12 @@ void execx86(int cycs) else { printf("DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc=readmemw(0,0); // printf("F6 30\n"); loadcs(readmemw(0,2)); @@ -3134,12 +3279,12 @@ void execx86(int cycs) else { printf("IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc=readmemw(0,0); // printf("F6 38\n"); loadcs(readmemw(0,2)); @@ -3167,7 +3312,7 @@ void execx86(int cycs) case 0x08: tempw2=getword(); setznp16(tempw&tempw2); - flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.flags &= ~(C_FLAG|V_FLAG|A_FLAG); cycles-=((cpu_mod==3)?5:11); break; case 0x10: /*NOT w*/ @@ -3186,18 +3331,18 @@ void execx86(int cycs) // 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); + if (AX|DX) cpu_state.flags &= ~Z_FLAG; + else cpu_state.flags |= Z_FLAG; + if (DX) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.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); + if ((tempws>>15) && ((tempws>>15)!=-1)) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.flags &= ~(C_FLAG|V_FLAG); // printf("%i ",tempws); AX=tempws&0xFFFF; tempws=(uint16_t)(tempws>>16); @@ -3205,8 +3350,8 @@ void execx86(int cycs) // printf("%04X %04X\n",AX,DX); // dumpregs(); // exit(-1); - if (AX|DX) flags&=~Z_FLAG; - else flags|=Z_FLAG; + if (AX|DX) cpu_state.flags &= ~Z_FLAG; + else cpu_state.flags |= Z_FLAG; cycles-=128; break; case 0x30: /*DIV AX,w*/ @@ -3222,12 +3367,12 @@ void execx86(int cycs) else { printf("DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc=readmemw(0,0); // printf("F7 30\n"); loadcs(readmemw(0,2)); @@ -3249,12 +3394,12 @@ void execx86(int cycs) else { printf("IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); - writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-2)&0xFFFF,cpu_state.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.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc=readmemw(0,0); // printf("F7 38\n"); loadcs(readmemw(0,2)); @@ -3271,48 +3416,48 @@ void execx86(int cycs) break; case 0xF8: /*CLC*/ - flags&=~C_FLAG; + cpu_state.flags &= ~C_FLAG; cycles-=2; break; case 0xF9: /*STC*/ // printf("STC %04X\n",pc); - flags|=C_FLAG; + cpu_state.flags |= C_FLAG; cycles-=2; break; case 0xFA: /*CLI*/ - flags&=~I_FLAG; + cpu_state.flags &= ~I_FLAG; // printf("CLI at %04X:%04X\n",cs>>4,pc); cycles-=3; break; case 0xFB: /*STI*/ - flags|=I_FLAG; + cpu_state.flags |= I_FLAG; // printf("STI at %04X:%04X\n",cs>>4,pc); cycles-=2; break; case 0xFC: /*CLD*/ - flags&=~D_FLAG; + cpu_state.flags &= ~D_FLAG; cycles-=2; break; case 0xFD: /*STD*/ - flags|=D_FLAG; + cpu_state.flags |= D_FLAG; cycles-=2; break; case 0xFE: /*INC/DEC b*/ fetchea(); temp=geteab(); - flags&=~V_FLAG; + cpu_state.flags &= ~V_FLAG; if (rmdat&0x38) { setsub8nc(temp,1); temp2=temp-1; - if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + if ((temp&0x80) && !(temp2&0x80)) cpu_state.flags |= V_FLAG; } else { setadd8nc(temp,1); temp2=temp+1; - if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + if ((temp2&0x80) && !(temp&0x80)) cpu_state.flags |= V_FLAG; } // setznp8(temp2); seteab(temp2); @@ -3429,14 +3574,6 @@ void execx86(int cycs) // if (instime) printf("%i %i %i %i\n",cycdiff,cycles,memcycs,fetchclocks); FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); if ((cycdiff-cycles) dosbox/$(am__dirstamp) +dosbox/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) dosbox/$(DEPDIR) + @: > dosbox/$(DEPDIR)/$(am__dirstamp) +dosbox/pcem-cdrom_image.$(OBJEXT): dosbox/$(am__dirstamp) \ + dosbox/$(DEPDIR)/$(am__dirstamp) +dosbox/pcem-dbopl.$(OBJEXT): dosbox/$(am__dirstamp) \ + dosbox/$(DEPDIR)/$(am__dirstamp) +dosbox/pcem-nukedopl.$(OBJEXT): dosbox/$(am__dirstamp) \ + dosbox/$(DEPDIR)/$(am__dirstamp) +dosbox/pcem-vid_cga_comp.$(OBJEXT): dosbox/$(am__dirstamp) \ + dosbox/$(DEPDIR)/$(am__dirstamp) +resid-fp/$(am__dirstamp): + @$(MKDIR_P) resid-fp + @: > resid-fp/$(am__dirstamp) +resid-fp/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) resid-fp/$(DEPDIR) + @: > resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-convolve.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-convolve-sse.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-envelope.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-extfilt.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-filter.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-pot.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-sid.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-voice.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave6581_PS_.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave6581_PST.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave6581_P_T.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave6581__ST.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave8580_PS_.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave8580_PST.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave8580_P_T.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave8580__ST.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +resid-fp/pcem-wave.$(OBJEXT): resid-fp/$(am__dirstamp) \ + resid-fp/$(DEPDIR)/$(am__dirstamp) +minivhd/$(am__dirstamp): + @$(MKDIR_P) minivhd + @: > minivhd/$(am__dirstamp) +minivhd/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) minivhd/$(DEPDIR) + @: > minivhd/$(DEPDIR)/$(am__dirstamp) +minivhd/pcem-cwalk.$(OBJEXT): minivhd/$(am__dirstamp) \ + minivhd/$(DEPDIR)/$(am__dirstamp) +minivhd/pcem-libxml2_encoding.$(OBJEXT): minivhd/$(am__dirstamp) \ + minivhd/$(DEPDIR)/$(am__dirstamp) +minivhd/pcem-minivhd_convert.$(OBJEXT): minivhd/$(am__dirstamp) \ + minivhd/$(DEPDIR)/$(am__dirstamp) +minivhd/pcem-minivhd_create.$(OBJEXT): minivhd/$(am__dirstamp) \ + minivhd/$(DEPDIR)/$(am__dirstamp) +minivhd/pcem-minivhd_io.$(OBJEXT): minivhd/$(am__dirstamp) \ + minivhd/$(DEPDIR)/$(am__dirstamp) +minivhd/pcem-minivhd_manage.$(OBJEXT): minivhd/$(am__dirstamp) \ + minivhd/$(DEPDIR)/$(am__dirstamp) +minivhd/pcem-minivhd_struct_rw.$(OBJEXT): minivhd/$(am__dirstamp) \ + minivhd/$(DEPDIR)/$(am__dirstamp) +minivhd/pcem-minivhd_util.$(OBJEXT): minivhd/$(am__dirstamp) \ + minivhd/$(DEPDIR)/$(am__dirstamp) +slirp/$(am__dirstamp): + @$(MKDIR_P) slirp + @: > slirp/$(am__dirstamp) +slirp/$(DEPDIR)/$(am__dirstamp): + @$(MKDIR_P) slirp/$(DEPDIR) + @: > slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-bootp.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-cksum.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-debug.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-if.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-ip_icmp.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-ip_input.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-ip_output.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-mbuf.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-misc.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-queue.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-sbuf.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-slirp.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-socket.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-tcp_input.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-tcp_output.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-tcp_subr.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-tcp_timer.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-tftp.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) +slirp/pcem-udp.$(OBJEXT): slirp/$(am__dirstamp) \ + slirp/$(DEPDIR)/$(am__dirstamp) pcem$(EXEEXT): $(pcem_OBJECTS) $(pcem_DEPENDENCIES) $(EXTRA_pcem_DEPENDENCIES) @rm -f pcem$(EXEEXT) - $(AM_V_CXXLD)$(CXXLINK) $(pcem_OBJECTS) $(pcem_LDADD) $(LIBS) + $(AM_V_CXXLD)$(pcem_LINK) $(pcem_OBJECTS) $(pcem_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) + -rm -f dosbox/*.$(OBJEXT) + -rm -f minivhd/*.$(OBJEXT) + -rm -f resid-fp/*.$(OBJEXT) + -rm -f slirp/*.$(OBJEXT) distclean-compile: -rm -f *.tab.c -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convolve-sse.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convolve.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbopl.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)/pcem-386.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386_dynarec.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386_dynarec_ops.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-808x.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-acer386sx.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ali1429.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-gui-config-sel.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-gui-configure.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-gui-deviceconfig.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-gui-hdconf.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-gui.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-joystick.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-keyboard.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-main.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-midi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-mouse.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-allegro-video.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-amstrad.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-ioctl-linux.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-iso.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-null.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_486.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_686.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_pentium.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_winchip.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_x86-64.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_x86.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-compaq.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-config.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cpu.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-dac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-device.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc_fdi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc_img.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc_sector.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-dma.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdc37c665.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdd.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdi2raw.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-gameport.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-hdd.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-hdd_esdi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-headland.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430fx.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430lx.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430vx.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ide.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-intel.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-intel_flash.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-io.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-jim.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-joystick_ch_flightstick_pro.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-joystick_standard.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-joystick_sw_pad.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-joystick_tm_fcs.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_amstrad.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_at.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_olim24.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_pcjr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_xt.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-lpt.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mca.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mcr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mem.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mfm_at.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mfm_xebec.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-model.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse_ps2.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse_serial.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-neat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-nmi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-nvr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-olivetti_m24.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-opti495.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pci.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pic.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-piix.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pit.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ppi.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps1.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps2.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps2_mca.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps2_nvr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-rom.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-rtc.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scat.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-serial.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sis496.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ad1848.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_adlib.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_adlibgold.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_cms.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_emu8k.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_gus.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_mpu401_uart.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_opl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_pas16.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ps1.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_pssj.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sb.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sb_dsp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sn76489.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_speaker.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ssi2001.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_wss.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ym7128.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-soundopenal.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-tandy_eeprom.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-tandy_rom.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-thread-pthread.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-timer.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-um8669f.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-um8881f.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati18800.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati28800.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati68860_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati_eeprom.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati_mach64.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_cga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_cga_comp.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_cl5429.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_colorplus.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ega.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_et4000.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_et4000w32.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_genius.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_hercules.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_icd2061.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ics2595.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_incolor.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_mda.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_olivetti_m24.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_oti067.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_paradise.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc1512.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc1640.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc200.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pcjr.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ps1_svga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_s3.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_s3_virge.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_sdac_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_stg_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_svga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_svga_render.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tandy.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tandysl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tgui9440.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tkd8001_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tvga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_unk_ramdac.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_vga.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_wy700.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-video.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wd76c10.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-x86seg.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-x87.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-xtide.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)/sound_dbopl.Po@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sound_resid.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@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386_common.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386_dynarec.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-386_dynarec_ops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-808x.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-82091aa.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-acc2036.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-acc2168.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-acc3221.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-acer386sx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ali1429.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-amstrad.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cassette.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cbm_io.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-image.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-ioctl-dummy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-ioctl-linux.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-ioctl-osx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-ioctl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cdrom-null.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cmd640.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_accumulate.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_allocator.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_arm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_arm64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_arm64_imm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_arm64_ops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_arm64_uops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_arm_ops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_arm_uops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86-64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86-64_ops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86-64_uops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86_ops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_backend_x86_uops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_block.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ir.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_3dnow.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_arith.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_branch.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_fpu_arith.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_fpu_constant.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_fpu_misc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_helpers.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_jump.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_logic.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_misc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_mmx_arith.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_mmx_cmp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_mmx_logic.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_mmx_pack.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_mmx_shift.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_mov.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_shift.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_ops_stack.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_reg.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_486.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_686.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_common.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_cyrixiii.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_k6.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_p6.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_pentium.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_winchip.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-codegen_timing_winchip2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-compaq.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-config.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cpu.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cpu_tables.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-cs8230.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-dells200.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-device.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc_fdi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc_img.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-disc_sector.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-dma.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-esdi_at.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-f82c710_upc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdc37c665.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdc37c93x.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-fdi2raw.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-gameport.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-hdd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-hdd_esdi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-hdd_file.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-headland.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430fx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430hx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430lx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i430vx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i440bx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-i440fx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ide.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ide_atapi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ide_sff8038i.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-intel.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-intel_flash.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-io.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-jim.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-joystick_ch_flightstick_pro.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-joystick_standard.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-joystick_sw_pad.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-joystick_tm_fcs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_amstrad.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_at.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_olim24.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_pcjr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-keyboard_xt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-laserxt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-lpt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-lpt_dac.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-lpt_dss.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mca.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mcr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mem.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mem_bios.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mfm_at.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mfm_xebec.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-midi_alsa.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-model.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse_msystems.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse_ps2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mouse_serial.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-mvp3.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ne2000.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-neat.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-nethandler.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-nmi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-nvr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-nvr_tc8521.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-olivetti_m24.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-opti495.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-paths.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pc87306.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pc87307.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pci.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pic.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-piix.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-piix_pm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pit.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ppi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps1.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps2_mca.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-ps2_nvr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-pzx.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-rom.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-rtc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-rtc_tc8521.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scamp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scat.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scsi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scsi_53c400.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scsi_aha1540.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scsi_cd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scsi_hd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scsi_ibm.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-scsi_zip.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-serial.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sio.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sis496.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sl82c460.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ad1848.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_adlib.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_adlibgold.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_audiopci.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_azt2316a.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_cms.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_dbopl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_emu8k.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_gus.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_mpu401_uart.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_opl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_pas16.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ps1.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_pssj.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_resid.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sb.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sb_dsp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_sn76489.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_speaker.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ssi2001.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_wss.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sound_ym7128.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-soundopenal.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-sst39sf010.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-superxt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-t1000.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-t3100e.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-tandy_eeprom.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-tandy_rom.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-timer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-um8669f.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-um8881f.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati18800.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati28800.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati68860_ramdac.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati_eeprom.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ati_mach64.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_cga.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_cl5429.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_colorplus.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_compaq_cga.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ddc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ega.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_et4000.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_et4000w32.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_genius.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_hercules.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ht216.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_icd2061.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ics2595.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_im1024.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_incolor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_mda.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_mga.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_olivetti_m24.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_oti037.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_oti067.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_paradise.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc1512.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc1640.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pc200.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pcjr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_pgc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_ps1_svga.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_s3.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_s3_virge.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_sdac_ramdac.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_sigma.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_stg_ramdac.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_svga.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_svga_render.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_t1000.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_t3100e.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tandy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tandysl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tgui9440.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tkd8001_ramdac.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_tvga.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_unk_ramdac.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_vga.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_banshee.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_blitter.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_display.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_fb.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_fifo.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_reg.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_render.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_setup.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_voodoo_texture.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vid_wy700.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-video.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vl82c480.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-vt82c586b.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-w83877tf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-w83977tf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wd76c10.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-app.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-common.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-config.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-config_sel.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-createdisc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-deviceconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-dialogbox.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-glslp-parser.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-hostconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-joystickconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-main.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-resources.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-display-win.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-display.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-joystick.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-keyboard.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-midi.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-mouse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-status.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-video-gl3.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-video-renderer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2-video.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-sdl2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-shader_man.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-shaderconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-status.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-thread.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-wx-utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-x86seg.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-x87.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-x87_timings.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-xi8088.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pcem-xtide.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@dosbox/$(DEPDIR)/pcem-cdrom_image.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@dosbox/$(DEPDIR)/pcem-dbopl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@dosbox/$(DEPDIR)/pcem-nukedopl.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@dosbox/$(DEPDIR)/pcem-vid_cga_comp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@minivhd/$(DEPDIR)/pcem-cwalk.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@minivhd/$(DEPDIR)/pcem-libxml2_encoding.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@minivhd/$(DEPDIR)/pcem-minivhd_convert.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@minivhd/$(DEPDIR)/pcem-minivhd_create.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@minivhd/$(DEPDIR)/pcem-minivhd_io.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@minivhd/$(DEPDIR)/pcem-minivhd_manage.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@minivhd/$(DEPDIR)/pcem-minivhd_util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-convolve-sse.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-convolve.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-envelope.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-extfilt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-filter.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-pot.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-sid.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-voice.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave6581_PST.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave6581__ST.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave8580_PST.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@resid-fp/$(DEPDIR)/pcem-wave8580__ST.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-bootp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-cksum.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-debug.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-if.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-ip_icmp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-ip_input.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-ip_output.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-mbuf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-misc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-queue.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-sbuf.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-slirp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-socket.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-tcp_input.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-tcp_output.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-tcp_subr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-tcp_timer.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-tftp.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@slirp/$(DEPDIR)/pcem-udp.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) .c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` @@ -776,6 +1630,20 @@ pcem-386.obj: 386.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386.obj `if test -f '386.c'; then $(CYGPATH_W) '386.c'; else $(CYGPATH_W) '$(srcdir)/386.c'; fi` +pcem-386_common.o: 386_common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386_common.o -MD -MP -MF $(DEPDIR)/pcem-386_common.Tpo -c -o pcem-386_common.o `test -f '386_common.c' || echo '$(srcdir)/'`386_common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-386_common.Tpo $(DEPDIR)/pcem-386_common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='386_common.c' object='pcem-386_common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386_common.o `test -f '386_common.c' || echo '$(srcdir)/'`386_common.c + +pcem-386_common.obj: 386_common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386_common.obj -MD -MP -MF $(DEPDIR)/pcem-386_common.Tpo -c -o pcem-386_common.obj `if test -f '386_common.c'; then $(CYGPATH_W) '386_common.c'; else $(CYGPATH_W) '$(srcdir)/386_common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-386_common.Tpo $(DEPDIR)/pcem-386_common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='386_common.c' object='pcem-386_common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-386_common.obj `if test -f '386_common.c'; then $(CYGPATH_W) '386_common.c'; else $(CYGPATH_W) '$(srcdir)/386_common.c'; fi` + pcem-386_dynarec.o: 386_dynarec.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-386_dynarec.o -MD -MP -MF $(DEPDIR)/pcem-386_dynarec.Tpo -c -o pcem-386_dynarec.o `test -f '386_dynarec.c' || echo '$(srcdir)/'`386_dynarec.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-386_dynarec.Tpo $(DEPDIR)/pcem-386_dynarec.Po @@ -818,6 +1686,62 @@ pcem-808x.obj: 808x.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-808x.obj `if test -f '808x.c'; then $(CYGPATH_W) '808x.c'; else $(CYGPATH_W) '$(srcdir)/808x.c'; fi` +pcem-82091aa.o: 82091aa.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-82091aa.o -MD -MP -MF $(DEPDIR)/pcem-82091aa.Tpo -c -o pcem-82091aa.o `test -f '82091aa.c' || echo '$(srcdir)/'`82091aa.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-82091aa.Tpo $(DEPDIR)/pcem-82091aa.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='82091aa.c' object='pcem-82091aa.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-82091aa.o `test -f '82091aa.c' || echo '$(srcdir)/'`82091aa.c + +pcem-82091aa.obj: 82091aa.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-82091aa.obj -MD -MP -MF $(DEPDIR)/pcem-82091aa.Tpo -c -o pcem-82091aa.obj `if test -f '82091aa.c'; then $(CYGPATH_W) '82091aa.c'; else $(CYGPATH_W) '$(srcdir)/82091aa.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-82091aa.Tpo $(DEPDIR)/pcem-82091aa.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='82091aa.c' object='pcem-82091aa.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-82091aa.obj `if test -f '82091aa.c'; then $(CYGPATH_W) '82091aa.c'; else $(CYGPATH_W) '$(srcdir)/82091aa.c'; fi` + +pcem-acc2036.o: acc2036.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acc2036.o -MD -MP -MF $(DEPDIR)/pcem-acc2036.Tpo -c -o pcem-acc2036.o `test -f 'acc2036.c' || echo '$(srcdir)/'`acc2036.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-acc2036.Tpo $(DEPDIR)/pcem-acc2036.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acc2036.c' object='pcem-acc2036.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-acc2036.o `test -f 'acc2036.c' || echo '$(srcdir)/'`acc2036.c + +pcem-acc2036.obj: acc2036.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acc2036.obj -MD -MP -MF $(DEPDIR)/pcem-acc2036.Tpo -c -o pcem-acc2036.obj `if test -f 'acc2036.c'; then $(CYGPATH_W) 'acc2036.c'; else $(CYGPATH_W) '$(srcdir)/acc2036.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-acc2036.Tpo $(DEPDIR)/pcem-acc2036.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acc2036.c' object='pcem-acc2036.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-acc2036.obj `if test -f 'acc2036.c'; then $(CYGPATH_W) 'acc2036.c'; else $(CYGPATH_W) '$(srcdir)/acc2036.c'; fi` + +pcem-acc2168.o: acc2168.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acc2168.o -MD -MP -MF $(DEPDIR)/pcem-acc2168.Tpo -c -o pcem-acc2168.o `test -f 'acc2168.c' || echo '$(srcdir)/'`acc2168.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-acc2168.Tpo $(DEPDIR)/pcem-acc2168.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acc2168.c' object='pcem-acc2168.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-acc2168.o `test -f 'acc2168.c' || echo '$(srcdir)/'`acc2168.c + +pcem-acc2168.obj: acc2168.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acc2168.obj -MD -MP -MF $(DEPDIR)/pcem-acc2168.Tpo -c -o pcem-acc2168.obj `if test -f 'acc2168.c'; then $(CYGPATH_W) 'acc2168.c'; else $(CYGPATH_W) '$(srcdir)/acc2168.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-acc2168.Tpo $(DEPDIR)/pcem-acc2168.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acc2168.c' object='pcem-acc2168.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-acc2168.obj `if test -f 'acc2168.c'; then $(CYGPATH_W) 'acc2168.c'; else $(CYGPATH_W) '$(srcdir)/acc2168.c'; fi` + +pcem-acc3221.o: acc3221.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acc3221.o -MD -MP -MF $(DEPDIR)/pcem-acc3221.Tpo -c -o pcem-acc3221.o `test -f 'acc3221.c' || echo '$(srcdir)/'`acc3221.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-acc3221.Tpo $(DEPDIR)/pcem-acc3221.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acc3221.c' object='pcem-acc3221.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-acc3221.o `test -f 'acc3221.c' || echo '$(srcdir)/'`acc3221.c + +pcem-acc3221.obj: acc3221.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acc3221.obj -MD -MP -MF $(DEPDIR)/pcem-acc3221.Tpo -c -o pcem-acc3221.obj `if test -f 'acc3221.c'; then $(CYGPATH_W) 'acc3221.c'; else $(CYGPATH_W) '$(srcdir)/acc3221.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-acc3221.Tpo $(DEPDIR)/pcem-acc3221.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='acc3221.c' object='pcem-acc3221.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-acc3221.obj `if test -f 'acc3221.c'; then $(CYGPATH_W) 'acc3221.c'; else $(CYGPATH_W) '$(srcdir)/acc3221.c'; fi` + pcem-acer386sx.o: acer386sx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-acer386sx.o -MD -MP -MF $(DEPDIR)/pcem-acer386sx.Tpo -c -o pcem-acer386sx.o `test -f 'acer386sx.c' || echo '$(srcdir)/'`acer386sx.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-acer386sx.Tpo $(DEPDIR)/pcem-acer386sx.Po @@ -846,160 +1770,6 @@ pcem-ali1429.obj: ali1429.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ali1429.obj `if test -f 'ali1429.c'; then $(CYGPATH_W) 'ali1429.c'; else $(CYGPATH_W) '$(srcdir)/ali1429.c'; fi` -pcem-allegro-gui.o: allegro-gui.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui.o -MD -MP -MF $(DEPDIR)/pcem-allegro-gui.Tpo -c -o pcem-allegro-gui.o `test -f 'allegro-gui.c' || echo '$(srcdir)/'`allegro-gui.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui.Tpo $(DEPDIR)/pcem-allegro-gui.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui.c' object='pcem-allegro-gui.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui.o `test -f 'allegro-gui.c' || echo '$(srcdir)/'`allegro-gui.c - -pcem-allegro-gui.obj: allegro-gui.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-gui.Tpo -c -o pcem-allegro-gui.obj `if test -f 'allegro-gui.c'; then $(CYGPATH_W) 'allegro-gui.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui.Tpo $(DEPDIR)/pcem-allegro-gui.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui.c' object='pcem-allegro-gui.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui.obj `if test -f 'allegro-gui.c'; then $(CYGPATH_W) 'allegro-gui.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui.c'; fi` - -pcem-allegro-gui-config-sel.o: allegro-gui-config-sel.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-config-sel.o -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-config-sel.Tpo -c -o pcem-allegro-gui-config-sel.o `test -f 'allegro-gui-config-sel.c' || echo '$(srcdir)/'`allegro-gui-config-sel.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui-config-sel.Tpo $(DEPDIR)/pcem-allegro-gui-config-sel.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui-config-sel.c' object='pcem-allegro-gui-config-sel.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-config-sel.o `test -f 'allegro-gui-config-sel.c' || echo '$(srcdir)/'`allegro-gui-config-sel.c - -pcem-allegro-gui-config-sel.obj: allegro-gui-config-sel.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-config-sel.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-config-sel.Tpo -c -o pcem-allegro-gui-config-sel.obj `if test -f 'allegro-gui-config-sel.c'; then $(CYGPATH_W) 'allegro-gui-config-sel.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-config-sel.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui-config-sel.Tpo $(DEPDIR)/pcem-allegro-gui-config-sel.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui-config-sel.c' object='pcem-allegro-gui-config-sel.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-config-sel.obj `if test -f 'allegro-gui-config-sel.c'; then $(CYGPATH_W) 'allegro-gui-config-sel.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-config-sel.c'; fi` - -pcem-allegro-gui-configure.o: allegro-gui-configure.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-configure.o -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-configure.Tpo -c -o pcem-allegro-gui-configure.o `test -f 'allegro-gui-configure.c' || echo '$(srcdir)/'`allegro-gui-configure.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui-configure.Tpo $(DEPDIR)/pcem-allegro-gui-configure.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui-configure.c' object='pcem-allegro-gui-configure.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-configure.o `test -f 'allegro-gui-configure.c' || echo '$(srcdir)/'`allegro-gui-configure.c - -pcem-allegro-gui-configure.obj: allegro-gui-configure.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-configure.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-configure.Tpo -c -o pcem-allegro-gui-configure.obj `if test -f 'allegro-gui-configure.c'; then $(CYGPATH_W) 'allegro-gui-configure.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-configure.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui-configure.Tpo $(DEPDIR)/pcem-allegro-gui-configure.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui-configure.c' object='pcem-allegro-gui-configure.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-configure.obj `if test -f 'allegro-gui-configure.c'; then $(CYGPATH_W) 'allegro-gui-configure.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-configure.c'; fi` - -pcem-allegro-gui-deviceconfig.o: allegro-gui-deviceconfig.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-deviceconfig.o -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-deviceconfig.Tpo -c -o pcem-allegro-gui-deviceconfig.o `test -f 'allegro-gui-deviceconfig.c' || echo '$(srcdir)/'`allegro-gui-deviceconfig.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui-deviceconfig.Tpo $(DEPDIR)/pcem-allegro-gui-deviceconfig.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui-deviceconfig.c' object='pcem-allegro-gui-deviceconfig.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-deviceconfig.o `test -f 'allegro-gui-deviceconfig.c' || echo '$(srcdir)/'`allegro-gui-deviceconfig.c - -pcem-allegro-gui-deviceconfig.obj: allegro-gui-deviceconfig.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-deviceconfig.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-deviceconfig.Tpo -c -o pcem-allegro-gui-deviceconfig.obj `if test -f 'allegro-gui-deviceconfig.c'; then $(CYGPATH_W) 'allegro-gui-deviceconfig.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-deviceconfig.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui-deviceconfig.Tpo $(DEPDIR)/pcem-allegro-gui-deviceconfig.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui-deviceconfig.c' object='pcem-allegro-gui-deviceconfig.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-deviceconfig.obj `if test -f 'allegro-gui-deviceconfig.c'; then $(CYGPATH_W) 'allegro-gui-deviceconfig.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-deviceconfig.c'; fi` - -pcem-allegro-gui-hdconf.o: allegro-gui-hdconf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-hdconf.o -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-hdconf.Tpo -c -o pcem-allegro-gui-hdconf.o `test -f 'allegro-gui-hdconf.c' || echo '$(srcdir)/'`allegro-gui-hdconf.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui-hdconf.Tpo $(DEPDIR)/pcem-allegro-gui-hdconf.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui-hdconf.c' object='pcem-allegro-gui-hdconf.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-hdconf.o `test -f 'allegro-gui-hdconf.c' || echo '$(srcdir)/'`allegro-gui-hdconf.c - -pcem-allegro-gui-hdconf.obj: allegro-gui-hdconf.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-gui-hdconf.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-gui-hdconf.Tpo -c -o pcem-allegro-gui-hdconf.obj `if test -f 'allegro-gui-hdconf.c'; then $(CYGPATH_W) 'allegro-gui-hdconf.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-hdconf.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-gui-hdconf.Tpo $(DEPDIR)/pcem-allegro-gui-hdconf.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-gui-hdconf.c' object='pcem-allegro-gui-hdconf.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-gui-hdconf.obj `if test -f 'allegro-gui-hdconf.c'; then $(CYGPATH_W) 'allegro-gui-hdconf.c'; else $(CYGPATH_W) '$(srcdir)/allegro-gui-hdconf.c'; fi` - -pcem-allegro-joystick.o: allegro-joystick.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-joystick.o -MD -MP -MF $(DEPDIR)/pcem-allegro-joystick.Tpo -c -o pcem-allegro-joystick.o `test -f 'allegro-joystick.c' || echo '$(srcdir)/'`allegro-joystick.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-joystick.Tpo $(DEPDIR)/pcem-allegro-joystick.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-joystick.c' object='pcem-allegro-joystick.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-joystick.o `test -f 'allegro-joystick.c' || echo '$(srcdir)/'`allegro-joystick.c - -pcem-allegro-joystick.obj: allegro-joystick.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-joystick.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-joystick.Tpo -c -o pcem-allegro-joystick.obj `if test -f 'allegro-joystick.c'; then $(CYGPATH_W) 'allegro-joystick.c'; else $(CYGPATH_W) '$(srcdir)/allegro-joystick.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-joystick.Tpo $(DEPDIR)/pcem-allegro-joystick.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-joystick.c' object='pcem-allegro-joystick.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-joystick.obj `if test -f 'allegro-joystick.c'; then $(CYGPATH_W) 'allegro-joystick.c'; else $(CYGPATH_W) '$(srcdir)/allegro-joystick.c'; fi` - -pcem-allegro-keyboard.o: allegro-keyboard.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-keyboard.o -MD -MP -MF $(DEPDIR)/pcem-allegro-keyboard.Tpo -c -o pcem-allegro-keyboard.o `test -f 'allegro-keyboard.c' || echo '$(srcdir)/'`allegro-keyboard.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-keyboard.Tpo $(DEPDIR)/pcem-allegro-keyboard.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-keyboard.c' object='pcem-allegro-keyboard.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-keyboard.o `test -f 'allegro-keyboard.c' || echo '$(srcdir)/'`allegro-keyboard.c - -pcem-allegro-keyboard.obj: allegro-keyboard.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-keyboard.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-keyboard.Tpo -c -o pcem-allegro-keyboard.obj `if test -f 'allegro-keyboard.c'; then $(CYGPATH_W) 'allegro-keyboard.c'; else $(CYGPATH_W) '$(srcdir)/allegro-keyboard.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-keyboard.Tpo $(DEPDIR)/pcem-allegro-keyboard.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-keyboard.c' object='pcem-allegro-keyboard.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-keyboard.obj `if test -f 'allegro-keyboard.c'; then $(CYGPATH_W) 'allegro-keyboard.c'; else $(CYGPATH_W) '$(srcdir)/allegro-keyboard.c'; fi` - -pcem-allegro-main.o: allegro-main.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-main.o -MD -MP -MF $(DEPDIR)/pcem-allegro-main.Tpo -c -o pcem-allegro-main.o `test -f 'allegro-main.c' || echo '$(srcdir)/'`allegro-main.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-main.Tpo $(DEPDIR)/pcem-allegro-main.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-main.c' object='pcem-allegro-main.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-main.o `test -f 'allegro-main.c' || echo '$(srcdir)/'`allegro-main.c - -pcem-allegro-main.obj: allegro-main.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-main.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-main.Tpo -c -o pcem-allegro-main.obj `if test -f 'allegro-main.c'; then $(CYGPATH_W) 'allegro-main.c'; else $(CYGPATH_W) '$(srcdir)/allegro-main.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-main.Tpo $(DEPDIR)/pcem-allegro-main.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-main.c' object='pcem-allegro-main.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-main.obj `if test -f 'allegro-main.c'; then $(CYGPATH_W) 'allegro-main.c'; else $(CYGPATH_W) '$(srcdir)/allegro-main.c'; fi` - -pcem-allegro-midi.o: allegro-midi.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-midi.o -MD -MP -MF $(DEPDIR)/pcem-allegro-midi.Tpo -c -o pcem-allegro-midi.o `test -f 'allegro-midi.c' || echo '$(srcdir)/'`allegro-midi.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-midi.Tpo $(DEPDIR)/pcem-allegro-midi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-midi.c' object='pcem-allegro-midi.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-midi.o `test -f 'allegro-midi.c' || echo '$(srcdir)/'`allegro-midi.c - -pcem-allegro-midi.obj: allegro-midi.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-midi.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-midi.Tpo -c -o pcem-allegro-midi.obj `if test -f 'allegro-midi.c'; then $(CYGPATH_W) 'allegro-midi.c'; else $(CYGPATH_W) '$(srcdir)/allegro-midi.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-midi.Tpo $(DEPDIR)/pcem-allegro-midi.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-midi.c' object='pcem-allegro-midi.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-midi.obj `if test -f 'allegro-midi.c'; then $(CYGPATH_W) 'allegro-midi.c'; else $(CYGPATH_W) '$(srcdir)/allegro-midi.c'; fi` - -pcem-allegro-mouse.o: allegro-mouse.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-mouse.o -MD -MP -MF $(DEPDIR)/pcem-allegro-mouse.Tpo -c -o pcem-allegro-mouse.o `test -f 'allegro-mouse.c' || echo '$(srcdir)/'`allegro-mouse.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-mouse.Tpo $(DEPDIR)/pcem-allegro-mouse.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-mouse.c' object='pcem-allegro-mouse.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-mouse.o `test -f 'allegro-mouse.c' || echo '$(srcdir)/'`allegro-mouse.c - -pcem-allegro-mouse.obj: allegro-mouse.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-mouse.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-mouse.Tpo -c -o pcem-allegro-mouse.obj `if test -f 'allegro-mouse.c'; then $(CYGPATH_W) 'allegro-mouse.c'; else $(CYGPATH_W) '$(srcdir)/allegro-mouse.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-mouse.Tpo $(DEPDIR)/pcem-allegro-mouse.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-mouse.c' object='pcem-allegro-mouse.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-mouse.obj `if test -f 'allegro-mouse.c'; then $(CYGPATH_W) 'allegro-mouse.c'; else $(CYGPATH_W) '$(srcdir)/allegro-mouse.c'; fi` - -pcem-allegro-video.o: allegro-video.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-video.o -MD -MP -MF $(DEPDIR)/pcem-allegro-video.Tpo -c -o pcem-allegro-video.o `test -f 'allegro-video.c' || echo '$(srcdir)/'`allegro-video.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-video.Tpo $(DEPDIR)/pcem-allegro-video.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-video.c' object='pcem-allegro-video.o' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-video.o `test -f 'allegro-video.c' || echo '$(srcdir)/'`allegro-video.c - -pcem-allegro-video.obj: allegro-video.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-allegro-video.obj -MD -MP -MF $(DEPDIR)/pcem-allegro-video.Tpo -c -o pcem-allegro-video.obj `if test -f 'allegro-video.c'; then $(CYGPATH_W) 'allegro-video.c'; else $(CYGPATH_W) '$(srcdir)/allegro-video.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-allegro-video.Tpo $(DEPDIR)/pcem-allegro-video.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='allegro-video.c' object='pcem-allegro-video.obj' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-allegro-video.obj `if test -f 'allegro-video.c'; then $(CYGPATH_W) 'allegro-video.c'; else $(CYGPATH_W) '$(srcdir)/allegro-video.c'; fi` - pcem-amstrad.o: amstrad.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-amstrad.o -MD -MP -MF $(DEPDIR)/pcem-amstrad.Tpo -c -o pcem-amstrad.o `test -f 'amstrad.c' || echo '$(srcdir)/'`amstrad.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-amstrad.Tpo $(DEPDIR)/pcem-amstrad.Po @@ -1014,33 +1784,33 @@ pcem-amstrad.obj: amstrad.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-amstrad.obj `if test -f 'amstrad.c'; then $(CYGPATH_W) 'amstrad.c'; else $(CYGPATH_W) '$(srcdir)/amstrad.c'; fi` -pcem-cdrom-ioctl-linux.o: cdrom-ioctl-linux.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-linux.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo -c -o pcem-cdrom-ioctl-linux.o `test -f 'cdrom-ioctl-linux.c' || echo '$(srcdir)/'`cdrom-ioctl-linux.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo $(DEPDIR)/pcem-cdrom-ioctl-linux.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl-linux.c' object='pcem-cdrom-ioctl-linux.o' libtool=no @AMDEPBACKSLASH@ +pcem-cassette.o: cassette.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cassette.o -MD -MP -MF $(DEPDIR)/pcem-cassette.Tpo -c -o pcem-cassette.o `test -f 'cassette.c' || echo '$(srcdir)/'`cassette.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cassette.Tpo $(DEPDIR)/pcem-cassette.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cassette.c' object='pcem-cassette.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-linux.o `test -f 'cdrom-ioctl-linux.c' || echo '$(srcdir)/'`cdrom-ioctl-linux.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cassette.o `test -f 'cassette.c' || echo '$(srcdir)/'`cassette.c -pcem-cdrom-ioctl-linux.obj: cdrom-ioctl-linux.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-linux.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo -c -o pcem-cdrom-ioctl-linux.obj `if test -f 'cdrom-ioctl-linux.c'; then $(CYGPATH_W) 'cdrom-ioctl-linux.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-linux.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo $(DEPDIR)/pcem-cdrom-ioctl-linux.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl-linux.c' object='pcem-cdrom-ioctl-linux.obj' libtool=no @AMDEPBACKSLASH@ +pcem-cassette.obj: cassette.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cassette.obj -MD -MP -MF $(DEPDIR)/pcem-cassette.Tpo -c -o pcem-cassette.obj `if test -f 'cassette.c'; then $(CYGPATH_W) 'cassette.c'; else $(CYGPATH_W) '$(srcdir)/cassette.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cassette.Tpo $(DEPDIR)/pcem-cassette.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cassette.c' object='pcem-cassette.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-linux.obj `if test -f 'cdrom-ioctl-linux.c'; then $(CYGPATH_W) 'cdrom-ioctl-linux.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-linux.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cassette.obj `if test -f 'cassette.c'; then $(CYGPATH_W) 'cassette.c'; else $(CYGPATH_W) '$(srcdir)/cassette.c'; fi` -pcem-cdrom-iso.o: cdrom-iso.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-iso.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-iso.Tpo -c -o pcem-cdrom-iso.o `test -f 'cdrom-iso.c' || echo '$(srcdir)/'`cdrom-iso.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-iso.Tpo $(DEPDIR)/pcem-cdrom-iso.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-iso.c' object='pcem-cdrom-iso.o' libtool=no @AMDEPBACKSLASH@ +pcem-cbm_io.o: cbm_io.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cbm_io.o -MD -MP -MF $(DEPDIR)/pcem-cbm_io.Tpo -c -o pcem-cbm_io.o `test -f 'cbm_io.c' || echo '$(srcdir)/'`cbm_io.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cbm_io.Tpo $(DEPDIR)/pcem-cbm_io.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cbm_io.c' object='pcem-cbm_io.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-iso.o `test -f 'cdrom-iso.c' || echo '$(srcdir)/'`cdrom-iso.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cbm_io.o `test -f 'cbm_io.c' || echo '$(srcdir)/'`cbm_io.c -pcem-cdrom-iso.obj: cdrom-iso.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-iso.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-iso.Tpo -c -o pcem-cdrom-iso.obj `if test -f 'cdrom-iso.c'; then $(CYGPATH_W) 'cdrom-iso.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-iso.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-iso.Tpo $(DEPDIR)/pcem-cdrom-iso.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-iso.c' object='pcem-cdrom-iso.obj' libtool=no @AMDEPBACKSLASH@ +pcem-cbm_io.obj: cbm_io.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cbm_io.obj -MD -MP -MF $(DEPDIR)/pcem-cbm_io.Tpo -c -o pcem-cbm_io.obj `if test -f 'cbm_io.c'; then $(CYGPATH_W) 'cbm_io.c'; else $(CYGPATH_W) '$(srcdir)/cbm_io.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cbm_io.Tpo $(DEPDIR)/pcem-cbm_io.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cbm_io.c' object='pcem-cbm_io.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-iso.obj `if test -f 'cdrom-iso.c'; then $(CYGPATH_W) 'cdrom-iso.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-iso.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cbm_io.obj `if test -f 'cbm_io.c'; then $(CYGPATH_W) 'cbm_io.c'; else $(CYGPATH_W) '$(srcdir)/cbm_io.c'; fi` pcem-cdrom-null.o: cdrom-null.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-null.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-null.Tpo -c -o pcem-cdrom-null.o `test -f 'cdrom-null.c' || echo '$(srcdir)/'`cdrom-null.c @@ -1056,6 +1826,20 @@ pcem-cdrom-null.obj: cdrom-null.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-null.obj `if test -f 'cdrom-null.c'; then $(CYGPATH_W) 'cdrom-null.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-null.c'; fi` +pcem-cmd640.o: cmd640.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cmd640.o -MD -MP -MF $(DEPDIR)/pcem-cmd640.Tpo -c -o pcem-cmd640.o `test -f 'cmd640.c' || echo '$(srcdir)/'`cmd640.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cmd640.Tpo $(DEPDIR)/pcem-cmd640.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd640.c' object='pcem-cmd640.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cmd640.o `test -f 'cmd640.c' || echo '$(srcdir)/'`cmd640.c + +pcem-cmd640.obj: cmd640.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cmd640.obj -MD -MP -MF $(DEPDIR)/pcem-cmd640.Tpo -c -o pcem-cmd640.obj `if test -f 'cmd640.c'; then $(CYGPATH_W) 'cmd640.c'; else $(CYGPATH_W) '$(srcdir)/cmd640.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cmd640.Tpo $(DEPDIR)/pcem-cmd640.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cmd640.c' object='pcem-cmd640.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cmd640.obj `if test -f 'cmd640.c'; then $(CYGPATH_W) 'cmd640.c'; else $(CYGPATH_W) '$(srcdir)/cmd640.c'; fi` + pcem-codegen.o: codegen.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen.o -MD -MP -MF $(DEPDIR)/pcem-codegen.Tpo -c -o pcem-codegen.o `test -f 'codegen.c' || echo '$(srcdir)/'`codegen.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen.Tpo $(DEPDIR)/pcem-codegen.Po @@ -1070,6 +1854,62 @@ pcem-codegen.obj: codegen.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen.obj `if test -f 'codegen.c'; then $(CYGPATH_W) 'codegen.c'; else $(CYGPATH_W) '$(srcdir)/codegen.c'; fi` +pcem-codegen_accumulate.o: codegen_accumulate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_accumulate.o -MD -MP -MF $(DEPDIR)/pcem-codegen_accumulate.Tpo -c -o pcem-codegen_accumulate.o `test -f 'codegen_accumulate.c' || echo '$(srcdir)/'`codegen_accumulate.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_accumulate.Tpo $(DEPDIR)/pcem-codegen_accumulate.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_accumulate.c' object='pcem-codegen_accumulate.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_accumulate.o `test -f 'codegen_accumulate.c' || echo '$(srcdir)/'`codegen_accumulate.c + +pcem-codegen_accumulate.obj: codegen_accumulate.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_accumulate.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_accumulate.Tpo -c -o pcem-codegen_accumulate.obj `if test -f 'codegen_accumulate.c'; then $(CYGPATH_W) 'codegen_accumulate.c'; else $(CYGPATH_W) '$(srcdir)/codegen_accumulate.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_accumulate.Tpo $(DEPDIR)/pcem-codegen_accumulate.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_accumulate.c' object='pcem-codegen_accumulate.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_accumulate.obj `if test -f 'codegen_accumulate.c'; then $(CYGPATH_W) 'codegen_accumulate.c'; else $(CYGPATH_W) '$(srcdir)/codegen_accumulate.c'; fi` + +pcem-codegen_allocator.o: codegen_allocator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_allocator.o -MD -MP -MF $(DEPDIR)/pcem-codegen_allocator.Tpo -c -o pcem-codegen_allocator.o `test -f 'codegen_allocator.c' || echo '$(srcdir)/'`codegen_allocator.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_allocator.Tpo $(DEPDIR)/pcem-codegen_allocator.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_allocator.c' object='pcem-codegen_allocator.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_allocator.o `test -f 'codegen_allocator.c' || echo '$(srcdir)/'`codegen_allocator.c + +pcem-codegen_allocator.obj: codegen_allocator.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_allocator.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_allocator.Tpo -c -o pcem-codegen_allocator.obj `if test -f 'codegen_allocator.c'; then $(CYGPATH_W) 'codegen_allocator.c'; else $(CYGPATH_W) '$(srcdir)/codegen_allocator.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_allocator.Tpo $(DEPDIR)/pcem-codegen_allocator.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_allocator.c' object='pcem-codegen_allocator.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_allocator.obj `if test -f 'codegen_allocator.c'; then $(CYGPATH_W) 'codegen_allocator.c'; else $(CYGPATH_W) '$(srcdir)/codegen_allocator.c'; fi` + +pcem-codegen_block.o: codegen_block.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_block.o -MD -MP -MF $(DEPDIR)/pcem-codegen_block.Tpo -c -o pcem-codegen_block.o `test -f 'codegen_block.c' || echo '$(srcdir)/'`codegen_block.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_block.Tpo $(DEPDIR)/pcem-codegen_block.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_block.c' object='pcem-codegen_block.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_block.o `test -f 'codegen_block.c' || echo '$(srcdir)/'`codegen_block.c + +pcem-codegen_block.obj: codegen_block.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_block.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_block.Tpo -c -o pcem-codegen_block.obj `if test -f 'codegen_block.c'; then $(CYGPATH_W) 'codegen_block.c'; else $(CYGPATH_W) '$(srcdir)/codegen_block.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_block.Tpo $(DEPDIR)/pcem-codegen_block.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_block.c' object='pcem-codegen_block.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_block.obj `if test -f 'codegen_block.c'; then $(CYGPATH_W) 'codegen_block.c'; else $(CYGPATH_W) '$(srcdir)/codegen_block.c'; fi` + +pcem-codegen_ir.o: codegen_ir.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ir.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ir.Tpo -c -o pcem-codegen_ir.o `test -f 'codegen_ir.c' || echo '$(srcdir)/'`codegen_ir.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ir.Tpo $(DEPDIR)/pcem-codegen_ir.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ir.c' object='pcem-codegen_ir.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ir.o `test -f 'codegen_ir.c' || echo '$(srcdir)/'`codegen_ir.c + +pcem-codegen_ir.obj: codegen_ir.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ir.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ir.Tpo -c -o pcem-codegen_ir.obj `if test -f 'codegen_ir.c'; then $(CYGPATH_W) 'codegen_ir.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ir.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ir.Tpo $(DEPDIR)/pcem-codegen_ir.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ir.c' object='pcem-codegen_ir.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ir.obj `if test -f 'codegen_ir.c'; then $(CYGPATH_W) 'codegen_ir.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ir.c'; fi` + pcem-codegen_ops.o: codegen_ops.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops.Tpo -c -o pcem-codegen_ops.o `test -f 'codegen_ops.c' || echo '$(srcdir)/'`codegen_ops.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops.Tpo $(DEPDIR)/pcem-codegen_ops.Po @@ -1084,6 +1924,300 @@ pcem-codegen_ops.obj: codegen_ops.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops.obj `if test -f 'codegen_ops.c'; then $(CYGPATH_W) 'codegen_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops.c'; fi` +pcem-codegen_ops_3dnow.o: codegen_ops_3dnow.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_3dnow.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_3dnow.Tpo -c -o pcem-codegen_ops_3dnow.o `test -f 'codegen_ops_3dnow.c' || echo '$(srcdir)/'`codegen_ops_3dnow.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_3dnow.Tpo $(DEPDIR)/pcem-codegen_ops_3dnow.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_3dnow.c' object='pcem-codegen_ops_3dnow.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_3dnow.o `test -f 'codegen_ops_3dnow.c' || echo '$(srcdir)/'`codegen_ops_3dnow.c + +pcem-codegen_ops_3dnow.obj: codegen_ops_3dnow.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_3dnow.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_3dnow.Tpo -c -o pcem-codegen_ops_3dnow.obj `if test -f 'codegen_ops_3dnow.c'; then $(CYGPATH_W) 'codegen_ops_3dnow.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_3dnow.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_3dnow.Tpo $(DEPDIR)/pcem-codegen_ops_3dnow.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_3dnow.c' object='pcem-codegen_ops_3dnow.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_3dnow.obj `if test -f 'codegen_ops_3dnow.c'; then $(CYGPATH_W) 'codegen_ops_3dnow.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_3dnow.c'; fi` + +pcem-codegen_ops_arith.o: codegen_ops_arith.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_arith.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_arith.Tpo -c -o pcem-codegen_ops_arith.o `test -f 'codegen_ops_arith.c' || echo '$(srcdir)/'`codegen_ops_arith.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_arith.Tpo $(DEPDIR)/pcem-codegen_ops_arith.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_arith.c' object='pcem-codegen_ops_arith.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_arith.o `test -f 'codegen_ops_arith.c' || echo '$(srcdir)/'`codegen_ops_arith.c + +pcem-codegen_ops_arith.obj: codegen_ops_arith.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_arith.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_arith.Tpo -c -o pcem-codegen_ops_arith.obj `if test -f 'codegen_ops_arith.c'; then $(CYGPATH_W) 'codegen_ops_arith.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_arith.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_arith.Tpo $(DEPDIR)/pcem-codegen_ops_arith.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_arith.c' object='pcem-codegen_ops_arith.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_arith.obj `if test -f 'codegen_ops_arith.c'; then $(CYGPATH_W) 'codegen_ops_arith.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_arith.c'; fi` + +pcem-codegen_ops_branch.o: codegen_ops_branch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_branch.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_branch.Tpo -c -o pcem-codegen_ops_branch.o `test -f 'codegen_ops_branch.c' || echo '$(srcdir)/'`codegen_ops_branch.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_branch.Tpo $(DEPDIR)/pcem-codegen_ops_branch.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_branch.c' object='pcem-codegen_ops_branch.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_branch.o `test -f 'codegen_ops_branch.c' || echo '$(srcdir)/'`codegen_ops_branch.c + +pcem-codegen_ops_branch.obj: codegen_ops_branch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_branch.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_branch.Tpo -c -o pcem-codegen_ops_branch.obj `if test -f 'codegen_ops_branch.c'; then $(CYGPATH_W) 'codegen_ops_branch.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_branch.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_branch.Tpo $(DEPDIR)/pcem-codegen_ops_branch.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_branch.c' object='pcem-codegen_ops_branch.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_branch.obj `if test -f 'codegen_ops_branch.c'; then $(CYGPATH_W) 'codegen_ops_branch.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_branch.c'; fi` + +pcem-codegen_ops_fpu_arith.o: codegen_ops_fpu_arith.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_fpu_arith.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_fpu_arith.Tpo -c -o pcem-codegen_ops_fpu_arith.o `test -f 'codegen_ops_fpu_arith.c' || echo '$(srcdir)/'`codegen_ops_fpu_arith.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_fpu_arith.Tpo $(DEPDIR)/pcem-codegen_ops_fpu_arith.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_fpu_arith.c' object='pcem-codegen_ops_fpu_arith.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_fpu_arith.o `test -f 'codegen_ops_fpu_arith.c' || echo '$(srcdir)/'`codegen_ops_fpu_arith.c + +pcem-codegen_ops_fpu_arith.obj: codegen_ops_fpu_arith.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_fpu_arith.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_fpu_arith.Tpo -c -o pcem-codegen_ops_fpu_arith.obj `if test -f 'codegen_ops_fpu_arith.c'; then $(CYGPATH_W) 'codegen_ops_fpu_arith.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_fpu_arith.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_fpu_arith.Tpo $(DEPDIR)/pcem-codegen_ops_fpu_arith.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_fpu_arith.c' object='pcem-codegen_ops_fpu_arith.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_fpu_arith.obj `if test -f 'codegen_ops_fpu_arith.c'; then $(CYGPATH_W) 'codegen_ops_fpu_arith.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_fpu_arith.c'; fi` + +pcem-codegen_ops_fpu_constant.o: codegen_ops_fpu_constant.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_fpu_constant.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_fpu_constant.Tpo -c -o pcem-codegen_ops_fpu_constant.o `test -f 'codegen_ops_fpu_constant.c' || echo '$(srcdir)/'`codegen_ops_fpu_constant.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_fpu_constant.Tpo $(DEPDIR)/pcem-codegen_ops_fpu_constant.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_fpu_constant.c' object='pcem-codegen_ops_fpu_constant.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_fpu_constant.o `test -f 'codegen_ops_fpu_constant.c' || echo '$(srcdir)/'`codegen_ops_fpu_constant.c + +pcem-codegen_ops_fpu_constant.obj: codegen_ops_fpu_constant.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_fpu_constant.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_fpu_constant.Tpo -c -o pcem-codegen_ops_fpu_constant.obj `if test -f 'codegen_ops_fpu_constant.c'; then $(CYGPATH_W) 'codegen_ops_fpu_constant.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_fpu_constant.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_fpu_constant.Tpo $(DEPDIR)/pcem-codegen_ops_fpu_constant.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_fpu_constant.c' object='pcem-codegen_ops_fpu_constant.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_fpu_constant.obj `if test -f 'codegen_ops_fpu_constant.c'; then $(CYGPATH_W) 'codegen_ops_fpu_constant.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_fpu_constant.c'; fi` + +pcem-codegen_ops_fpu_loadstore.o: codegen_ops_fpu_loadstore.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_fpu_loadstore.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Tpo -c -o pcem-codegen_ops_fpu_loadstore.o `test -f 'codegen_ops_fpu_loadstore.c' || echo '$(srcdir)/'`codegen_ops_fpu_loadstore.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Tpo $(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_fpu_loadstore.c' object='pcem-codegen_ops_fpu_loadstore.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_fpu_loadstore.o `test -f 'codegen_ops_fpu_loadstore.c' || echo '$(srcdir)/'`codegen_ops_fpu_loadstore.c + +pcem-codegen_ops_fpu_loadstore.obj: codegen_ops_fpu_loadstore.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_fpu_loadstore.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Tpo -c -o pcem-codegen_ops_fpu_loadstore.obj `if test -f 'codegen_ops_fpu_loadstore.c'; then $(CYGPATH_W) 'codegen_ops_fpu_loadstore.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_fpu_loadstore.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Tpo $(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_fpu_loadstore.c' object='pcem-codegen_ops_fpu_loadstore.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_fpu_loadstore.obj `if test -f 'codegen_ops_fpu_loadstore.c'; then $(CYGPATH_W) 'codegen_ops_fpu_loadstore.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_fpu_loadstore.c'; fi` + +pcem-codegen_ops_fpu_misc.o: codegen_ops_fpu_misc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_fpu_misc.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_fpu_misc.Tpo -c -o pcem-codegen_ops_fpu_misc.o `test -f 'codegen_ops_fpu_misc.c' || echo '$(srcdir)/'`codegen_ops_fpu_misc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_fpu_misc.Tpo $(DEPDIR)/pcem-codegen_ops_fpu_misc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_fpu_misc.c' object='pcem-codegen_ops_fpu_misc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_fpu_misc.o `test -f 'codegen_ops_fpu_misc.c' || echo '$(srcdir)/'`codegen_ops_fpu_misc.c + +pcem-codegen_ops_fpu_misc.obj: codegen_ops_fpu_misc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_fpu_misc.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_fpu_misc.Tpo -c -o pcem-codegen_ops_fpu_misc.obj `if test -f 'codegen_ops_fpu_misc.c'; then $(CYGPATH_W) 'codegen_ops_fpu_misc.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_fpu_misc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_fpu_misc.Tpo $(DEPDIR)/pcem-codegen_ops_fpu_misc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_fpu_misc.c' object='pcem-codegen_ops_fpu_misc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_fpu_misc.obj `if test -f 'codegen_ops_fpu_misc.c'; then $(CYGPATH_W) 'codegen_ops_fpu_misc.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_fpu_misc.c'; fi` + +pcem-codegen_ops_mmx_arith.o: codegen_ops_mmx_arith.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_arith.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_arith.Tpo -c -o pcem-codegen_ops_mmx_arith.o `test -f 'codegen_ops_mmx_arith.c' || echo '$(srcdir)/'`codegen_ops_mmx_arith.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_arith.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_arith.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_arith.c' object='pcem-codegen_ops_mmx_arith.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_arith.o `test -f 'codegen_ops_mmx_arith.c' || echo '$(srcdir)/'`codegen_ops_mmx_arith.c + +pcem-codegen_ops_mmx_arith.obj: codegen_ops_mmx_arith.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_arith.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_arith.Tpo -c -o pcem-codegen_ops_mmx_arith.obj `if test -f 'codegen_ops_mmx_arith.c'; then $(CYGPATH_W) 'codegen_ops_mmx_arith.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_arith.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_arith.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_arith.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_arith.c' object='pcem-codegen_ops_mmx_arith.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_arith.obj `if test -f 'codegen_ops_mmx_arith.c'; then $(CYGPATH_W) 'codegen_ops_mmx_arith.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_arith.c'; fi` + +pcem-codegen_ops_mmx_cmp.o: codegen_ops_mmx_cmp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_cmp.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_cmp.Tpo -c -o pcem-codegen_ops_mmx_cmp.o `test -f 'codegen_ops_mmx_cmp.c' || echo '$(srcdir)/'`codegen_ops_mmx_cmp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_cmp.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_cmp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_cmp.c' object='pcem-codegen_ops_mmx_cmp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_cmp.o `test -f 'codegen_ops_mmx_cmp.c' || echo '$(srcdir)/'`codegen_ops_mmx_cmp.c + +pcem-codegen_ops_mmx_cmp.obj: codegen_ops_mmx_cmp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_cmp.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_cmp.Tpo -c -o pcem-codegen_ops_mmx_cmp.obj `if test -f 'codegen_ops_mmx_cmp.c'; then $(CYGPATH_W) 'codegen_ops_mmx_cmp.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_cmp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_cmp.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_cmp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_cmp.c' object='pcem-codegen_ops_mmx_cmp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_cmp.obj `if test -f 'codegen_ops_mmx_cmp.c'; then $(CYGPATH_W) 'codegen_ops_mmx_cmp.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_cmp.c'; fi` + +pcem-codegen_ops_mmx_loadstore.o: codegen_ops_mmx_loadstore.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_loadstore.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Tpo -c -o pcem-codegen_ops_mmx_loadstore.o `test -f 'codegen_ops_mmx_loadstore.c' || echo '$(srcdir)/'`codegen_ops_mmx_loadstore.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_loadstore.c' object='pcem-codegen_ops_mmx_loadstore.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_loadstore.o `test -f 'codegen_ops_mmx_loadstore.c' || echo '$(srcdir)/'`codegen_ops_mmx_loadstore.c + +pcem-codegen_ops_mmx_loadstore.obj: codegen_ops_mmx_loadstore.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_loadstore.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Tpo -c -o pcem-codegen_ops_mmx_loadstore.obj `if test -f 'codegen_ops_mmx_loadstore.c'; then $(CYGPATH_W) 'codegen_ops_mmx_loadstore.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_loadstore.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_loadstore.c' object='pcem-codegen_ops_mmx_loadstore.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_loadstore.obj `if test -f 'codegen_ops_mmx_loadstore.c'; then $(CYGPATH_W) 'codegen_ops_mmx_loadstore.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_loadstore.c'; fi` + +pcem-codegen_ops_mmx_logic.o: codegen_ops_mmx_logic.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_logic.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_logic.Tpo -c -o pcem-codegen_ops_mmx_logic.o `test -f 'codegen_ops_mmx_logic.c' || echo '$(srcdir)/'`codegen_ops_mmx_logic.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_logic.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_logic.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_logic.c' object='pcem-codegen_ops_mmx_logic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_logic.o `test -f 'codegen_ops_mmx_logic.c' || echo '$(srcdir)/'`codegen_ops_mmx_logic.c + +pcem-codegen_ops_mmx_logic.obj: codegen_ops_mmx_logic.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_logic.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_logic.Tpo -c -o pcem-codegen_ops_mmx_logic.obj `if test -f 'codegen_ops_mmx_logic.c'; then $(CYGPATH_W) 'codegen_ops_mmx_logic.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_logic.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_logic.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_logic.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_logic.c' object='pcem-codegen_ops_mmx_logic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_logic.obj `if test -f 'codegen_ops_mmx_logic.c'; then $(CYGPATH_W) 'codegen_ops_mmx_logic.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_logic.c'; fi` + +pcem-codegen_ops_mmx_pack.o: codegen_ops_mmx_pack.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_pack.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_pack.Tpo -c -o pcem-codegen_ops_mmx_pack.o `test -f 'codegen_ops_mmx_pack.c' || echo '$(srcdir)/'`codegen_ops_mmx_pack.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_pack.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_pack.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_pack.c' object='pcem-codegen_ops_mmx_pack.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_pack.o `test -f 'codegen_ops_mmx_pack.c' || echo '$(srcdir)/'`codegen_ops_mmx_pack.c + +pcem-codegen_ops_mmx_pack.obj: codegen_ops_mmx_pack.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_pack.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_pack.Tpo -c -o pcem-codegen_ops_mmx_pack.obj `if test -f 'codegen_ops_mmx_pack.c'; then $(CYGPATH_W) 'codegen_ops_mmx_pack.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_pack.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_pack.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_pack.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_pack.c' object='pcem-codegen_ops_mmx_pack.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_pack.obj `if test -f 'codegen_ops_mmx_pack.c'; then $(CYGPATH_W) 'codegen_ops_mmx_pack.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_pack.c'; fi` + +pcem-codegen_ops_mmx_shift.o: codegen_ops_mmx_shift.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_shift.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_shift.Tpo -c -o pcem-codegen_ops_mmx_shift.o `test -f 'codegen_ops_mmx_shift.c' || echo '$(srcdir)/'`codegen_ops_mmx_shift.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_shift.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_shift.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_shift.c' object='pcem-codegen_ops_mmx_shift.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_shift.o `test -f 'codegen_ops_mmx_shift.c' || echo '$(srcdir)/'`codegen_ops_mmx_shift.c + +pcem-codegen_ops_mmx_shift.obj: codegen_ops_mmx_shift.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mmx_shift.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mmx_shift.Tpo -c -o pcem-codegen_ops_mmx_shift.obj `if test -f 'codegen_ops_mmx_shift.c'; then $(CYGPATH_W) 'codegen_ops_mmx_shift.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_shift.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mmx_shift.Tpo $(DEPDIR)/pcem-codegen_ops_mmx_shift.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mmx_shift.c' object='pcem-codegen_ops_mmx_shift.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mmx_shift.obj `if test -f 'codegen_ops_mmx_shift.c'; then $(CYGPATH_W) 'codegen_ops_mmx_shift.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mmx_shift.c'; fi` + +pcem-codegen_ops_helpers.o: codegen_ops_helpers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_helpers.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_helpers.Tpo -c -o pcem-codegen_ops_helpers.o `test -f 'codegen_ops_helpers.c' || echo '$(srcdir)/'`codegen_ops_helpers.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_helpers.Tpo $(DEPDIR)/pcem-codegen_ops_helpers.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_helpers.c' object='pcem-codegen_ops_helpers.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_helpers.o `test -f 'codegen_ops_helpers.c' || echo '$(srcdir)/'`codegen_ops_helpers.c + +pcem-codegen_ops_helpers.obj: codegen_ops_helpers.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_helpers.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_helpers.Tpo -c -o pcem-codegen_ops_helpers.obj `if test -f 'codegen_ops_helpers.c'; then $(CYGPATH_W) 'codegen_ops_helpers.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_helpers.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_helpers.Tpo $(DEPDIR)/pcem-codegen_ops_helpers.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_helpers.c' object='pcem-codegen_ops_helpers.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_helpers.obj `if test -f 'codegen_ops_helpers.c'; then $(CYGPATH_W) 'codegen_ops_helpers.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_helpers.c'; fi` + +pcem-codegen_ops_jump.o: codegen_ops_jump.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_jump.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_jump.Tpo -c -o pcem-codegen_ops_jump.o `test -f 'codegen_ops_jump.c' || echo '$(srcdir)/'`codegen_ops_jump.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_jump.Tpo $(DEPDIR)/pcem-codegen_ops_jump.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_jump.c' object='pcem-codegen_ops_jump.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_jump.o `test -f 'codegen_ops_jump.c' || echo '$(srcdir)/'`codegen_ops_jump.c + +pcem-codegen_ops_jump.obj: codegen_ops_jump.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_jump.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_jump.Tpo -c -o pcem-codegen_ops_jump.obj `if test -f 'codegen_ops_jump.c'; then $(CYGPATH_W) 'codegen_ops_jump.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_jump.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_jump.Tpo $(DEPDIR)/pcem-codegen_ops_jump.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_jump.c' object='pcem-codegen_ops_jump.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_jump.obj `if test -f 'codegen_ops_jump.c'; then $(CYGPATH_W) 'codegen_ops_jump.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_jump.c'; fi` + +pcem-codegen_ops_logic.o: codegen_ops_logic.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_logic.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_logic.Tpo -c -o pcem-codegen_ops_logic.o `test -f 'codegen_ops_logic.c' || echo '$(srcdir)/'`codegen_ops_logic.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_logic.Tpo $(DEPDIR)/pcem-codegen_ops_logic.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_logic.c' object='pcem-codegen_ops_logic.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_logic.o `test -f 'codegen_ops_logic.c' || echo '$(srcdir)/'`codegen_ops_logic.c + +pcem-codegen_ops_logic.obj: codegen_ops_logic.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_logic.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_logic.Tpo -c -o pcem-codegen_ops_logic.obj `if test -f 'codegen_ops_logic.c'; then $(CYGPATH_W) 'codegen_ops_logic.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_logic.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_logic.Tpo $(DEPDIR)/pcem-codegen_ops_logic.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_logic.c' object='pcem-codegen_ops_logic.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_logic.obj `if test -f 'codegen_ops_logic.c'; then $(CYGPATH_W) 'codegen_ops_logic.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_logic.c'; fi` + +pcem-codegen_ops_shift.o: codegen_ops_shift.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_shift.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_shift.Tpo -c -o pcem-codegen_ops_shift.o `test -f 'codegen_ops_shift.c' || echo '$(srcdir)/'`codegen_ops_shift.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_shift.Tpo $(DEPDIR)/pcem-codegen_ops_shift.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_shift.c' object='pcem-codegen_ops_shift.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_shift.o `test -f 'codegen_ops_shift.c' || echo '$(srcdir)/'`codegen_ops_shift.c + +pcem-codegen_ops_shift.obj: codegen_ops_shift.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_shift.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_shift.Tpo -c -o pcem-codegen_ops_shift.obj `if test -f 'codegen_ops_shift.c'; then $(CYGPATH_W) 'codegen_ops_shift.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_shift.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_shift.Tpo $(DEPDIR)/pcem-codegen_ops_shift.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_shift.c' object='pcem-codegen_ops_shift.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_shift.obj `if test -f 'codegen_ops_shift.c'; then $(CYGPATH_W) 'codegen_ops_shift.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_shift.c'; fi` + +pcem-codegen_ops_misc.o: codegen_ops_misc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_misc.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_misc.Tpo -c -o pcem-codegen_ops_misc.o `test -f 'codegen_ops_misc.c' || echo '$(srcdir)/'`codegen_ops_misc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_misc.Tpo $(DEPDIR)/pcem-codegen_ops_misc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_misc.c' object='pcem-codegen_ops_misc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_misc.o `test -f 'codegen_ops_misc.c' || echo '$(srcdir)/'`codegen_ops_misc.c + +pcem-codegen_ops_misc.obj: codegen_ops_misc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_misc.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_misc.Tpo -c -o pcem-codegen_ops_misc.obj `if test -f 'codegen_ops_misc.c'; then $(CYGPATH_W) 'codegen_ops_misc.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_misc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_misc.Tpo $(DEPDIR)/pcem-codegen_ops_misc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_misc.c' object='pcem-codegen_ops_misc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_misc.obj `if test -f 'codegen_ops_misc.c'; then $(CYGPATH_W) 'codegen_ops_misc.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_misc.c'; fi` + +pcem-codegen_ops_mov.o: codegen_ops_mov.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mov.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mov.Tpo -c -o pcem-codegen_ops_mov.o `test -f 'codegen_ops_mov.c' || echo '$(srcdir)/'`codegen_ops_mov.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mov.Tpo $(DEPDIR)/pcem-codegen_ops_mov.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mov.c' object='pcem-codegen_ops_mov.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mov.o `test -f 'codegen_ops_mov.c' || echo '$(srcdir)/'`codegen_ops_mov.c + +pcem-codegen_ops_mov.obj: codegen_ops_mov.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_mov.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_mov.Tpo -c -o pcem-codegen_ops_mov.obj `if test -f 'codegen_ops_mov.c'; then $(CYGPATH_W) 'codegen_ops_mov.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mov.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_mov.Tpo $(DEPDIR)/pcem-codegen_ops_mov.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_mov.c' object='pcem-codegen_ops_mov.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_mov.obj `if test -f 'codegen_ops_mov.c'; then $(CYGPATH_W) 'codegen_ops_mov.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_mov.c'; fi` + +pcem-codegen_ops_stack.o: codegen_ops_stack.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_stack.o -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_stack.Tpo -c -o pcem-codegen_ops_stack.o `test -f 'codegen_ops_stack.c' || echo '$(srcdir)/'`codegen_ops_stack.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_stack.Tpo $(DEPDIR)/pcem-codegen_ops_stack.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_stack.c' object='pcem-codegen_ops_stack.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_stack.o `test -f 'codegen_ops_stack.c' || echo '$(srcdir)/'`codegen_ops_stack.c + +pcem-codegen_ops_stack.obj: codegen_ops_stack.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_ops_stack.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_ops_stack.Tpo -c -o pcem-codegen_ops_stack.obj `if test -f 'codegen_ops_stack.c'; then $(CYGPATH_W) 'codegen_ops_stack.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_stack.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_ops_stack.Tpo $(DEPDIR)/pcem-codegen_ops_stack.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_ops_stack.c' object='pcem-codegen_ops_stack.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_ops_stack.obj `if test -f 'codegen_ops_stack.c'; then $(CYGPATH_W) 'codegen_ops_stack.c'; else $(CYGPATH_W) '$(srcdir)/codegen_ops_stack.c'; fi` + +pcem-codegen_reg.o: codegen_reg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_reg.o -MD -MP -MF $(DEPDIR)/pcem-codegen_reg.Tpo -c -o pcem-codegen_reg.o `test -f 'codegen_reg.c' || echo '$(srcdir)/'`codegen_reg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_reg.Tpo $(DEPDIR)/pcem-codegen_reg.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_reg.c' object='pcem-codegen_reg.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_reg.o `test -f 'codegen_reg.c' || echo '$(srcdir)/'`codegen_reg.c + +pcem-codegen_reg.obj: codegen_reg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_reg.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_reg.Tpo -c -o pcem-codegen_reg.obj `if test -f 'codegen_reg.c'; then $(CYGPATH_W) 'codegen_reg.c'; else $(CYGPATH_W) '$(srcdir)/codegen_reg.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_reg.Tpo $(DEPDIR)/pcem-codegen_reg.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_reg.c' object='pcem-codegen_reg.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_reg.obj `if test -f 'codegen_reg.c'; then $(CYGPATH_W) 'codegen_reg.c'; else $(CYGPATH_W) '$(srcdir)/codegen_reg.c'; fi` + pcem-codegen_timing_486.o: codegen_timing_486.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_486.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_486.Tpo -c -o pcem-codegen_timing_486.o `test -f 'codegen_timing_486.c' || echo '$(srcdir)/'`codegen_timing_486.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_486.Tpo $(DEPDIR)/pcem-codegen_timing_486.Po @@ -1112,6 +2246,62 @@ pcem-codegen_timing_686.obj: codegen_timing_686.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_686.obj `if test -f 'codegen_timing_686.c'; then $(CYGPATH_W) 'codegen_timing_686.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_686.c'; fi` +pcem-codegen_timing_common.o: codegen_timing_common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_common.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_common.Tpo -c -o pcem-codegen_timing_common.o `test -f 'codegen_timing_common.c' || echo '$(srcdir)/'`codegen_timing_common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_common.Tpo $(DEPDIR)/pcem-codegen_timing_common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_common.c' object='pcem-codegen_timing_common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_common.o `test -f 'codegen_timing_common.c' || echo '$(srcdir)/'`codegen_timing_common.c + +pcem-codegen_timing_common.obj: codegen_timing_common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_common.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_common.Tpo -c -o pcem-codegen_timing_common.obj `if test -f 'codegen_timing_common.c'; then $(CYGPATH_W) 'codegen_timing_common.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_common.Tpo $(DEPDIR)/pcem-codegen_timing_common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_common.c' object='pcem-codegen_timing_common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_common.obj `if test -f 'codegen_timing_common.c'; then $(CYGPATH_W) 'codegen_timing_common.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_common.c'; fi` + +pcem-codegen_timing_cyrixiii.o: codegen_timing_cyrixiii.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_cyrixiii.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_cyrixiii.Tpo -c -o pcem-codegen_timing_cyrixiii.o `test -f 'codegen_timing_cyrixiii.c' || echo '$(srcdir)/'`codegen_timing_cyrixiii.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_cyrixiii.Tpo $(DEPDIR)/pcem-codegen_timing_cyrixiii.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_cyrixiii.c' object='pcem-codegen_timing_cyrixiii.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_cyrixiii.o `test -f 'codegen_timing_cyrixiii.c' || echo '$(srcdir)/'`codegen_timing_cyrixiii.c + +pcem-codegen_timing_cyrixiii.obj: codegen_timing_cyrixiii.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_cyrixiii.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_cyrixiii.Tpo -c -o pcem-codegen_timing_cyrixiii.obj `if test -f 'codegen_timing_cyrixiii.c'; then $(CYGPATH_W) 'codegen_timing_cyrixiii.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_cyrixiii.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_cyrixiii.Tpo $(DEPDIR)/pcem-codegen_timing_cyrixiii.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_cyrixiii.c' object='pcem-codegen_timing_cyrixiii.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_cyrixiii.obj `if test -f 'codegen_timing_cyrixiii.c'; then $(CYGPATH_W) 'codegen_timing_cyrixiii.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_cyrixiii.c'; fi` + +pcem-codegen_timing_k6.o: codegen_timing_k6.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_k6.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_k6.Tpo -c -o pcem-codegen_timing_k6.o `test -f 'codegen_timing_k6.c' || echo '$(srcdir)/'`codegen_timing_k6.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_k6.Tpo $(DEPDIR)/pcem-codegen_timing_k6.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_k6.c' object='pcem-codegen_timing_k6.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_k6.o `test -f 'codegen_timing_k6.c' || echo '$(srcdir)/'`codegen_timing_k6.c + +pcem-codegen_timing_k6.obj: codegen_timing_k6.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_k6.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_k6.Tpo -c -o pcem-codegen_timing_k6.obj `if test -f 'codegen_timing_k6.c'; then $(CYGPATH_W) 'codegen_timing_k6.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_k6.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_k6.Tpo $(DEPDIR)/pcem-codegen_timing_k6.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_k6.c' object='pcem-codegen_timing_k6.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_k6.obj `if test -f 'codegen_timing_k6.c'; then $(CYGPATH_W) 'codegen_timing_k6.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_k6.c'; fi` + +pcem-codegen_timing_p6.o: codegen_timing_p6.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_p6.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_p6.Tpo -c -o pcem-codegen_timing_p6.o `test -f 'codegen_timing_p6.c' || echo '$(srcdir)/'`codegen_timing_p6.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_p6.Tpo $(DEPDIR)/pcem-codegen_timing_p6.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_p6.c' object='pcem-codegen_timing_p6.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_p6.o `test -f 'codegen_timing_p6.c' || echo '$(srcdir)/'`codegen_timing_p6.c + +pcem-codegen_timing_p6.obj: codegen_timing_p6.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_p6.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_p6.Tpo -c -o pcem-codegen_timing_p6.obj `if test -f 'codegen_timing_p6.c'; then $(CYGPATH_W) 'codegen_timing_p6.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_p6.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_p6.Tpo $(DEPDIR)/pcem-codegen_timing_p6.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_p6.c' object='pcem-codegen_timing_p6.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_p6.obj `if test -f 'codegen_timing_p6.c'; then $(CYGPATH_W) 'codegen_timing_p6.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_p6.c'; fi` + pcem-codegen_timing_pentium.o: codegen_timing_pentium.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_pentium.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_pentium.Tpo -c -o pcem-codegen_timing_pentium.o `test -f 'codegen_timing_pentium.c' || echo '$(srcdir)/'`codegen_timing_pentium.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_pentium.Tpo $(DEPDIR)/pcem-codegen_timing_pentium.Po @@ -1140,6 +2330,20 @@ pcem-codegen_timing_winchip.obj: codegen_timing_winchip.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_winchip.obj `if test -f 'codegen_timing_winchip.c'; then $(CYGPATH_W) 'codegen_timing_winchip.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_winchip.c'; fi` +pcem-codegen_timing_winchip2.o: codegen_timing_winchip2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_winchip2.o -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_winchip2.Tpo -c -o pcem-codegen_timing_winchip2.o `test -f 'codegen_timing_winchip2.c' || echo '$(srcdir)/'`codegen_timing_winchip2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_winchip2.Tpo $(DEPDIR)/pcem-codegen_timing_winchip2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_winchip2.c' object='pcem-codegen_timing_winchip2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_winchip2.o `test -f 'codegen_timing_winchip2.c' || echo '$(srcdir)/'`codegen_timing_winchip2.c + +pcem-codegen_timing_winchip2.obj: codegen_timing_winchip2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_timing_winchip2.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_timing_winchip2.Tpo -c -o pcem-codegen_timing_winchip2.obj `if test -f 'codegen_timing_winchip2.c'; then $(CYGPATH_W) 'codegen_timing_winchip2.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_winchip2.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_timing_winchip2.Tpo $(DEPDIR)/pcem-codegen_timing_winchip2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_timing_winchip2.c' object='pcem-codegen_timing_winchip2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_timing_winchip2.obj `if test -f 'codegen_timing_winchip2.c'; then $(CYGPATH_W) 'codegen_timing_winchip2.c'; else $(CYGPATH_W) '$(srcdir)/codegen_timing_winchip2.c'; fi` + pcem-compaq.o: compaq.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-compaq.o -MD -MP -MF $(DEPDIR)/pcem-compaq.Tpo -c -o pcem-compaq.o `test -f 'compaq.c' || echo '$(srcdir)/'`compaq.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-compaq.Tpo $(DEPDIR)/pcem-compaq.Po @@ -1182,19 +2386,47 @@ pcem-cpu.obj: cpu.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cpu.obj `if test -f 'cpu.c'; then $(CYGPATH_W) 'cpu.c'; else $(CYGPATH_W) '$(srcdir)/cpu.c'; fi` -pcem-dac.o: dac.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-dac.o -MD -MP -MF $(DEPDIR)/pcem-dac.Tpo -c -o pcem-dac.o `test -f 'dac.c' || echo '$(srcdir)/'`dac.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-dac.Tpo $(DEPDIR)/pcem-dac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dac.c' object='pcem-dac.o' libtool=no @AMDEPBACKSLASH@ +pcem-cpu_tables.o: cpu_tables.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cpu_tables.o -MD -MP -MF $(DEPDIR)/pcem-cpu_tables.Tpo -c -o pcem-cpu_tables.o `test -f 'cpu_tables.c' || echo '$(srcdir)/'`cpu_tables.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cpu_tables.Tpo $(DEPDIR)/pcem-cpu_tables.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cpu_tables.c' object='pcem-cpu_tables.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dac.o `test -f 'dac.c' || echo '$(srcdir)/'`dac.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cpu_tables.o `test -f 'cpu_tables.c' || echo '$(srcdir)/'`cpu_tables.c -pcem-dac.obj: dac.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-dac.obj -MD -MP -MF $(DEPDIR)/pcem-dac.Tpo -c -o pcem-dac.obj `if test -f 'dac.c'; then $(CYGPATH_W) 'dac.c'; else $(CYGPATH_W) '$(srcdir)/dac.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-dac.Tpo $(DEPDIR)/pcem-dac.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dac.c' object='pcem-dac.obj' libtool=no @AMDEPBACKSLASH@ +pcem-cpu_tables.obj: cpu_tables.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cpu_tables.obj -MD -MP -MF $(DEPDIR)/pcem-cpu_tables.Tpo -c -o pcem-cpu_tables.obj `if test -f 'cpu_tables.c'; then $(CYGPATH_W) 'cpu_tables.c'; else $(CYGPATH_W) '$(srcdir)/cpu_tables.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cpu_tables.Tpo $(DEPDIR)/pcem-cpu_tables.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cpu_tables.c' object='pcem-cpu_tables.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dac.obj `if test -f 'dac.c'; then $(CYGPATH_W) 'dac.c'; else $(CYGPATH_W) '$(srcdir)/dac.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cpu_tables.obj `if test -f 'cpu_tables.c'; then $(CYGPATH_W) 'cpu_tables.c'; else $(CYGPATH_W) '$(srcdir)/cpu_tables.c'; fi` + +pcem-cs8230.o: cs8230.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cs8230.o -MD -MP -MF $(DEPDIR)/pcem-cs8230.Tpo -c -o pcem-cs8230.o `test -f 'cs8230.c' || echo '$(srcdir)/'`cs8230.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cs8230.Tpo $(DEPDIR)/pcem-cs8230.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cs8230.c' object='pcem-cs8230.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cs8230.o `test -f 'cs8230.c' || echo '$(srcdir)/'`cs8230.c + +pcem-cs8230.obj: cs8230.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cs8230.obj -MD -MP -MF $(DEPDIR)/pcem-cs8230.Tpo -c -o pcem-cs8230.obj `if test -f 'cs8230.c'; then $(CYGPATH_W) 'cs8230.c'; else $(CYGPATH_W) '$(srcdir)/cs8230.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cs8230.Tpo $(DEPDIR)/pcem-cs8230.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cs8230.c' object='pcem-cs8230.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cs8230.obj `if test -f 'cs8230.c'; then $(CYGPATH_W) 'cs8230.c'; else $(CYGPATH_W) '$(srcdir)/cs8230.c'; fi` + +pcem-dells200.o: dells200.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-dells200.o -MD -MP -MF $(DEPDIR)/pcem-dells200.Tpo -c -o pcem-dells200.o `test -f 'dells200.c' || echo '$(srcdir)/'`dells200.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-dells200.Tpo $(DEPDIR)/pcem-dells200.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dells200.c' object='pcem-dells200.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dells200.o `test -f 'dells200.c' || echo '$(srcdir)/'`dells200.c + +pcem-dells200.obj: dells200.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-dells200.obj -MD -MP -MF $(DEPDIR)/pcem-dells200.Tpo -c -o pcem-dells200.obj `if test -f 'dells200.c'; then $(CYGPATH_W) 'dells200.c'; else $(CYGPATH_W) '$(srcdir)/dells200.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-dells200.Tpo $(DEPDIR)/pcem-dells200.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dells200.c' object='pcem-dells200.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dells200.obj `if test -f 'dells200.c'; then $(CYGPATH_W) 'dells200.c'; else $(CYGPATH_W) '$(srcdir)/dells200.c'; fi` pcem-device.o: device.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-device.o -MD -MP -MF $(DEPDIR)/pcem-device.Tpo -c -o pcem-device.o `test -f 'device.c' || echo '$(srcdir)/'`device.c @@ -1280,6 +2512,34 @@ pcem-dma.obj: dma.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-dma.obj `if test -f 'dma.c'; then $(CYGPATH_W) 'dma.c'; else $(CYGPATH_W) '$(srcdir)/dma.c'; fi` +pcem-esdi_at.o: esdi_at.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-esdi_at.o -MD -MP -MF $(DEPDIR)/pcem-esdi_at.Tpo -c -o pcem-esdi_at.o `test -f 'esdi_at.c' || echo '$(srcdir)/'`esdi_at.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-esdi_at.Tpo $(DEPDIR)/pcem-esdi_at.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='esdi_at.c' object='pcem-esdi_at.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-esdi_at.o `test -f 'esdi_at.c' || echo '$(srcdir)/'`esdi_at.c + +pcem-esdi_at.obj: esdi_at.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-esdi_at.obj -MD -MP -MF $(DEPDIR)/pcem-esdi_at.Tpo -c -o pcem-esdi_at.obj `if test -f 'esdi_at.c'; then $(CYGPATH_W) 'esdi_at.c'; else $(CYGPATH_W) '$(srcdir)/esdi_at.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-esdi_at.Tpo $(DEPDIR)/pcem-esdi_at.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='esdi_at.c' object='pcem-esdi_at.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-esdi_at.obj `if test -f 'esdi_at.c'; then $(CYGPATH_W) 'esdi_at.c'; else $(CYGPATH_W) '$(srcdir)/esdi_at.c'; fi` + +pcem-f82c710_upc.o: f82c710_upc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-f82c710_upc.o -MD -MP -MF $(DEPDIR)/pcem-f82c710_upc.Tpo -c -o pcem-f82c710_upc.o `test -f 'f82c710_upc.c' || echo '$(srcdir)/'`f82c710_upc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-f82c710_upc.Tpo $(DEPDIR)/pcem-f82c710_upc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f82c710_upc.c' object='pcem-f82c710_upc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-f82c710_upc.o `test -f 'f82c710_upc.c' || echo '$(srcdir)/'`f82c710_upc.c + +pcem-f82c710_upc.obj: f82c710_upc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-f82c710_upc.obj -MD -MP -MF $(DEPDIR)/pcem-f82c710_upc.Tpo -c -o pcem-f82c710_upc.obj `if test -f 'f82c710_upc.c'; then $(CYGPATH_W) 'f82c710_upc.c'; else $(CYGPATH_W) '$(srcdir)/f82c710_upc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-f82c710_upc.Tpo $(DEPDIR)/pcem-f82c710_upc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='f82c710_upc.c' object='pcem-f82c710_upc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-f82c710_upc.obj `if test -f 'f82c710_upc.c'; then $(CYGPATH_W) 'f82c710_upc.c'; else $(CYGPATH_W) '$(srcdir)/f82c710_upc.c'; fi` + pcem-fdc.o: fdc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdc.o -MD -MP -MF $(DEPDIR)/pcem-fdc.Tpo -c -o pcem-fdc.o `test -f 'fdc.c' || echo '$(srcdir)/'`fdc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-fdc.Tpo $(DEPDIR)/pcem-fdc.Po @@ -1308,6 +2568,20 @@ pcem-fdc37c665.obj: fdc37c665.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdc37c665.obj `if test -f 'fdc37c665.c'; then $(CYGPATH_W) 'fdc37c665.c'; else $(CYGPATH_W) '$(srcdir)/fdc37c665.c'; fi` +pcem-fdc37c93x.o: fdc37c93x.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdc37c93x.o -MD -MP -MF $(DEPDIR)/pcem-fdc37c93x.Tpo -c -o pcem-fdc37c93x.o `test -f 'fdc37c93x.c' || echo '$(srcdir)/'`fdc37c93x.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-fdc37c93x.Tpo $(DEPDIR)/pcem-fdc37c93x.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdc37c93x.c' object='pcem-fdc37c93x.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdc37c93x.o `test -f 'fdc37c93x.c' || echo '$(srcdir)/'`fdc37c93x.c + +pcem-fdc37c93x.obj: fdc37c93x.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdc37c93x.obj -MD -MP -MF $(DEPDIR)/pcem-fdc37c93x.Tpo -c -o pcem-fdc37c93x.obj `if test -f 'fdc37c93x.c'; then $(CYGPATH_W) 'fdc37c93x.c'; else $(CYGPATH_W) '$(srcdir)/fdc37c93x.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-fdc37c93x.Tpo $(DEPDIR)/pcem-fdc37c93x.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fdc37c93x.c' object='pcem-fdc37c93x.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-fdc37c93x.obj `if test -f 'fdc37c93x.c'; then $(CYGPATH_W) 'fdc37c93x.c'; else $(CYGPATH_W) '$(srcdir)/fdc37c93x.c'; fi` + pcem-fdd.o: fdd.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-fdd.o -MD -MP -MF $(DEPDIR)/pcem-fdd.Tpo -c -o pcem-fdd.o `test -f 'fdd.c' || echo '$(srcdir)/'`fdd.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-fdd.Tpo $(DEPDIR)/pcem-fdd.Po @@ -1378,6 +2652,20 @@ pcem-hdd_esdi.obj: hdd_esdi.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-hdd_esdi.obj `if test -f 'hdd_esdi.c'; then $(CYGPATH_W) 'hdd_esdi.c'; else $(CYGPATH_W) '$(srcdir)/hdd_esdi.c'; fi` +pcem-hdd_file.o: hdd_file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-hdd_file.o -MD -MP -MF $(DEPDIR)/pcem-hdd_file.Tpo -c -o pcem-hdd_file.o `test -f 'hdd_file.c' || echo '$(srcdir)/'`hdd_file.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-hdd_file.Tpo $(DEPDIR)/pcem-hdd_file.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hdd_file.c' object='pcem-hdd_file.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-hdd_file.o `test -f 'hdd_file.c' || echo '$(srcdir)/'`hdd_file.c + +pcem-hdd_file.obj: hdd_file.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-hdd_file.obj -MD -MP -MF $(DEPDIR)/pcem-hdd_file.Tpo -c -o pcem-hdd_file.obj `if test -f 'hdd_file.c'; then $(CYGPATH_W) 'hdd_file.c'; else $(CYGPATH_W) '$(srcdir)/hdd_file.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-hdd_file.Tpo $(DEPDIR)/pcem-hdd_file.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hdd_file.c' object='pcem-hdd_file.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-hdd_file.obj `if test -f 'hdd_file.c'; then $(CYGPATH_W) 'hdd_file.c'; else $(CYGPATH_W) '$(srcdir)/hdd_file.c'; fi` + pcem-headland.o: headland.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-headland.o -MD -MP -MF $(DEPDIR)/pcem-headland.Tpo -c -o pcem-headland.o `test -f 'headland.c' || echo '$(srcdir)/'`headland.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-headland.Tpo $(DEPDIR)/pcem-headland.Po @@ -1420,6 +2708,20 @@ pcem-i430fx.obj: i430fx.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430fx.obj `if test -f 'i430fx.c'; then $(CYGPATH_W) 'i430fx.c'; else $(CYGPATH_W) '$(srcdir)/i430fx.c'; fi` +pcem-i430hx.o: i430hx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430hx.o -MD -MP -MF $(DEPDIR)/pcem-i430hx.Tpo -c -o pcem-i430hx.o `test -f 'i430hx.c' || echo '$(srcdir)/'`i430hx.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-i430hx.Tpo $(DEPDIR)/pcem-i430hx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i430hx.c' object='pcem-i430hx.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430hx.o `test -f 'i430hx.c' || echo '$(srcdir)/'`i430hx.c + +pcem-i430hx.obj: i430hx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430hx.obj -MD -MP -MF $(DEPDIR)/pcem-i430hx.Tpo -c -o pcem-i430hx.obj `if test -f 'i430hx.c'; then $(CYGPATH_W) 'i430hx.c'; else $(CYGPATH_W) '$(srcdir)/i430hx.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-i430hx.Tpo $(DEPDIR)/pcem-i430hx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i430hx.c' object='pcem-i430hx.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430hx.obj `if test -f 'i430hx.c'; then $(CYGPATH_W) 'i430hx.c'; else $(CYGPATH_W) '$(srcdir)/i430hx.c'; fi` + pcem-i430vx.o: i430vx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i430vx.o -MD -MP -MF $(DEPDIR)/pcem-i430vx.Tpo -c -o pcem-i430vx.o `test -f 'i430vx.c' || echo '$(srcdir)/'`i430vx.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-i430vx.Tpo $(DEPDIR)/pcem-i430vx.Po @@ -1434,6 +2736,34 @@ pcem-i430vx.obj: i430vx.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i430vx.obj `if test -f 'i430vx.c'; then $(CYGPATH_W) 'i430vx.c'; else $(CYGPATH_W) '$(srcdir)/i430vx.c'; fi` +pcem-i440fx.o: i440fx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i440fx.o -MD -MP -MF $(DEPDIR)/pcem-i440fx.Tpo -c -o pcem-i440fx.o `test -f 'i440fx.c' || echo '$(srcdir)/'`i440fx.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-i440fx.Tpo $(DEPDIR)/pcem-i440fx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i440fx.c' object='pcem-i440fx.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i440fx.o `test -f 'i440fx.c' || echo '$(srcdir)/'`i440fx.c + +pcem-i440fx.obj: i440fx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i440fx.obj -MD -MP -MF $(DEPDIR)/pcem-i440fx.Tpo -c -o pcem-i440fx.obj `if test -f 'i440fx.c'; then $(CYGPATH_W) 'i440fx.c'; else $(CYGPATH_W) '$(srcdir)/i440fx.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-i440fx.Tpo $(DEPDIR)/pcem-i440fx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i440fx.c' object='pcem-i440fx.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i440fx.obj `if test -f 'i440fx.c'; then $(CYGPATH_W) 'i440fx.c'; else $(CYGPATH_W) '$(srcdir)/i440fx.c'; fi` + +pcem-i440bx.o: i440bx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i440bx.o -MD -MP -MF $(DEPDIR)/pcem-i440bx.Tpo -c -o pcem-i440bx.o `test -f 'i440bx.c' || echo '$(srcdir)/'`i440bx.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-i440bx.Tpo $(DEPDIR)/pcem-i440bx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i440bx.c' object='pcem-i440bx.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i440bx.o `test -f 'i440bx.c' || echo '$(srcdir)/'`i440bx.c + +pcem-i440bx.obj: i440bx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-i440bx.obj -MD -MP -MF $(DEPDIR)/pcem-i440bx.Tpo -c -o pcem-i440bx.obj `if test -f 'i440bx.c'; then $(CYGPATH_W) 'i440bx.c'; else $(CYGPATH_W) '$(srcdir)/i440bx.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-i440bx.Tpo $(DEPDIR)/pcem-i440bx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='i440bx.c' object='pcem-i440bx.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-i440bx.obj `if test -f 'i440bx.c'; then $(CYGPATH_W) 'i440bx.c'; else $(CYGPATH_W) '$(srcdir)/i440bx.c'; fi` + pcem-ide.o: ide.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ide.o -MD -MP -MF $(DEPDIR)/pcem-ide.Tpo -c -o pcem-ide.o `test -f 'ide.c' || echo '$(srcdir)/'`ide.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-ide.Tpo $(DEPDIR)/pcem-ide.Po @@ -1448,6 +2778,34 @@ pcem-ide.obj: ide.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ide.obj `if test -f 'ide.c'; then $(CYGPATH_W) 'ide.c'; else $(CYGPATH_W) '$(srcdir)/ide.c'; fi` +pcem-ide_atapi.o: ide_atapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ide_atapi.o -MD -MP -MF $(DEPDIR)/pcem-ide_atapi.Tpo -c -o pcem-ide_atapi.o `test -f 'ide_atapi.c' || echo '$(srcdir)/'`ide_atapi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-ide_atapi.Tpo $(DEPDIR)/pcem-ide_atapi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ide_atapi.c' object='pcem-ide_atapi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ide_atapi.o `test -f 'ide_atapi.c' || echo '$(srcdir)/'`ide_atapi.c + +pcem-ide_atapi.obj: ide_atapi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ide_atapi.obj -MD -MP -MF $(DEPDIR)/pcem-ide_atapi.Tpo -c -o pcem-ide_atapi.obj `if test -f 'ide_atapi.c'; then $(CYGPATH_W) 'ide_atapi.c'; else $(CYGPATH_W) '$(srcdir)/ide_atapi.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-ide_atapi.Tpo $(DEPDIR)/pcem-ide_atapi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ide_atapi.c' object='pcem-ide_atapi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ide_atapi.obj `if test -f 'ide_atapi.c'; then $(CYGPATH_W) 'ide_atapi.c'; else $(CYGPATH_W) '$(srcdir)/ide_atapi.c'; fi` + +pcem-ide_sff8038i.o: ide_sff8038i.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ide_sff8038i.o -MD -MP -MF $(DEPDIR)/pcem-ide_sff8038i.Tpo -c -o pcem-ide_sff8038i.o `test -f 'ide_sff8038i.c' || echo '$(srcdir)/'`ide_sff8038i.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-ide_sff8038i.Tpo $(DEPDIR)/pcem-ide_sff8038i.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ide_sff8038i.c' object='pcem-ide_sff8038i.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ide_sff8038i.o `test -f 'ide_sff8038i.c' || echo '$(srcdir)/'`ide_sff8038i.c + +pcem-ide_sff8038i.obj: ide_sff8038i.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ide_sff8038i.obj -MD -MP -MF $(DEPDIR)/pcem-ide_sff8038i.Tpo -c -o pcem-ide_sff8038i.obj `if test -f 'ide_sff8038i.c'; then $(CYGPATH_W) 'ide_sff8038i.c'; else $(CYGPATH_W) '$(srcdir)/ide_sff8038i.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-ide_sff8038i.Tpo $(DEPDIR)/pcem-ide_sff8038i.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ide_sff8038i.c' object='pcem-ide_sff8038i.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ide_sff8038i.obj `if test -f 'ide_sff8038i.c'; then $(CYGPATH_W) 'ide_sff8038i.c'; else $(CYGPATH_W) '$(srcdir)/ide_sff8038i.c'; fi` + pcem-intel.o: intel.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-intel.o -MD -MP -MF $(DEPDIR)/pcem-intel.Tpo -c -o pcem-intel.o `test -f 'intel.c' || echo '$(srcdir)/'`intel.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-intel.Tpo $(DEPDIR)/pcem-intel.Po @@ -1644,6 +3002,20 @@ pcem-keyboard_xt.obj: keyboard_xt.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-keyboard_xt.obj `if test -f 'keyboard_xt.c'; then $(CYGPATH_W) 'keyboard_xt.c'; else $(CYGPATH_W) '$(srcdir)/keyboard_xt.c'; fi` +pcem-laserxt.o: laserxt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-laserxt.o -MD -MP -MF $(DEPDIR)/pcem-laserxt.Tpo -c -o pcem-laserxt.o `test -f 'laserxt.c' || echo '$(srcdir)/'`laserxt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-laserxt.Tpo $(DEPDIR)/pcem-laserxt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='laserxt.c' object='pcem-laserxt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-laserxt.o `test -f 'laserxt.c' || echo '$(srcdir)/'`laserxt.c + +pcem-laserxt.obj: laserxt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-laserxt.obj -MD -MP -MF $(DEPDIR)/pcem-laserxt.Tpo -c -o pcem-laserxt.obj `if test -f 'laserxt.c'; then $(CYGPATH_W) 'laserxt.c'; else $(CYGPATH_W) '$(srcdir)/laserxt.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-laserxt.Tpo $(DEPDIR)/pcem-laserxt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='laserxt.c' object='pcem-laserxt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-laserxt.obj `if test -f 'laserxt.c'; then $(CYGPATH_W) 'laserxt.c'; else $(CYGPATH_W) '$(srcdir)/laserxt.c'; fi` + pcem-lpt.o: lpt.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-lpt.o -MD -MP -MF $(DEPDIR)/pcem-lpt.Tpo -c -o pcem-lpt.o `test -f 'lpt.c' || echo '$(srcdir)/'`lpt.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-lpt.Tpo $(DEPDIR)/pcem-lpt.Po @@ -1658,6 +3030,34 @@ pcem-lpt.obj: lpt.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-lpt.obj `if test -f 'lpt.c'; then $(CYGPATH_W) 'lpt.c'; else $(CYGPATH_W) '$(srcdir)/lpt.c'; fi` +pcem-lpt_dac.o: lpt_dac.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-lpt_dac.o -MD -MP -MF $(DEPDIR)/pcem-lpt_dac.Tpo -c -o pcem-lpt_dac.o `test -f 'lpt_dac.c' || echo '$(srcdir)/'`lpt_dac.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-lpt_dac.Tpo $(DEPDIR)/pcem-lpt_dac.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lpt_dac.c' object='pcem-lpt_dac.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-lpt_dac.o `test -f 'lpt_dac.c' || echo '$(srcdir)/'`lpt_dac.c + +pcem-lpt_dac.obj: lpt_dac.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-lpt_dac.obj -MD -MP -MF $(DEPDIR)/pcem-lpt_dac.Tpo -c -o pcem-lpt_dac.obj `if test -f 'lpt_dac.c'; then $(CYGPATH_W) 'lpt_dac.c'; else $(CYGPATH_W) '$(srcdir)/lpt_dac.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-lpt_dac.Tpo $(DEPDIR)/pcem-lpt_dac.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lpt_dac.c' object='pcem-lpt_dac.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-lpt_dac.obj `if test -f 'lpt_dac.c'; then $(CYGPATH_W) 'lpt_dac.c'; else $(CYGPATH_W) '$(srcdir)/lpt_dac.c'; fi` + +pcem-lpt_dss.o: lpt_dss.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-lpt_dss.o -MD -MP -MF $(DEPDIR)/pcem-lpt_dss.Tpo -c -o pcem-lpt_dss.o `test -f 'lpt_dss.c' || echo '$(srcdir)/'`lpt_dss.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-lpt_dss.Tpo $(DEPDIR)/pcem-lpt_dss.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lpt_dss.c' object='pcem-lpt_dss.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-lpt_dss.o `test -f 'lpt_dss.c' || echo '$(srcdir)/'`lpt_dss.c + +pcem-lpt_dss.obj: lpt_dss.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-lpt_dss.obj -MD -MP -MF $(DEPDIR)/pcem-lpt_dss.Tpo -c -o pcem-lpt_dss.obj `if test -f 'lpt_dss.c'; then $(CYGPATH_W) 'lpt_dss.c'; else $(CYGPATH_W) '$(srcdir)/lpt_dss.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-lpt_dss.Tpo $(DEPDIR)/pcem-lpt_dss.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lpt_dss.c' object='pcem-lpt_dss.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-lpt_dss.obj `if test -f 'lpt_dss.c'; then $(CYGPATH_W) 'lpt_dss.c'; else $(CYGPATH_W) '$(srcdir)/lpt_dss.c'; fi` + pcem-mca.o: mca.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mca.o -MD -MP -MF $(DEPDIR)/pcem-mca.Tpo -c -o pcem-mca.o `test -f 'mca.c' || echo '$(srcdir)/'`mca.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mca.Tpo $(DEPDIR)/pcem-mca.Po @@ -1700,6 +3100,20 @@ pcem-mem.obj: mem.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mem.obj `if test -f 'mem.c'; then $(CYGPATH_W) 'mem.c'; else $(CYGPATH_W) '$(srcdir)/mem.c'; fi` +pcem-mem_bios.o: mem_bios.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mem_bios.o -MD -MP -MF $(DEPDIR)/pcem-mem_bios.Tpo -c -o pcem-mem_bios.o `test -f 'mem_bios.c' || echo '$(srcdir)/'`mem_bios.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mem_bios.Tpo $(DEPDIR)/pcem-mem_bios.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mem_bios.c' object='pcem-mem_bios.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mem_bios.o `test -f 'mem_bios.c' || echo '$(srcdir)/'`mem_bios.c + +pcem-mem_bios.obj: mem_bios.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mem_bios.obj -MD -MP -MF $(DEPDIR)/pcem-mem_bios.Tpo -c -o pcem-mem_bios.obj `if test -f 'mem_bios.c'; then $(CYGPATH_W) 'mem_bios.c'; else $(CYGPATH_W) '$(srcdir)/mem_bios.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mem_bios.Tpo $(DEPDIR)/pcem-mem_bios.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mem_bios.c' object='pcem-mem_bios.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mem_bios.obj `if test -f 'mem_bios.c'; then $(CYGPATH_W) 'mem_bios.c'; else $(CYGPATH_W) '$(srcdir)/mem_bios.c'; fi` + pcem-mfm_at.o: mfm_at.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mfm_at.o -MD -MP -MF $(DEPDIR)/pcem-mfm_at.Tpo -c -o pcem-mfm_at.o `test -f 'mfm_at.c' || echo '$(srcdir)/'`mfm_at.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mfm_at.Tpo $(DEPDIR)/pcem-mfm_at.Po @@ -1756,6 +3170,20 @@ pcem-mouse.obj: mouse.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse.obj `if test -f 'mouse.c'; then $(CYGPATH_W) 'mouse.c'; else $(CYGPATH_W) '$(srcdir)/mouse.c'; fi` +pcem-mouse_msystems.o: mouse_msystems.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse_msystems.o -MD -MP -MF $(DEPDIR)/pcem-mouse_msystems.Tpo -c -o pcem-mouse_msystems.o `test -f 'mouse_msystems.c' || echo '$(srcdir)/'`mouse_msystems.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mouse_msystems.Tpo $(DEPDIR)/pcem-mouse_msystems.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mouse_msystems.c' object='pcem-mouse_msystems.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse_msystems.o `test -f 'mouse_msystems.c' || echo '$(srcdir)/'`mouse_msystems.c + +pcem-mouse_msystems.obj: mouse_msystems.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse_msystems.obj -MD -MP -MF $(DEPDIR)/pcem-mouse_msystems.Tpo -c -o pcem-mouse_msystems.obj `if test -f 'mouse_msystems.c'; then $(CYGPATH_W) 'mouse_msystems.c'; else $(CYGPATH_W) '$(srcdir)/mouse_msystems.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mouse_msystems.Tpo $(DEPDIR)/pcem-mouse_msystems.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mouse_msystems.c' object='pcem-mouse_msystems.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse_msystems.obj `if test -f 'mouse_msystems.c'; then $(CYGPATH_W) 'mouse_msystems.c'; else $(CYGPATH_W) '$(srcdir)/mouse_msystems.c'; fi` + pcem-mouse_ps2.o: mouse_ps2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mouse_ps2.o -MD -MP -MF $(DEPDIR)/pcem-mouse_ps2.Tpo -c -o pcem-mouse_ps2.o `test -f 'mouse_ps2.c' || echo '$(srcdir)/'`mouse_ps2.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mouse_ps2.Tpo $(DEPDIR)/pcem-mouse_ps2.Po @@ -1784,6 +3212,20 @@ pcem-mouse_serial.obj: mouse_serial.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mouse_serial.obj `if test -f 'mouse_serial.c'; then $(CYGPATH_W) 'mouse_serial.c'; else $(CYGPATH_W) '$(srcdir)/mouse_serial.c'; fi` +pcem-mvp3.o: mvp3.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mvp3.o -MD -MP -MF $(DEPDIR)/pcem-mvp3.Tpo -c -o pcem-mvp3.o `test -f 'mvp3.c' || echo '$(srcdir)/'`mvp3.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mvp3.Tpo $(DEPDIR)/pcem-mvp3.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mvp3.c' object='pcem-mvp3.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mvp3.o `test -f 'mvp3.c' || echo '$(srcdir)/'`mvp3.c + +pcem-mvp3.obj: mvp3.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-mvp3.obj -MD -MP -MF $(DEPDIR)/pcem-mvp3.Tpo -c -o pcem-mvp3.obj `if test -f 'mvp3.c'; then $(CYGPATH_W) 'mvp3.c'; else $(CYGPATH_W) '$(srcdir)/mvp3.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-mvp3.Tpo $(DEPDIR)/pcem-mvp3.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mvp3.c' object='pcem-mvp3.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-mvp3.obj `if test -f 'mvp3.c'; then $(CYGPATH_W) 'mvp3.c'; else $(CYGPATH_W) '$(srcdir)/mvp3.c'; fi` + pcem-neat.o: neat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-neat.o -MD -MP -MF $(DEPDIR)/pcem-neat.Tpo -c -o pcem-neat.o `test -f 'neat.c' || echo '$(srcdir)/'`neat.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-neat.Tpo $(DEPDIR)/pcem-neat.Po @@ -1854,6 +3296,20 @@ pcem-opti495.obj: opti495.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-opti495.obj `if test -f 'opti495.c'; then $(CYGPATH_W) 'opti495.c'; else $(CYGPATH_W) '$(srcdir)/opti495.c'; fi` +pcem-paths.o: paths.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-paths.o -MD -MP -MF $(DEPDIR)/pcem-paths.Tpo -c -o pcem-paths.o `test -f 'paths.c' || echo '$(srcdir)/'`paths.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-paths.Tpo $(DEPDIR)/pcem-paths.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='paths.c' object='pcem-paths.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-paths.o `test -f 'paths.c' || echo '$(srcdir)/'`paths.c + +pcem-paths.obj: paths.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-paths.obj -MD -MP -MF $(DEPDIR)/pcem-paths.Tpo -c -o pcem-paths.obj `if test -f 'paths.c'; then $(CYGPATH_W) 'paths.c'; else $(CYGPATH_W) '$(srcdir)/paths.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-paths.Tpo $(DEPDIR)/pcem-paths.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='paths.c' object='pcem-paths.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-paths.obj `if test -f 'paths.c'; then $(CYGPATH_W) 'paths.c'; else $(CYGPATH_W) '$(srcdir)/paths.c'; fi` + pcem-pc.o: pc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pc.o -MD -MP -MF $(DEPDIR)/pcem-pc.Tpo -c -o pcem-pc.o `test -f 'pc.c' || echo '$(srcdir)/'`pc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pc.Tpo $(DEPDIR)/pcem-pc.Po @@ -1868,6 +3324,34 @@ pcem-pc.obj: pc.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pc.obj `if test -f 'pc.c'; then $(CYGPATH_W) 'pc.c'; else $(CYGPATH_W) '$(srcdir)/pc.c'; fi` +pcem-pc87306.o: pc87306.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pc87306.o -MD -MP -MF $(DEPDIR)/pcem-pc87306.Tpo -c -o pcem-pc87306.o `test -f 'pc87306.c' || echo '$(srcdir)/'`pc87306.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pc87306.Tpo $(DEPDIR)/pcem-pc87306.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pc87306.c' object='pcem-pc87306.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pc87306.o `test -f 'pc87306.c' || echo '$(srcdir)/'`pc87306.c + +pcem-pc87306.obj: pc87306.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pc87306.obj -MD -MP -MF $(DEPDIR)/pcem-pc87306.Tpo -c -o pcem-pc87306.obj `if test -f 'pc87306.c'; then $(CYGPATH_W) 'pc87306.c'; else $(CYGPATH_W) '$(srcdir)/pc87306.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pc87306.Tpo $(DEPDIR)/pcem-pc87306.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pc87306.c' object='pcem-pc87306.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pc87306.obj `if test -f 'pc87306.c'; then $(CYGPATH_W) 'pc87306.c'; else $(CYGPATH_W) '$(srcdir)/pc87306.c'; fi` + +pcem-pc87307.o: pc87307.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pc87307.o -MD -MP -MF $(DEPDIR)/pcem-pc87307.Tpo -c -o pcem-pc87307.o `test -f 'pc87307.c' || echo '$(srcdir)/'`pc87307.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pc87307.Tpo $(DEPDIR)/pcem-pc87307.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pc87307.c' object='pcem-pc87307.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pc87307.o `test -f 'pc87307.c' || echo '$(srcdir)/'`pc87307.c + +pcem-pc87307.obj: pc87307.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pc87307.obj -MD -MP -MF $(DEPDIR)/pcem-pc87307.Tpo -c -o pcem-pc87307.obj `if test -f 'pc87307.c'; then $(CYGPATH_W) 'pc87307.c'; else $(CYGPATH_W) '$(srcdir)/pc87307.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pc87307.Tpo $(DEPDIR)/pcem-pc87307.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pc87307.c' object='pcem-pc87307.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pc87307.obj `if test -f 'pc87307.c'; then $(CYGPATH_W) 'pc87307.c'; else $(CYGPATH_W) '$(srcdir)/pc87307.c'; fi` + pcem-pci.o: pci.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pci.o -MD -MP -MF $(DEPDIR)/pcem-pci.Tpo -c -o pcem-pci.o `test -f 'pci.c' || echo '$(srcdir)/'`pci.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pci.Tpo $(DEPDIR)/pcem-pci.Po @@ -1910,6 +3394,20 @@ pcem-piix.obj: piix.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-piix.obj `if test -f 'piix.c'; then $(CYGPATH_W) 'piix.c'; else $(CYGPATH_W) '$(srcdir)/piix.c'; fi` +pcem-piix_pm.o: piix_pm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-piix_pm.o -MD -MP -MF $(DEPDIR)/pcem-piix_pm.Tpo -c -o pcem-piix_pm.o `test -f 'piix_pm.c' || echo '$(srcdir)/'`piix_pm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-piix_pm.Tpo $(DEPDIR)/pcem-piix_pm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='piix_pm.c' object='pcem-piix_pm.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-piix_pm.o `test -f 'piix_pm.c' || echo '$(srcdir)/'`piix_pm.c + +pcem-piix_pm.obj: piix_pm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-piix_pm.obj -MD -MP -MF $(DEPDIR)/pcem-piix_pm.Tpo -c -o pcem-piix_pm.obj `if test -f 'piix_pm.c'; then $(CYGPATH_W) 'piix_pm.c'; else $(CYGPATH_W) '$(srcdir)/piix_pm.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-piix_pm.Tpo $(DEPDIR)/pcem-piix_pm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='piix_pm.c' object='pcem-piix_pm.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-piix_pm.obj `if test -f 'piix_pm.c'; then $(CYGPATH_W) 'piix_pm.c'; else $(CYGPATH_W) '$(srcdir)/piix_pm.c'; fi` + pcem-pit.o: pit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pit.o -MD -MP -MF $(DEPDIR)/pcem-pit.Tpo -c -o pcem-pit.o `test -f 'pit.c' || echo '$(srcdir)/'`pit.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pit.Tpo $(DEPDIR)/pcem-pit.Po @@ -1994,6 +3492,34 @@ pcem-ps2_nvr.obj: ps2_nvr.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ps2_nvr.obj `if test -f 'ps2_nvr.c'; then $(CYGPATH_W) 'ps2_nvr.c'; else $(CYGPATH_W) '$(srcdir)/ps2_nvr.c'; fi` +pcem-nvr_tc8521.o: nvr_tc8521.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-nvr_tc8521.o -MD -MP -MF $(DEPDIR)/pcem-nvr_tc8521.Tpo -c -o pcem-nvr_tc8521.o `test -f 'nvr_tc8521.c' || echo '$(srcdir)/'`nvr_tc8521.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-nvr_tc8521.Tpo $(DEPDIR)/pcem-nvr_tc8521.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nvr_tc8521.c' object='pcem-nvr_tc8521.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-nvr_tc8521.o `test -f 'nvr_tc8521.c' || echo '$(srcdir)/'`nvr_tc8521.c + +pcem-nvr_tc8521.obj: nvr_tc8521.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-nvr_tc8521.obj -MD -MP -MF $(DEPDIR)/pcem-nvr_tc8521.Tpo -c -o pcem-nvr_tc8521.obj `if test -f 'nvr_tc8521.c'; then $(CYGPATH_W) 'nvr_tc8521.c'; else $(CYGPATH_W) '$(srcdir)/nvr_tc8521.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-nvr_tc8521.Tpo $(DEPDIR)/pcem-nvr_tc8521.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nvr_tc8521.c' object='pcem-nvr_tc8521.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-nvr_tc8521.obj `if test -f 'nvr_tc8521.c'; then $(CYGPATH_W) 'nvr_tc8521.c'; else $(CYGPATH_W) '$(srcdir)/nvr_tc8521.c'; fi` + +pcem-pzx.o: pzx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pzx.o -MD -MP -MF $(DEPDIR)/pcem-pzx.Tpo -c -o pcem-pzx.o `test -f 'pzx.c' || echo '$(srcdir)/'`pzx.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pzx.Tpo $(DEPDIR)/pcem-pzx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pzx.c' object='pcem-pzx.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pzx.o `test -f 'pzx.c' || echo '$(srcdir)/'`pzx.c + +pcem-pzx.obj: pzx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-pzx.obj -MD -MP -MF $(DEPDIR)/pcem-pzx.Tpo -c -o pcem-pzx.obj `if test -f 'pzx.c'; then $(CYGPATH_W) 'pzx.c'; else $(CYGPATH_W) '$(srcdir)/pzx.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-pzx.Tpo $(DEPDIR)/pcem-pzx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pzx.c' object='pcem-pzx.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-pzx.obj `if test -f 'pzx.c'; then $(CYGPATH_W) 'pzx.c'; else $(CYGPATH_W) '$(srcdir)/pzx.c'; fi` + pcem-rom.o: rom.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-rom.o -MD -MP -MF $(DEPDIR)/pcem-rom.Tpo -c -o pcem-rom.o `test -f 'rom.c' || echo '$(srcdir)/'`rom.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-rom.Tpo $(DEPDIR)/pcem-rom.Po @@ -2022,6 +3548,34 @@ pcem-rtc.obj: rtc.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-rtc.obj `if test -f 'rtc.c'; then $(CYGPATH_W) 'rtc.c'; else $(CYGPATH_W) '$(srcdir)/rtc.c'; fi` +pcem-rtc_tc8521.o: rtc_tc8521.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-rtc_tc8521.o -MD -MP -MF $(DEPDIR)/pcem-rtc_tc8521.Tpo -c -o pcem-rtc_tc8521.o `test -f 'rtc_tc8521.c' || echo '$(srcdir)/'`rtc_tc8521.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-rtc_tc8521.Tpo $(DEPDIR)/pcem-rtc_tc8521.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtc_tc8521.c' object='pcem-rtc_tc8521.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-rtc_tc8521.o `test -f 'rtc_tc8521.c' || echo '$(srcdir)/'`rtc_tc8521.c + +pcem-rtc_tc8521.obj: rtc_tc8521.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-rtc_tc8521.obj -MD -MP -MF $(DEPDIR)/pcem-rtc_tc8521.Tpo -c -o pcem-rtc_tc8521.obj `if test -f 'rtc_tc8521.c'; then $(CYGPATH_W) 'rtc_tc8521.c'; else $(CYGPATH_W) '$(srcdir)/rtc_tc8521.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-rtc_tc8521.Tpo $(DEPDIR)/pcem-rtc_tc8521.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rtc_tc8521.c' object='pcem-rtc_tc8521.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-rtc_tc8521.obj `if test -f 'rtc_tc8521.c'; then $(CYGPATH_W) 'rtc_tc8521.c'; else $(CYGPATH_W) '$(srcdir)/rtc_tc8521.c'; fi` + +pcem-scamp.o: scamp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scamp.o -MD -MP -MF $(DEPDIR)/pcem-scamp.Tpo -c -o pcem-scamp.o `test -f 'scamp.c' || echo '$(srcdir)/'`scamp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scamp.Tpo $(DEPDIR)/pcem-scamp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scamp.c' object='pcem-scamp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scamp.o `test -f 'scamp.c' || echo '$(srcdir)/'`scamp.c + +pcem-scamp.obj: scamp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scamp.obj -MD -MP -MF $(DEPDIR)/pcem-scamp.Tpo -c -o pcem-scamp.obj `if test -f 'scamp.c'; then $(CYGPATH_W) 'scamp.c'; else $(CYGPATH_W) '$(srcdir)/scamp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scamp.Tpo $(DEPDIR)/pcem-scamp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scamp.c' object='pcem-scamp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scamp.obj `if test -f 'scamp.c'; then $(CYGPATH_W) 'scamp.c'; else $(CYGPATH_W) '$(srcdir)/scamp.c'; fi` + pcem-scat.o: scat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scat.o -MD -MP -MF $(DEPDIR)/pcem-scat.Tpo -c -o pcem-scat.o `test -f 'scat.c' || echo '$(srcdir)/'`scat.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scat.Tpo $(DEPDIR)/pcem-scat.Po @@ -2036,6 +3590,104 @@ pcem-scat.obj: scat.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scat.obj `if test -f 'scat.c'; then $(CYGPATH_W) 'scat.c'; else $(CYGPATH_W) '$(srcdir)/scat.c'; fi` +pcem-scsi.o: scsi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi.o -MD -MP -MF $(DEPDIR)/pcem-scsi.Tpo -c -o pcem-scsi.o `test -f 'scsi.c' || echo '$(srcdir)/'`scsi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi.Tpo $(DEPDIR)/pcem-scsi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi.c' object='pcem-scsi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi.o `test -f 'scsi.c' || echo '$(srcdir)/'`scsi.c + +pcem-scsi.obj: scsi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi.obj -MD -MP -MF $(DEPDIR)/pcem-scsi.Tpo -c -o pcem-scsi.obj `if test -f 'scsi.c'; then $(CYGPATH_W) 'scsi.c'; else $(CYGPATH_W) '$(srcdir)/scsi.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi.Tpo $(DEPDIR)/pcem-scsi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi.c' object='pcem-scsi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi.obj `if test -f 'scsi.c'; then $(CYGPATH_W) 'scsi.c'; else $(CYGPATH_W) '$(srcdir)/scsi.c'; fi` + +pcem-scsi_53c400.o: scsi_53c400.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_53c400.o -MD -MP -MF $(DEPDIR)/pcem-scsi_53c400.Tpo -c -o pcem-scsi_53c400.o `test -f 'scsi_53c400.c' || echo '$(srcdir)/'`scsi_53c400.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_53c400.Tpo $(DEPDIR)/pcem-scsi_53c400.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_53c400.c' object='pcem-scsi_53c400.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_53c400.o `test -f 'scsi_53c400.c' || echo '$(srcdir)/'`scsi_53c400.c + +pcem-scsi_53c400.obj: scsi_53c400.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_53c400.obj -MD -MP -MF $(DEPDIR)/pcem-scsi_53c400.Tpo -c -o pcem-scsi_53c400.obj `if test -f 'scsi_53c400.c'; then $(CYGPATH_W) 'scsi_53c400.c'; else $(CYGPATH_W) '$(srcdir)/scsi_53c400.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_53c400.Tpo $(DEPDIR)/pcem-scsi_53c400.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_53c400.c' object='pcem-scsi_53c400.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_53c400.obj `if test -f 'scsi_53c400.c'; then $(CYGPATH_W) 'scsi_53c400.c'; else $(CYGPATH_W) '$(srcdir)/scsi_53c400.c'; fi` + +pcem-scsi_aha1540.o: scsi_aha1540.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_aha1540.o -MD -MP -MF $(DEPDIR)/pcem-scsi_aha1540.Tpo -c -o pcem-scsi_aha1540.o `test -f 'scsi_aha1540.c' || echo '$(srcdir)/'`scsi_aha1540.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_aha1540.Tpo $(DEPDIR)/pcem-scsi_aha1540.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_aha1540.c' object='pcem-scsi_aha1540.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_aha1540.o `test -f 'scsi_aha1540.c' || echo '$(srcdir)/'`scsi_aha1540.c + +pcem-scsi_aha1540.obj: scsi_aha1540.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_aha1540.obj -MD -MP -MF $(DEPDIR)/pcem-scsi_aha1540.Tpo -c -o pcem-scsi_aha1540.obj `if test -f 'scsi_aha1540.c'; then $(CYGPATH_W) 'scsi_aha1540.c'; else $(CYGPATH_W) '$(srcdir)/scsi_aha1540.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_aha1540.Tpo $(DEPDIR)/pcem-scsi_aha1540.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_aha1540.c' object='pcem-scsi_aha1540.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_aha1540.obj `if test -f 'scsi_aha1540.c'; then $(CYGPATH_W) 'scsi_aha1540.c'; else $(CYGPATH_W) '$(srcdir)/scsi_aha1540.c'; fi` + +pcem-scsi_cd.o: scsi_cd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_cd.o -MD -MP -MF $(DEPDIR)/pcem-scsi_cd.Tpo -c -o pcem-scsi_cd.o `test -f 'scsi_cd.c' || echo '$(srcdir)/'`scsi_cd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_cd.Tpo $(DEPDIR)/pcem-scsi_cd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_cd.c' object='pcem-scsi_cd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_cd.o `test -f 'scsi_cd.c' || echo '$(srcdir)/'`scsi_cd.c + +pcem-scsi_cd.obj: scsi_cd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_cd.obj -MD -MP -MF $(DEPDIR)/pcem-scsi_cd.Tpo -c -o pcem-scsi_cd.obj `if test -f 'scsi_cd.c'; then $(CYGPATH_W) 'scsi_cd.c'; else $(CYGPATH_W) '$(srcdir)/scsi_cd.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_cd.Tpo $(DEPDIR)/pcem-scsi_cd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_cd.c' object='pcem-scsi_cd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_cd.obj `if test -f 'scsi_cd.c'; then $(CYGPATH_W) 'scsi_cd.c'; else $(CYGPATH_W) '$(srcdir)/scsi_cd.c'; fi` + +pcem-scsi_hd.o: scsi_hd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_hd.o -MD -MP -MF $(DEPDIR)/pcem-scsi_hd.Tpo -c -o pcem-scsi_hd.o `test -f 'scsi_hd.c' || echo '$(srcdir)/'`scsi_hd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_hd.Tpo $(DEPDIR)/pcem-scsi_hd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_hd.c' object='pcem-scsi_hd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_hd.o `test -f 'scsi_hd.c' || echo '$(srcdir)/'`scsi_hd.c + +pcem-scsi_hd.obj: scsi_hd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_hd.obj -MD -MP -MF $(DEPDIR)/pcem-scsi_hd.Tpo -c -o pcem-scsi_hd.obj `if test -f 'scsi_hd.c'; then $(CYGPATH_W) 'scsi_hd.c'; else $(CYGPATH_W) '$(srcdir)/scsi_hd.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_hd.Tpo $(DEPDIR)/pcem-scsi_hd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_hd.c' object='pcem-scsi_hd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_hd.obj `if test -f 'scsi_hd.c'; then $(CYGPATH_W) 'scsi_hd.c'; else $(CYGPATH_W) '$(srcdir)/scsi_hd.c'; fi` + +pcem-scsi_ibm.o: scsi_ibm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_ibm.o -MD -MP -MF $(DEPDIR)/pcem-scsi_ibm.Tpo -c -o pcem-scsi_ibm.o `test -f 'scsi_ibm.c' || echo '$(srcdir)/'`scsi_ibm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_ibm.Tpo $(DEPDIR)/pcem-scsi_ibm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_ibm.c' object='pcem-scsi_ibm.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_ibm.o `test -f 'scsi_ibm.c' || echo '$(srcdir)/'`scsi_ibm.c + +pcem-scsi_ibm.obj: scsi_ibm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_ibm.obj -MD -MP -MF $(DEPDIR)/pcem-scsi_ibm.Tpo -c -o pcem-scsi_ibm.obj `if test -f 'scsi_ibm.c'; then $(CYGPATH_W) 'scsi_ibm.c'; else $(CYGPATH_W) '$(srcdir)/scsi_ibm.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_ibm.Tpo $(DEPDIR)/pcem-scsi_ibm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_ibm.c' object='pcem-scsi_ibm.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_ibm.obj `if test -f 'scsi_ibm.c'; then $(CYGPATH_W) 'scsi_ibm.c'; else $(CYGPATH_W) '$(srcdir)/scsi_ibm.c'; fi` + +pcem-scsi_zip.o: scsi_zip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_zip.o -MD -MP -MF $(DEPDIR)/pcem-scsi_zip.Tpo -c -o pcem-scsi_zip.o `test -f 'scsi_zip.c' || echo '$(srcdir)/'`scsi_zip.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_zip.Tpo $(DEPDIR)/pcem-scsi_zip.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_zip.c' object='pcem-scsi_zip.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_zip.o `test -f 'scsi_zip.c' || echo '$(srcdir)/'`scsi_zip.c + +pcem-scsi_zip.obj: scsi_zip.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-scsi_zip.obj -MD -MP -MF $(DEPDIR)/pcem-scsi_zip.Tpo -c -o pcem-scsi_zip.obj `if test -f 'scsi_zip.c'; then $(CYGPATH_W) 'scsi_zip.c'; else $(CYGPATH_W) '$(srcdir)/scsi_zip.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-scsi_zip.Tpo $(DEPDIR)/pcem-scsi_zip.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='scsi_zip.c' object='pcem-scsi_zip.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-scsi_zip.obj `if test -f 'scsi_zip.c'; then $(CYGPATH_W) 'scsi_zip.c'; else $(CYGPATH_W) '$(srcdir)/scsi_zip.c'; fi` + pcem-serial.o: serial.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-serial.o -MD -MP -MF $(DEPDIR)/pcem-serial.Tpo -c -o pcem-serial.o `test -f 'serial.c' || echo '$(srcdir)/'`serial.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-serial.Tpo $(DEPDIR)/pcem-serial.Po @@ -2050,6 +3702,20 @@ pcem-serial.obj: serial.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-serial.obj `if test -f 'serial.c'; then $(CYGPATH_W) 'serial.c'; else $(CYGPATH_W) '$(srcdir)/serial.c'; fi` +pcem-sio.o: sio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sio.o -MD -MP -MF $(DEPDIR)/pcem-sio.Tpo -c -o pcem-sio.o `test -f 'sio.c' || echo '$(srcdir)/'`sio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sio.Tpo $(DEPDIR)/pcem-sio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sio.c' object='pcem-sio.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sio.o `test -f 'sio.c' || echo '$(srcdir)/'`sio.c + +pcem-sio.obj: sio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sio.obj -MD -MP -MF $(DEPDIR)/pcem-sio.Tpo -c -o pcem-sio.obj `if test -f 'sio.c'; then $(CYGPATH_W) 'sio.c'; else $(CYGPATH_W) '$(srcdir)/sio.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sio.Tpo $(DEPDIR)/pcem-sio.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sio.c' object='pcem-sio.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sio.obj `if test -f 'sio.c'; then $(CYGPATH_W) 'sio.c'; else $(CYGPATH_W) '$(srcdir)/sio.c'; fi` + pcem-sis496.o: sis496.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sis496.o -MD -MP -MF $(DEPDIR)/pcem-sis496.Tpo -c -o pcem-sis496.o `test -f 'sis496.c' || echo '$(srcdir)/'`sis496.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sis496.Tpo $(DEPDIR)/pcem-sis496.Po @@ -2064,6 +3730,20 @@ pcem-sis496.obj: sis496.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sis496.obj `if test -f 'sis496.c'; then $(CYGPATH_W) 'sis496.c'; else $(CYGPATH_W) '$(srcdir)/sis496.c'; fi` +pcem-sl82c460.o: sl82c460.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sl82c460.o -MD -MP -MF $(DEPDIR)/pcem-sl82c460.Tpo -c -o pcem-sl82c460.o `test -f 'sl82c460.c' || echo '$(srcdir)/'`sl82c460.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sl82c460.Tpo $(DEPDIR)/pcem-sl82c460.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sl82c460.c' object='pcem-sl82c460.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sl82c460.o `test -f 'sl82c460.c' || echo '$(srcdir)/'`sl82c460.c + +pcem-sl82c460.obj: sl82c460.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sl82c460.obj -MD -MP -MF $(DEPDIR)/pcem-sl82c460.Tpo -c -o pcem-sl82c460.obj `if test -f 'sl82c460.c'; then $(CYGPATH_W) 'sl82c460.c'; else $(CYGPATH_W) '$(srcdir)/sl82c460.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sl82c460.Tpo $(DEPDIR)/pcem-sl82c460.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sl82c460.c' object='pcem-sl82c460.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sl82c460.obj `if test -f 'sl82c460.c'; then $(CYGPATH_W) 'sl82c460.c'; else $(CYGPATH_W) '$(srcdir)/sl82c460.c'; fi` + pcem-sound.o: sound.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound.o -MD -MP -MF $(DEPDIR)/pcem-sound.Tpo -c -o pcem-sound.o `test -f 'sound.c' || echo '$(srcdir)/'`sound.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound.Tpo $(DEPDIR)/pcem-sound.Po @@ -2120,6 +3800,34 @@ pcem-sound_adlibgold.obj: sound_adlibgold.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_adlibgold.obj `if test -f 'sound_adlibgold.c'; then $(CYGPATH_W) 'sound_adlibgold.c'; else $(CYGPATH_W) '$(srcdir)/sound_adlibgold.c'; fi` +pcem-sound_audiopci.o: sound_audiopci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_audiopci.o -MD -MP -MF $(DEPDIR)/pcem-sound_audiopci.Tpo -c -o pcem-sound_audiopci.o `test -f 'sound_audiopci.c' || echo '$(srcdir)/'`sound_audiopci.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_audiopci.Tpo $(DEPDIR)/pcem-sound_audiopci.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sound_audiopci.c' object='pcem-sound_audiopci.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_audiopci.o `test -f 'sound_audiopci.c' || echo '$(srcdir)/'`sound_audiopci.c + +pcem-sound_audiopci.obj: sound_audiopci.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_audiopci.obj -MD -MP -MF $(DEPDIR)/pcem-sound_audiopci.Tpo -c -o pcem-sound_audiopci.obj `if test -f 'sound_audiopci.c'; then $(CYGPATH_W) 'sound_audiopci.c'; else $(CYGPATH_W) '$(srcdir)/sound_audiopci.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_audiopci.Tpo $(DEPDIR)/pcem-sound_audiopci.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sound_audiopci.c' object='pcem-sound_audiopci.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_audiopci.obj `if test -f 'sound_audiopci.c'; then $(CYGPATH_W) 'sound_audiopci.c'; else $(CYGPATH_W) '$(srcdir)/sound_audiopci.c'; fi` + +pcem-sound_azt2316a.o: sound_azt2316a.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_azt2316a.o -MD -MP -MF $(DEPDIR)/pcem-sound_azt2316a.Tpo -c -o pcem-sound_azt2316a.o `test -f 'sound_azt2316a.c' || echo '$(srcdir)/'`sound_azt2316a.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_azt2316a.Tpo $(DEPDIR)/pcem-sound_azt2316a.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sound_azt2316a.c' object='pcem-sound_azt2316a.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_azt2316a.o `test -f 'sound_azt2316a.c' || echo '$(srcdir)/'`sound_azt2316a.c + +pcem-sound_azt2316a.obj: sound_azt2316a.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_azt2316a.obj -MD -MP -MF $(DEPDIR)/pcem-sound_azt2316a.Tpo -c -o pcem-sound_azt2316a.obj `if test -f 'sound_azt2316a.c'; then $(CYGPATH_W) 'sound_azt2316a.c'; else $(CYGPATH_W) '$(srcdir)/sound_azt2316a.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_azt2316a.Tpo $(DEPDIR)/pcem-sound_azt2316a.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sound_azt2316a.c' object='pcem-sound_azt2316a.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sound_azt2316a.obj `if test -f 'sound_azt2316a.c'; then $(CYGPATH_W) 'sound_azt2316a.c'; else $(CYGPATH_W) '$(srcdir)/sound_azt2316a.c'; fi` + pcem-sound_cms.o: sound_cms.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sound_cms.o -MD -MP -MF $(DEPDIR)/pcem-sound_cms.Tpo -c -o pcem-sound_cms.o `test -f 'sound_cms.c' || echo '$(srcdir)/'`sound_cms.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_cms.Tpo $(DEPDIR)/pcem-sound_cms.Po @@ -2344,6 +4052,34 @@ pcem-soundopenal.obj: soundopenal.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-soundopenal.obj `if test -f 'soundopenal.c'; then $(CYGPATH_W) 'soundopenal.c'; else $(CYGPATH_W) '$(srcdir)/soundopenal.c'; fi` +pcem-sst39sf010.o: sst39sf010.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sst39sf010.o -MD -MP -MF $(DEPDIR)/pcem-sst39sf010.Tpo -c -o pcem-sst39sf010.o `test -f 'sst39sf010.c' || echo '$(srcdir)/'`sst39sf010.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sst39sf010.Tpo $(DEPDIR)/pcem-sst39sf010.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sst39sf010.c' object='pcem-sst39sf010.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sst39sf010.o `test -f 'sst39sf010.c' || echo '$(srcdir)/'`sst39sf010.c + +pcem-sst39sf010.obj: sst39sf010.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-sst39sf010.obj -MD -MP -MF $(DEPDIR)/pcem-sst39sf010.Tpo -c -o pcem-sst39sf010.obj `if test -f 'sst39sf010.c'; then $(CYGPATH_W) 'sst39sf010.c'; else $(CYGPATH_W) '$(srcdir)/sst39sf010.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sst39sf010.Tpo $(DEPDIR)/pcem-sst39sf010.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sst39sf010.c' object='pcem-sst39sf010.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-sst39sf010.obj `if test -f 'sst39sf010.c'; then $(CYGPATH_W) 'sst39sf010.c'; else $(CYGPATH_W) '$(srcdir)/sst39sf010.c'; fi` + +pcem-superxt.o: superxt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-superxt.o -MD -MP -MF $(DEPDIR)/pcem-superxt.Tpo -c -o pcem-superxt.o `test -f 'superxt.c' || echo '$(srcdir)/'`superxt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-superxt.Tpo $(DEPDIR)/pcem-superxt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='superxt.c' object='pcem-superxt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-superxt.o `test -f 'superxt.c' || echo '$(srcdir)/'`superxt.c + +pcem-superxt.obj: superxt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-superxt.obj -MD -MP -MF $(DEPDIR)/pcem-superxt.Tpo -c -o pcem-superxt.obj `if test -f 'superxt.c'; then $(CYGPATH_W) 'superxt.c'; else $(CYGPATH_W) '$(srcdir)/superxt.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-superxt.Tpo $(DEPDIR)/pcem-superxt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='superxt.c' object='pcem-superxt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-superxt.obj `if test -f 'superxt.c'; then $(CYGPATH_W) 'superxt.c'; else $(CYGPATH_W) '$(srcdir)/superxt.c'; fi` + pcem-tandy_eeprom.o: tandy_eeprom.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-tandy_eeprom.o -MD -MP -MF $(DEPDIR)/pcem-tandy_eeprom.Tpo -c -o pcem-tandy_eeprom.o `test -f 'tandy_eeprom.c' || echo '$(srcdir)/'`tandy_eeprom.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-tandy_eeprom.Tpo $(DEPDIR)/pcem-tandy_eeprom.Po @@ -2372,19 +4108,33 @@ pcem-tandy_rom.obj: tandy_rom.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-tandy_rom.obj `if test -f 'tandy_rom.c'; then $(CYGPATH_W) 'tandy_rom.c'; else $(CYGPATH_W) '$(srcdir)/tandy_rom.c'; fi` -pcem-thread-pthread.o: thread-pthread.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-thread-pthread.o -MD -MP -MF $(DEPDIR)/pcem-thread-pthread.Tpo -c -o pcem-thread-pthread.o `test -f 'thread-pthread.c' || echo '$(srcdir)/'`thread-pthread.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-thread-pthread.Tpo $(DEPDIR)/pcem-thread-pthread.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thread-pthread.c' object='pcem-thread-pthread.o' libtool=no @AMDEPBACKSLASH@ +pcem-t1000.o: t1000.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-t1000.o -MD -MP -MF $(DEPDIR)/pcem-t1000.Tpo -c -o pcem-t1000.o `test -f 't1000.c' || echo '$(srcdir)/'`t1000.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-t1000.Tpo $(DEPDIR)/pcem-t1000.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='t1000.c' object='pcem-t1000.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-thread-pthread.o `test -f 'thread-pthread.c' || echo '$(srcdir)/'`thread-pthread.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-t1000.o `test -f 't1000.c' || echo '$(srcdir)/'`t1000.c -pcem-thread-pthread.obj: thread-pthread.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-thread-pthread.obj -MD -MP -MF $(DEPDIR)/pcem-thread-pthread.Tpo -c -o pcem-thread-pthread.obj `if test -f 'thread-pthread.c'; then $(CYGPATH_W) 'thread-pthread.c'; else $(CYGPATH_W) '$(srcdir)/thread-pthread.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-thread-pthread.Tpo $(DEPDIR)/pcem-thread-pthread.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thread-pthread.c' object='pcem-thread-pthread.obj' libtool=no @AMDEPBACKSLASH@ +pcem-t1000.obj: t1000.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-t1000.obj -MD -MP -MF $(DEPDIR)/pcem-t1000.Tpo -c -o pcem-t1000.obj `if test -f 't1000.c'; then $(CYGPATH_W) 't1000.c'; else $(CYGPATH_W) '$(srcdir)/t1000.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-t1000.Tpo $(DEPDIR)/pcem-t1000.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='t1000.c' object='pcem-t1000.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-thread-pthread.obj `if test -f 'thread-pthread.c'; then $(CYGPATH_W) 'thread-pthread.c'; else $(CYGPATH_W) '$(srcdir)/thread-pthread.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-t1000.obj `if test -f 't1000.c'; then $(CYGPATH_W) 't1000.c'; else $(CYGPATH_W) '$(srcdir)/t1000.c'; fi` + +pcem-t3100e.o: t3100e.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-t3100e.o -MD -MP -MF $(DEPDIR)/pcem-t3100e.Tpo -c -o pcem-t3100e.o `test -f 't3100e.c' || echo '$(srcdir)/'`t3100e.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-t3100e.Tpo $(DEPDIR)/pcem-t3100e.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='t3100e.c' object='pcem-t3100e.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-t3100e.o `test -f 't3100e.c' || echo '$(srcdir)/'`t3100e.c + +pcem-t3100e.obj: t3100e.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-t3100e.obj -MD -MP -MF $(DEPDIR)/pcem-t3100e.Tpo -c -o pcem-t3100e.obj `if test -f 't3100e.c'; then $(CYGPATH_W) 't3100e.c'; else $(CYGPATH_W) '$(srcdir)/t3100e.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-t3100e.Tpo $(DEPDIR)/pcem-t3100e.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='t3100e.c' object='pcem-t3100e.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-t3100e.obj `if test -f 't3100e.c'; then $(CYGPATH_W) 't3100e.c'; else $(CYGPATH_W) '$(srcdir)/t3100e.c'; fi` pcem-timer.o: timer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-timer.o -MD -MP -MF $(DEPDIR)/pcem-timer.Tpo -c -o pcem-timer.o `test -f 'timer.c' || echo '$(srcdir)/'`timer.c @@ -2540,6 +4290,34 @@ pcem-vid_colorplus.obj: vid_colorplus.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_colorplus.obj `if test -f 'vid_colorplus.c'; then $(CYGPATH_W) 'vid_colorplus.c'; else $(CYGPATH_W) '$(srcdir)/vid_colorplus.c'; fi` +pcem-vid_compaq_cga.o: vid_compaq_cga.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_compaq_cga.o -MD -MP -MF $(DEPDIR)/pcem-vid_compaq_cga.Tpo -c -o pcem-vid_compaq_cga.o `test -f 'vid_compaq_cga.c' || echo '$(srcdir)/'`vid_compaq_cga.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_compaq_cga.Tpo $(DEPDIR)/pcem-vid_compaq_cga.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_compaq_cga.c' object='pcem-vid_compaq_cga.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_compaq_cga.o `test -f 'vid_compaq_cga.c' || echo '$(srcdir)/'`vid_compaq_cga.c + +pcem-vid_compaq_cga.obj: vid_compaq_cga.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_compaq_cga.obj -MD -MP -MF $(DEPDIR)/pcem-vid_compaq_cga.Tpo -c -o pcem-vid_compaq_cga.obj `if test -f 'vid_compaq_cga.c'; then $(CYGPATH_W) 'vid_compaq_cga.c'; else $(CYGPATH_W) '$(srcdir)/vid_compaq_cga.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_compaq_cga.Tpo $(DEPDIR)/pcem-vid_compaq_cga.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_compaq_cga.c' object='pcem-vid_compaq_cga.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_compaq_cga.obj `if test -f 'vid_compaq_cga.c'; then $(CYGPATH_W) 'vid_compaq_cga.c'; else $(CYGPATH_W) '$(srcdir)/vid_compaq_cga.c'; fi` + +pcem-vid_ddc.o: vid_ddc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ddc.o -MD -MP -MF $(DEPDIR)/pcem-vid_ddc.Tpo -c -o pcem-vid_ddc.o `test -f 'vid_ddc.c' || echo '$(srcdir)/'`vid_ddc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_ddc.Tpo $(DEPDIR)/pcem-vid_ddc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_ddc.c' object='pcem-vid_ddc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ddc.o `test -f 'vid_ddc.c' || echo '$(srcdir)/'`vid_ddc.c + +pcem-vid_ddc.obj: vid_ddc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ddc.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ddc.Tpo -c -o pcem-vid_ddc.obj `if test -f 'vid_ddc.c'; then $(CYGPATH_W) 'vid_ddc.c'; else $(CYGPATH_W) '$(srcdir)/vid_ddc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_ddc.Tpo $(DEPDIR)/pcem-vid_ddc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_ddc.c' object='pcem-vid_ddc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ddc.obj `if test -f 'vid_ddc.c'; then $(CYGPATH_W) 'vid_ddc.c'; else $(CYGPATH_W) '$(srcdir)/vid_ddc.c'; fi` + pcem-vid_ega.o: vid_ega.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ega.o -MD -MP -MF $(DEPDIR)/pcem-vid_ega.Tpo -c -o pcem-vid_ega.o `test -f 'vid_ega.c' || echo '$(srcdir)/'`vid_ega.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_ega.Tpo $(DEPDIR)/pcem-vid_ega.Po @@ -2610,6 +4388,20 @@ pcem-vid_hercules.obj: vid_hercules.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_hercules.obj `if test -f 'vid_hercules.c'; then $(CYGPATH_W) 'vid_hercules.c'; else $(CYGPATH_W) '$(srcdir)/vid_hercules.c'; fi` +pcem-vid_ht216.o: vid_ht216.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ht216.o -MD -MP -MF $(DEPDIR)/pcem-vid_ht216.Tpo -c -o pcem-vid_ht216.o `test -f 'vid_ht216.c' || echo '$(srcdir)/'`vid_ht216.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_ht216.Tpo $(DEPDIR)/pcem-vid_ht216.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_ht216.c' object='pcem-vid_ht216.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ht216.o `test -f 'vid_ht216.c' || echo '$(srcdir)/'`vid_ht216.c + +pcem-vid_ht216.obj: vid_ht216.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ht216.obj -MD -MP -MF $(DEPDIR)/pcem-vid_ht216.Tpo -c -o pcem-vid_ht216.obj `if test -f 'vid_ht216.c'; then $(CYGPATH_W) 'vid_ht216.c'; else $(CYGPATH_W) '$(srcdir)/vid_ht216.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_ht216.Tpo $(DEPDIR)/pcem-vid_ht216.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_ht216.c' object='pcem-vid_ht216.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ht216.obj `if test -f 'vid_ht216.c'; then $(CYGPATH_W) 'vid_ht216.c'; else $(CYGPATH_W) '$(srcdir)/vid_ht216.c'; fi` + pcem-vid_icd2061.o: vid_icd2061.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_icd2061.o -MD -MP -MF $(DEPDIR)/pcem-vid_icd2061.Tpo -c -o pcem-vid_icd2061.o `test -f 'vid_icd2061.c' || echo '$(srcdir)/'`vid_icd2061.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_icd2061.Tpo $(DEPDIR)/pcem-vid_icd2061.Po @@ -2638,6 +4430,20 @@ pcem-vid_ics2595.obj: vid_ics2595.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_ics2595.obj `if test -f 'vid_ics2595.c'; then $(CYGPATH_W) 'vid_ics2595.c'; else $(CYGPATH_W) '$(srcdir)/vid_ics2595.c'; fi` +pcem-vid_im1024.o: vid_im1024.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_im1024.o -MD -MP -MF $(DEPDIR)/pcem-vid_im1024.Tpo -c -o pcem-vid_im1024.o `test -f 'vid_im1024.c' || echo '$(srcdir)/'`vid_im1024.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_im1024.Tpo $(DEPDIR)/pcem-vid_im1024.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_im1024.c' object='pcem-vid_im1024.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_im1024.o `test -f 'vid_im1024.c' || echo '$(srcdir)/'`vid_im1024.c + +pcem-vid_im1024.obj: vid_im1024.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_im1024.obj -MD -MP -MF $(DEPDIR)/pcem-vid_im1024.Tpo -c -o pcem-vid_im1024.obj `if test -f 'vid_im1024.c'; then $(CYGPATH_W) 'vid_im1024.c'; else $(CYGPATH_W) '$(srcdir)/vid_im1024.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_im1024.Tpo $(DEPDIR)/pcem-vid_im1024.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_im1024.c' object='pcem-vid_im1024.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_im1024.obj `if test -f 'vid_im1024.c'; then $(CYGPATH_W) 'vid_im1024.c'; else $(CYGPATH_W) '$(srcdir)/vid_im1024.c'; fi` + pcem-vid_incolor.o: vid_incolor.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_incolor.o -MD -MP -MF $(DEPDIR)/pcem-vid_incolor.Tpo -c -o pcem-vid_incolor.o `test -f 'vid_incolor.c' || echo '$(srcdir)/'`vid_incolor.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_incolor.Tpo $(DEPDIR)/pcem-vid_incolor.Po @@ -2666,6 +4472,20 @@ pcem-vid_mda.obj: vid_mda.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_mda.obj `if test -f 'vid_mda.c'; then $(CYGPATH_W) 'vid_mda.c'; else $(CYGPATH_W) '$(srcdir)/vid_mda.c'; fi` +pcem-vid_mga.o: vid_mga.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_mga.o -MD -MP -MF $(DEPDIR)/pcem-vid_mga.Tpo -c -o pcem-vid_mga.o `test -f 'vid_mga.c' || echo '$(srcdir)/'`vid_mga.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_mga.Tpo $(DEPDIR)/pcem-vid_mga.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_mga.c' object='pcem-vid_mga.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_mga.o `test -f 'vid_mga.c' || echo '$(srcdir)/'`vid_mga.c + +pcem-vid_mga.obj: vid_mga.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_mga.obj -MD -MP -MF $(DEPDIR)/pcem-vid_mga.Tpo -c -o pcem-vid_mga.obj `if test -f 'vid_mga.c'; then $(CYGPATH_W) 'vid_mga.c'; else $(CYGPATH_W) '$(srcdir)/vid_mga.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_mga.Tpo $(DEPDIR)/pcem-vid_mga.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_mga.c' object='pcem-vid_mga.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_mga.obj `if test -f 'vid_mga.c'; then $(CYGPATH_W) 'vid_mga.c'; else $(CYGPATH_W) '$(srcdir)/vid_mga.c'; fi` + pcem-vid_olivetti_m24.o: vid_olivetti_m24.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_olivetti_m24.o -MD -MP -MF $(DEPDIR)/pcem-vid_olivetti_m24.Tpo -c -o pcem-vid_olivetti_m24.o `test -f 'vid_olivetti_m24.c' || echo '$(srcdir)/'`vid_olivetti_m24.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_olivetti_m24.Tpo $(DEPDIR)/pcem-vid_olivetti_m24.Po @@ -2680,6 +4500,20 @@ pcem-vid_olivetti_m24.obj: vid_olivetti_m24.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_olivetti_m24.obj `if test -f 'vid_olivetti_m24.c'; then $(CYGPATH_W) 'vid_olivetti_m24.c'; else $(CYGPATH_W) '$(srcdir)/vid_olivetti_m24.c'; fi` +pcem-vid_oti037.o: vid_oti037.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_oti037.o -MD -MP -MF $(DEPDIR)/pcem-vid_oti037.Tpo -c -o pcem-vid_oti037.o `test -f 'vid_oti037.c' || echo '$(srcdir)/'`vid_oti037.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_oti037.Tpo $(DEPDIR)/pcem-vid_oti037.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_oti037.c' object='pcem-vid_oti037.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_oti037.o `test -f 'vid_oti037.c' || echo '$(srcdir)/'`vid_oti037.c + +pcem-vid_oti037.obj: vid_oti037.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_oti037.obj -MD -MP -MF $(DEPDIR)/pcem-vid_oti037.Tpo -c -o pcem-vid_oti037.obj `if test -f 'vid_oti037.c'; then $(CYGPATH_W) 'vid_oti037.c'; else $(CYGPATH_W) '$(srcdir)/vid_oti037.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_oti037.Tpo $(DEPDIR)/pcem-vid_oti037.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_oti037.c' object='pcem-vid_oti037.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_oti037.obj `if test -f 'vid_oti037.c'; then $(CYGPATH_W) 'vid_oti037.c'; else $(CYGPATH_W) '$(srcdir)/vid_oti037.c'; fi` + pcem-vid_oti067.o: vid_oti067.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_oti067.o -MD -MP -MF $(DEPDIR)/pcem-vid_oti067.Tpo -c -o pcem-vid_oti067.o `test -f 'vid_oti067.c' || echo '$(srcdir)/'`vid_oti067.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_oti067.Tpo $(DEPDIR)/pcem-vid_oti067.Po @@ -2764,6 +4598,20 @@ pcem-vid_pcjr.obj: vid_pcjr.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pcjr.obj `if test -f 'vid_pcjr.c'; then $(CYGPATH_W) 'vid_pcjr.c'; else $(CYGPATH_W) '$(srcdir)/vid_pcjr.c'; fi` +pcem-vid_pgc.o: vid_pgc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pgc.o -MD -MP -MF $(DEPDIR)/pcem-vid_pgc.Tpo -c -o pcem-vid_pgc.o `test -f 'vid_pgc.c' || echo '$(srcdir)/'`vid_pgc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_pgc.Tpo $(DEPDIR)/pcem-vid_pgc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_pgc.c' object='pcem-vid_pgc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pgc.o `test -f 'vid_pgc.c' || echo '$(srcdir)/'`vid_pgc.c + +pcem-vid_pgc.obj: vid_pgc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_pgc.obj -MD -MP -MF $(DEPDIR)/pcem-vid_pgc.Tpo -c -o pcem-vid_pgc.obj `if test -f 'vid_pgc.c'; then $(CYGPATH_W) 'vid_pgc.c'; else $(CYGPATH_W) '$(srcdir)/vid_pgc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_pgc.Tpo $(DEPDIR)/pcem-vid_pgc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_pgc.c' object='pcem-vid_pgc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_pgc.obj `if test -f 'vid_pgc.c'; then $(CYGPATH_W) 'vid_pgc.c'; else $(CYGPATH_W) '$(srcdir)/vid_pgc.c'; fi` + pcem-vid_ps1_svga.o: vid_ps1_svga.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_ps1_svga.o -MD -MP -MF $(DEPDIR)/pcem-vid_ps1_svga.Tpo -c -o pcem-vid_ps1_svga.o `test -f 'vid_ps1_svga.c' || echo '$(srcdir)/'`vid_ps1_svga.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_ps1_svga.Tpo $(DEPDIR)/pcem-vid_ps1_svga.Po @@ -2820,6 +4668,20 @@ pcem-vid_sdac_ramdac.obj: vid_sdac_ramdac.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_sdac_ramdac.obj `if test -f 'vid_sdac_ramdac.c'; then $(CYGPATH_W) 'vid_sdac_ramdac.c'; else $(CYGPATH_W) '$(srcdir)/vid_sdac_ramdac.c'; fi` +pcem-vid_sigma.o: vid_sigma.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_sigma.o -MD -MP -MF $(DEPDIR)/pcem-vid_sigma.Tpo -c -o pcem-vid_sigma.o `test -f 'vid_sigma.c' || echo '$(srcdir)/'`vid_sigma.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_sigma.Tpo $(DEPDIR)/pcem-vid_sigma.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_sigma.c' object='pcem-vid_sigma.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_sigma.o `test -f 'vid_sigma.c' || echo '$(srcdir)/'`vid_sigma.c + +pcem-vid_sigma.obj: vid_sigma.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_sigma.obj -MD -MP -MF $(DEPDIR)/pcem-vid_sigma.Tpo -c -o pcem-vid_sigma.obj `if test -f 'vid_sigma.c'; then $(CYGPATH_W) 'vid_sigma.c'; else $(CYGPATH_W) '$(srcdir)/vid_sigma.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_sigma.Tpo $(DEPDIR)/pcem-vid_sigma.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_sigma.c' object='pcem-vid_sigma.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_sigma.obj `if test -f 'vid_sigma.c'; then $(CYGPATH_W) 'vid_sigma.c'; else $(CYGPATH_W) '$(srcdir)/vid_sigma.c'; fi` + pcem-vid_stg_ramdac.o: vid_stg_ramdac.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_stg_ramdac.o -MD -MP -MF $(DEPDIR)/pcem-vid_stg_ramdac.Tpo -c -o pcem-vid_stg_ramdac.o `test -f 'vid_stg_ramdac.c' || echo '$(srcdir)/'`vid_stg_ramdac.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_stg_ramdac.Tpo $(DEPDIR)/pcem-vid_stg_ramdac.Po @@ -2862,6 +4724,34 @@ pcem-vid_svga_render.obj: vid_svga_render.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_svga_render.obj `if test -f 'vid_svga_render.c'; then $(CYGPATH_W) 'vid_svga_render.c'; else $(CYGPATH_W) '$(srcdir)/vid_svga_render.c'; fi` +pcem-vid_t1000.o: vid_t1000.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_t1000.o -MD -MP -MF $(DEPDIR)/pcem-vid_t1000.Tpo -c -o pcem-vid_t1000.o `test -f 'vid_t1000.c' || echo '$(srcdir)/'`vid_t1000.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_t1000.Tpo $(DEPDIR)/pcem-vid_t1000.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_t1000.c' object='pcem-vid_t1000.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_t1000.o `test -f 'vid_t1000.c' || echo '$(srcdir)/'`vid_t1000.c + +pcem-vid_t1000.obj: vid_t1000.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_t1000.obj -MD -MP -MF $(DEPDIR)/pcem-vid_t1000.Tpo -c -o pcem-vid_t1000.obj `if test -f 'vid_t1000.c'; then $(CYGPATH_W) 'vid_t1000.c'; else $(CYGPATH_W) '$(srcdir)/vid_t1000.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_t1000.Tpo $(DEPDIR)/pcem-vid_t1000.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_t1000.c' object='pcem-vid_t1000.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_t1000.obj `if test -f 'vid_t1000.c'; then $(CYGPATH_W) 'vid_t1000.c'; else $(CYGPATH_W) '$(srcdir)/vid_t1000.c'; fi` + +pcem-vid_t3100e.o: vid_t3100e.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_t3100e.o -MD -MP -MF $(DEPDIR)/pcem-vid_t3100e.Tpo -c -o pcem-vid_t3100e.o `test -f 'vid_t3100e.c' || echo '$(srcdir)/'`vid_t3100e.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_t3100e.Tpo $(DEPDIR)/pcem-vid_t3100e.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_t3100e.c' object='pcem-vid_t3100e.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_t3100e.o `test -f 'vid_t3100e.c' || echo '$(srcdir)/'`vid_t3100e.c + +pcem-vid_t3100e.obj: vid_t3100e.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_t3100e.obj -MD -MP -MF $(DEPDIR)/pcem-vid_t3100e.Tpo -c -o pcem-vid_t3100e.obj `if test -f 'vid_t3100e.c'; then $(CYGPATH_W) 'vid_t3100e.c'; else $(CYGPATH_W) '$(srcdir)/vid_t3100e.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_t3100e.Tpo $(DEPDIR)/pcem-vid_t3100e.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_t3100e.c' object='pcem-vid_t3100e.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_t3100e.obj `if test -f 'vid_t3100e.c'; then $(CYGPATH_W) 'vid_t3100e.c'; else $(CYGPATH_W) '$(srcdir)/vid_t3100e.c'; fi` + pcem-vid_tandy.o: vid_tandy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_tandy.o -MD -MP -MF $(DEPDIR)/pcem-vid_tandy.Tpo -c -o pcem-vid_tandy.o `test -f 'vid_tandy.c' || echo '$(srcdir)/'`vid_tandy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_tandy.Tpo $(DEPDIR)/pcem-vid_tandy.Po @@ -2974,6 +4864,146 @@ pcem-vid_voodoo.obj: vid_voodoo.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo.obj `if test -f 'vid_voodoo.c'; then $(CYGPATH_W) 'vid_voodoo.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo.c'; fi` +pcem-vid_voodoo_banshee.o: vid_voodoo_banshee.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_banshee.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_banshee.Tpo -c -o pcem-vid_voodoo_banshee.o `test -f 'vid_voodoo_banshee.c' || echo '$(srcdir)/'`vid_voodoo_banshee.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_banshee.Tpo $(DEPDIR)/pcem-vid_voodoo_banshee.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_banshee.c' object='pcem-vid_voodoo_banshee.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_banshee.o `test -f 'vid_voodoo_banshee.c' || echo '$(srcdir)/'`vid_voodoo_banshee.c + +pcem-vid_voodoo_banshee.obj: vid_voodoo_banshee.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_banshee.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_banshee.Tpo -c -o pcem-vid_voodoo_banshee.obj `if test -f 'vid_voodoo_banshee.c'; then $(CYGPATH_W) 'vid_voodoo_banshee.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_banshee.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_banshee.Tpo $(DEPDIR)/pcem-vid_voodoo_banshee.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_banshee.c' object='pcem-vid_voodoo_banshee.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_banshee.obj `if test -f 'vid_voodoo_banshee.c'; then $(CYGPATH_W) 'vid_voodoo_banshee.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_banshee.c'; fi` + +pcem-vid_voodoo_banshee_blitter.o: vid_voodoo_banshee_blitter.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_banshee_blitter.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Tpo -c -o pcem-vid_voodoo_banshee_blitter.o `test -f 'vid_voodoo_banshee_blitter.c' || echo '$(srcdir)/'`vid_voodoo_banshee_blitter.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Tpo $(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_banshee_blitter.c' object='pcem-vid_voodoo_banshee_blitter.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_banshee_blitter.o `test -f 'vid_voodoo_banshee_blitter.c' || echo '$(srcdir)/'`vid_voodoo_banshee_blitter.c + +pcem-vid_voodoo_banshee_blitter.obj: vid_voodoo_banshee_blitter.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_banshee_blitter.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Tpo -c -o pcem-vid_voodoo_banshee_blitter.obj `if test -f 'vid_voodoo_banshee_blitter.c'; then $(CYGPATH_W) 'vid_voodoo_banshee_blitter.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_banshee_blitter.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Tpo $(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_banshee_blitter.c' object='pcem-vid_voodoo_banshee_blitter.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_banshee_blitter.obj `if test -f 'vid_voodoo_banshee_blitter.c'; then $(CYGPATH_W) 'vid_voodoo_banshee_blitter.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_banshee_blitter.c'; fi` + +pcem-vid_voodoo_blitter.o: vid_voodoo_blitter.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_blitter.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_blitter.Tpo -c -o pcem-vid_voodoo_blitter.o `test -f 'vid_voodoo_blitter.c' || echo '$(srcdir)/'`vid_voodoo_blitter.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_blitter.Tpo $(DEPDIR)/pcem-vid_voodoo_blitter.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_blitter.c' object='pcem-vid_voodoo_blitter.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_blitter.o `test -f 'vid_voodoo_blitter.c' || echo '$(srcdir)/'`vid_voodoo_blitter.c + +pcem-vid_voodoo_blitter.obj: vid_voodoo_blitter.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_blitter.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_blitter.Tpo -c -o pcem-vid_voodoo_blitter.obj `if test -f 'vid_voodoo_blitter.c'; then $(CYGPATH_W) 'vid_voodoo_blitter.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_blitter.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_blitter.Tpo $(DEPDIR)/pcem-vid_voodoo_blitter.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_blitter.c' object='pcem-vid_voodoo_blitter.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_blitter.obj `if test -f 'vid_voodoo_blitter.c'; then $(CYGPATH_W) 'vid_voodoo_blitter.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_blitter.c'; fi` + +pcem-vid_voodoo_display.o: vid_voodoo_display.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_display.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_display.Tpo -c -o pcem-vid_voodoo_display.o `test -f 'vid_voodoo_display.c' || echo '$(srcdir)/'`vid_voodoo_display.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_display.Tpo $(DEPDIR)/pcem-vid_voodoo_display.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_display.c' object='pcem-vid_voodoo_display.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_display.o `test -f 'vid_voodoo_display.c' || echo '$(srcdir)/'`vid_voodoo_display.c + +pcem-vid_voodoo_display.obj: vid_voodoo_display.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_display.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_display.Tpo -c -o pcem-vid_voodoo_display.obj `if test -f 'vid_voodoo_display.c'; then $(CYGPATH_W) 'vid_voodoo_display.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_display.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_display.Tpo $(DEPDIR)/pcem-vid_voodoo_display.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_display.c' object='pcem-vid_voodoo_display.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_display.obj `if test -f 'vid_voodoo_display.c'; then $(CYGPATH_W) 'vid_voodoo_display.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_display.c'; fi` + +pcem-vid_voodoo_fb.o: vid_voodoo_fb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_fb.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_fb.Tpo -c -o pcem-vid_voodoo_fb.o `test -f 'vid_voodoo_fb.c' || echo '$(srcdir)/'`vid_voodoo_fb.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_fb.Tpo $(DEPDIR)/pcem-vid_voodoo_fb.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_fb.c' object='pcem-vid_voodoo_fb.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_fb.o `test -f 'vid_voodoo_fb.c' || echo '$(srcdir)/'`vid_voodoo_fb.c + +pcem-vid_voodoo_fb.obj: vid_voodoo_fb.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_fb.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_fb.Tpo -c -o pcem-vid_voodoo_fb.obj `if test -f 'vid_voodoo_fb.c'; then $(CYGPATH_W) 'vid_voodoo_fb.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_fb.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_fb.Tpo $(DEPDIR)/pcem-vid_voodoo_fb.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_fb.c' object='pcem-vid_voodoo_fb.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_fb.obj `if test -f 'vid_voodoo_fb.c'; then $(CYGPATH_W) 'vid_voodoo_fb.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_fb.c'; fi` + +pcem-vid_voodoo_fifo.o: vid_voodoo_fifo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_fifo.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_fifo.Tpo -c -o pcem-vid_voodoo_fifo.o `test -f 'vid_voodoo_fifo.c' || echo '$(srcdir)/'`vid_voodoo_fifo.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_fifo.Tpo $(DEPDIR)/pcem-vid_voodoo_fifo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_fifo.c' object='pcem-vid_voodoo_fifo.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_fifo.o `test -f 'vid_voodoo_fifo.c' || echo '$(srcdir)/'`vid_voodoo_fifo.c + +pcem-vid_voodoo_fifo.obj: vid_voodoo_fifo.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_fifo.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_fifo.Tpo -c -o pcem-vid_voodoo_fifo.obj `if test -f 'vid_voodoo_fifo.c'; then $(CYGPATH_W) 'vid_voodoo_fifo.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_fifo.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_fifo.Tpo $(DEPDIR)/pcem-vid_voodoo_fifo.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_fifo.c' object='pcem-vid_voodoo_fifo.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_fifo.obj `if test -f 'vid_voodoo_fifo.c'; then $(CYGPATH_W) 'vid_voodoo_fifo.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_fifo.c'; fi` + +pcem-vid_voodoo_reg.o: vid_voodoo_reg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_reg.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_reg.Tpo -c -o pcem-vid_voodoo_reg.o `test -f 'vid_voodoo_reg.c' || echo '$(srcdir)/'`vid_voodoo_reg.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_reg.Tpo $(DEPDIR)/pcem-vid_voodoo_reg.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_reg.c' object='pcem-vid_voodoo_reg.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_reg.o `test -f 'vid_voodoo_reg.c' || echo '$(srcdir)/'`vid_voodoo_reg.c + +pcem-vid_voodoo_reg.obj: vid_voodoo_reg.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_reg.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_reg.Tpo -c -o pcem-vid_voodoo_reg.obj `if test -f 'vid_voodoo_reg.c'; then $(CYGPATH_W) 'vid_voodoo_reg.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_reg.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_reg.Tpo $(DEPDIR)/pcem-vid_voodoo_reg.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_reg.c' object='pcem-vid_voodoo_reg.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_reg.obj `if test -f 'vid_voodoo_reg.c'; then $(CYGPATH_W) 'vid_voodoo_reg.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_reg.c'; fi` + +pcem-vid_voodoo_render.o: vid_voodoo_render.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_render.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_render.Tpo -c -o pcem-vid_voodoo_render.o `test -f 'vid_voodoo_render.c' || echo '$(srcdir)/'`vid_voodoo_render.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_render.Tpo $(DEPDIR)/pcem-vid_voodoo_render.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_render.c' object='pcem-vid_voodoo_render.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_render.o `test -f 'vid_voodoo_render.c' || echo '$(srcdir)/'`vid_voodoo_render.c + +pcem-vid_voodoo_render.obj: vid_voodoo_render.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_render.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_render.Tpo -c -o pcem-vid_voodoo_render.obj `if test -f 'vid_voodoo_render.c'; then $(CYGPATH_W) 'vid_voodoo_render.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_render.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_render.Tpo $(DEPDIR)/pcem-vid_voodoo_render.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_render.c' object='pcem-vid_voodoo_render.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_render.obj `if test -f 'vid_voodoo_render.c'; then $(CYGPATH_W) 'vid_voodoo_render.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_render.c'; fi` + +pcem-vid_voodoo_setup.o: vid_voodoo_setup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_setup.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_setup.Tpo -c -o pcem-vid_voodoo_setup.o `test -f 'vid_voodoo_setup.c' || echo '$(srcdir)/'`vid_voodoo_setup.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_setup.Tpo $(DEPDIR)/pcem-vid_voodoo_setup.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_setup.c' object='pcem-vid_voodoo_setup.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_setup.o `test -f 'vid_voodoo_setup.c' || echo '$(srcdir)/'`vid_voodoo_setup.c + +pcem-vid_voodoo_setup.obj: vid_voodoo_setup.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_setup.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_setup.Tpo -c -o pcem-vid_voodoo_setup.obj `if test -f 'vid_voodoo_setup.c'; then $(CYGPATH_W) 'vid_voodoo_setup.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_setup.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_setup.Tpo $(DEPDIR)/pcem-vid_voodoo_setup.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_setup.c' object='pcem-vid_voodoo_setup.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_setup.obj `if test -f 'vid_voodoo_setup.c'; then $(CYGPATH_W) 'vid_voodoo_setup.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_setup.c'; fi` + +pcem-vid_voodoo_texture.o: vid_voodoo_texture.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_texture.o -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_texture.Tpo -c -o pcem-vid_voodoo_texture.o `test -f 'vid_voodoo_texture.c' || echo '$(srcdir)/'`vid_voodoo_texture.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_texture.Tpo $(DEPDIR)/pcem-vid_voodoo_texture.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_texture.c' object='pcem-vid_voodoo_texture.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_texture.o `test -f 'vid_voodoo_texture.c' || echo '$(srcdir)/'`vid_voodoo_texture.c + +pcem-vid_voodoo_texture.obj: vid_voodoo_texture.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_voodoo_texture.obj -MD -MP -MF $(DEPDIR)/pcem-vid_voodoo_texture.Tpo -c -o pcem-vid_voodoo_texture.obj `if test -f 'vid_voodoo_texture.c'; then $(CYGPATH_W) 'vid_voodoo_texture.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_texture.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_voodoo_texture.Tpo $(DEPDIR)/pcem-vid_voodoo_texture.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vid_voodoo_texture.c' object='pcem-vid_voodoo_texture.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_voodoo_texture.obj `if test -f 'vid_voodoo_texture.c'; then $(CYGPATH_W) 'vid_voodoo_texture.c'; else $(CYGPATH_W) '$(srcdir)/vid_voodoo_texture.c'; fi` + pcem-video.o: video.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-video.o -MD -MP -MF $(DEPDIR)/pcem-video.Tpo -c -o pcem-video.o `test -f 'video.c' || echo '$(srcdir)/'`video.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-video.Tpo $(DEPDIR)/pcem-video.Po @@ -3016,6 +5046,62 @@ pcem-vid_wy700.obj: vid_wy700.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_wy700.obj `if test -f 'vid_wy700.c'; then $(CYGPATH_W) 'vid_wy700.c'; else $(CYGPATH_W) '$(srcdir)/vid_wy700.c'; fi` +pcem-vt82c586b.o: vt82c586b.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vt82c586b.o -MD -MP -MF $(DEPDIR)/pcem-vt82c586b.Tpo -c -o pcem-vt82c586b.o `test -f 'vt82c586b.c' || echo '$(srcdir)/'`vt82c586b.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vt82c586b.Tpo $(DEPDIR)/pcem-vt82c586b.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vt82c586b.c' object='pcem-vt82c586b.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vt82c586b.o `test -f 'vt82c586b.c' || echo '$(srcdir)/'`vt82c586b.c + +pcem-vt82c586b.obj: vt82c586b.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vt82c586b.obj -MD -MP -MF $(DEPDIR)/pcem-vt82c586b.Tpo -c -o pcem-vt82c586b.obj `if test -f 'vt82c586b.c'; then $(CYGPATH_W) 'vt82c586b.c'; else $(CYGPATH_W) '$(srcdir)/vt82c586b.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vt82c586b.Tpo $(DEPDIR)/pcem-vt82c586b.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vt82c586b.c' object='pcem-vt82c586b.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vt82c586b.obj `if test -f 'vt82c586b.c'; then $(CYGPATH_W) 'vt82c586b.c'; else $(CYGPATH_W) '$(srcdir)/vt82c586b.c'; fi` + +pcem-vl82c480.o: vl82c480.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vl82c480.o -MD -MP -MF $(DEPDIR)/pcem-vl82c480.Tpo -c -o pcem-vl82c480.o `test -f 'vl82c480.c' || echo '$(srcdir)/'`vl82c480.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vl82c480.Tpo $(DEPDIR)/pcem-vl82c480.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vl82c480.c' object='pcem-vl82c480.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vl82c480.o `test -f 'vl82c480.c' || echo '$(srcdir)/'`vl82c480.c + +pcem-vl82c480.obj: vl82c480.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vl82c480.obj -MD -MP -MF $(DEPDIR)/pcem-vl82c480.Tpo -c -o pcem-vl82c480.obj `if test -f 'vl82c480.c'; then $(CYGPATH_W) 'vl82c480.c'; else $(CYGPATH_W) '$(srcdir)/vl82c480.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vl82c480.Tpo $(DEPDIR)/pcem-vl82c480.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vl82c480.c' object='pcem-vl82c480.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vl82c480.obj `if test -f 'vl82c480.c'; then $(CYGPATH_W) 'vl82c480.c'; else $(CYGPATH_W) '$(srcdir)/vl82c480.c'; fi` + +pcem-w83877tf.o: w83877tf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-w83877tf.o -MD -MP -MF $(DEPDIR)/pcem-w83877tf.Tpo -c -o pcem-w83877tf.o `test -f 'w83877tf.c' || echo '$(srcdir)/'`w83877tf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-w83877tf.Tpo $(DEPDIR)/pcem-w83877tf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w83877tf.c' object='pcem-w83877tf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-w83877tf.o `test -f 'w83877tf.c' || echo '$(srcdir)/'`w83877tf.c + +pcem-w83877tf.obj: w83877tf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-w83877tf.obj -MD -MP -MF $(DEPDIR)/pcem-w83877tf.Tpo -c -o pcem-w83877tf.obj `if test -f 'w83877tf.c'; then $(CYGPATH_W) 'w83877tf.c'; else $(CYGPATH_W) '$(srcdir)/w83877tf.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-w83877tf.Tpo $(DEPDIR)/pcem-w83877tf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w83877tf.c' object='pcem-w83877tf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-w83877tf.obj `if test -f 'w83877tf.c'; then $(CYGPATH_W) 'w83877tf.c'; else $(CYGPATH_W) '$(srcdir)/w83877tf.c'; fi` + +pcem-w83977tf.o: w83977tf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-w83977tf.o -MD -MP -MF $(DEPDIR)/pcem-w83977tf.Tpo -c -o pcem-w83977tf.o `test -f 'w83977tf.c' || echo '$(srcdir)/'`w83977tf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-w83977tf.Tpo $(DEPDIR)/pcem-w83977tf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w83977tf.c' object='pcem-w83977tf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-w83977tf.o `test -f 'w83977tf.c' || echo '$(srcdir)/'`w83977tf.c + +pcem-w83977tf.obj: w83977tf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-w83977tf.obj -MD -MP -MF $(DEPDIR)/pcem-w83977tf.Tpo -c -o pcem-w83977tf.obj `if test -f 'w83977tf.c'; then $(CYGPATH_W) 'w83977tf.c'; else $(CYGPATH_W) '$(srcdir)/w83977tf.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-w83977tf.Tpo $(DEPDIR)/pcem-w83977tf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='w83977tf.c' object='pcem-w83977tf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-w83977tf.obj `if test -f 'w83977tf.c'; then $(CYGPATH_W) 'w83977tf.c'; else $(CYGPATH_W) '$(srcdir)/w83977tf.c'; fi` + pcem-x86seg.o: x86seg.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-x86seg.o -MD -MP -MF $(DEPDIR)/pcem-x86seg.Tpo -c -o pcem-x86seg.o `test -f 'x86seg.c' || echo '$(srcdir)/'`x86seg.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-x86seg.Tpo $(DEPDIR)/pcem-x86seg.Po @@ -3044,6 +5130,34 @@ pcem-x87.obj: x87.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-x87.obj `if test -f 'x87.c'; then $(CYGPATH_W) 'x87.c'; else $(CYGPATH_W) '$(srcdir)/x87.c'; fi` +pcem-x87_timings.o: x87_timings.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-x87_timings.o -MD -MP -MF $(DEPDIR)/pcem-x87_timings.Tpo -c -o pcem-x87_timings.o `test -f 'x87_timings.c' || echo '$(srcdir)/'`x87_timings.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-x87_timings.Tpo $(DEPDIR)/pcem-x87_timings.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='x87_timings.c' object='pcem-x87_timings.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-x87_timings.o `test -f 'x87_timings.c' || echo '$(srcdir)/'`x87_timings.c + +pcem-x87_timings.obj: x87_timings.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-x87_timings.obj -MD -MP -MF $(DEPDIR)/pcem-x87_timings.Tpo -c -o pcem-x87_timings.obj `if test -f 'x87_timings.c'; then $(CYGPATH_W) 'x87_timings.c'; else $(CYGPATH_W) '$(srcdir)/x87_timings.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-x87_timings.Tpo $(DEPDIR)/pcem-x87_timings.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='x87_timings.c' object='pcem-x87_timings.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-x87_timings.obj `if test -f 'x87_timings.c'; then $(CYGPATH_W) 'x87_timings.c'; else $(CYGPATH_W) '$(srcdir)/x87_timings.c'; fi` + +pcem-xi8088.o: xi8088.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-xi8088.o -MD -MP -MF $(DEPDIR)/pcem-xi8088.Tpo -c -o pcem-xi8088.o `test -f 'xi8088.c' || echo '$(srcdir)/'`xi8088.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-xi8088.Tpo $(DEPDIR)/pcem-xi8088.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xi8088.c' object='pcem-xi8088.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-xi8088.o `test -f 'xi8088.c' || echo '$(srcdir)/'`xi8088.c + +pcem-xi8088.obj: xi8088.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-xi8088.obj -MD -MP -MF $(DEPDIR)/pcem-xi8088.Tpo -c -o pcem-xi8088.obj `if test -f 'xi8088.c'; then $(CYGPATH_W) 'xi8088.c'; else $(CYGPATH_W) '$(srcdir)/xi8088.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-xi8088.Tpo $(DEPDIR)/pcem-xi8088.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xi8088.c' object='pcem-xi8088.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-xi8088.obj `if test -f 'xi8088.c'; then $(CYGPATH_W) 'xi8088.c'; else $(CYGPATH_W) '$(srcdir)/xi8088.c'; fi` + pcem-xtide.o: xtide.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-xtide.o -MD -MP -MF $(DEPDIR)/pcem-xtide.Tpo -c -o pcem-xtide.o `test -f 'xtide.c' || echo '$(srcdir)/'`xtide.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-xtide.Tpo $(DEPDIR)/pcem-xtide.Po @@ -3058,324 +5172,1462 @@ pcem-xtide.obj: xtide.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-xtide.obj `if test -f 'xtide.c'; then $(CYGPATH_W) 'xtide.c'; else $(CYGPATH_W) '$(srcdir)/xtide.c'; fi` -pcem-vid_cga_comp.o: dosbox/vid_cga_comp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_cga_comp.o -MD -MP -MF $(DEPDIR)/pcem-vid_cga_comp.Tpo -c -o pcem-vid_cga_comp.o `test -f 'dosbox/vid_cga_comp.c' || echo '$(srcdir)/'`dosbox/vid_cga_comp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_cga_comp.Tpo $(DEPDIR)/pcem-vid_cga_comp.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dosbox/vid_cga_comp.c' object='pcem-vid_cga_comp.o' libtool=no @AMDEPBACKSLASH@ +dosbox/pcem-vid_cga_comp.o: dosbox/vid_cga_comp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT dosbox/pcem-vid_cga_comp.o -MD -MP -MF dosbox/$(DEPDIR)/pcem-vid_cga_comp.Tpo -c -o dosbox/pcem-vid_cga_comp.o `test -f 'dosbox/vid_cga_comp.c' || echo '$(srcdir)/'`dosbox/vid_cga_comp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dosbox/$(DEPDIR)/pcem-vid_cga_comp.Tpo dosbox/$(DEPDIR)/pcem-vid_cga_comp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dosbox/vid_cga_comp.c' object='dosbox/pcem-vid_cga_comp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_cga_comp.o `test -f 'dosbox/vid_cga_comp.c' || echo '$(srcdir)/'`dosbox/vid_cga_comp.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o dosbox/pcem-vid_cga_comp.o `test -f 'dosbox/vid_cga_comp.c' || echo '$(srcdir)/'`dosbox/vid_cga_comp.c -pcem-vid_cga_comp.obj: dosbox/vid_cga_comp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-vid_cga_comp.obj -MD -MP -MF $(DEPDIR)/pcem-vid_cga_comp.Tpo -c -o pcem-vid_cga_comp.obj `if test -f 'dosbox/vid_cga_comp.c'; then $(CYGPATH_W) 'dosbox/vid_cga_comp.c'; else $(CYGPATH_W) '$(srcdir)/dosbox/vid_cga_comp.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-vid_cga_comp.Tpo $(DEPDIR)/pcem-vid_cga_comp.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dosbox/vid_cga_comp.c' object='pcem-vid_cga_comp.obj' libtool=no @AMDEPBACKSLASH@ +dosbox/pcem-vid_cga_comp.obj: dosbox/vid_cga_comp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT dosbox/pcem-vid_cga_comp.obj -MD -MP -MF dosbox/$(DEPDIR)/pcem-vid_cga_comp.Tpo -c -o dosbox/pcem-vid_cga_comp.obj `if test -f 'dosbox/vid_cga_comp.c'; then $(CYGPATH_W) 'dosbox/vid_cga_comp.c'; else $(CYGPATH_W) '$(srcdir)/dosbox/vid_cga_comp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) dosbox/$(DEPDIR)/pcem-vid_cga_comp.Tpo dosbox/$(DEPDIR)/pcem-vid_cga_comp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dosbox/vid_cga_comp.c' object='dosbox/pcem-vid_cga_comp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-vid_cga_comp.obj `if test -f 'dosbox/vid_cga_comp.c'; then $(CYGPATH_W) 'dosbox/vid_cga_comp.c'; else $(CYGPATH_W) '$(srcdir)/dosbox/vid_cga_comp.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o dosbox/pcem-vid_cga_comp.obj `if test -f 'dosbox/vid_cga_comp.c'; then $(CYGPATH_W) 'dosbox/vid_cga_comp.c'; else $(CYGPATH_W) '$(srcdir)/dosbox/vid_cga_comp.c'; fi` -pcem-codegen_x86.o: codegen_x86.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_x86.o -MD -MP -MF $(DEPDIR)/pcem-codegen_x86.Tpo -c -o pcem-codegen_x86.o `test -f 'codegen_x86.c' || echo '$(srcdir)/'`codegen_x86.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_x86.Tpo $(DEPDIR)/pcem-codegen_x86.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_x86.c' object='pcem-codegen_x86.o' libtool=no @AMDEPBACKSLASH@ +minivhd/pcem-cwalk.o: minivhd/cwalk.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-cwalk.o -MD -MP -MF minivhd/$(DEPDIR)/pcem-cwalk.Tpo -c -o minivhd/pcem-cwalk.o `test -f 'minivhd/cwalk.c' || echo '$(srcdir)/'`minivhd/cwalk.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-cwalk.Tpo minivhd/$(DEPDIR)/pcem-cwalk.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/cwalk.c' object='minivhd/pcem-cwalk.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_x86.o `test -f 'codegen_x86.c' || echo '$(srcdir)/'`codegen_x86.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-cwalk.o `test -f 'minivhd/cwalk.c' || echo '$(srcdir)/'`minivhd/cwalk.c -pcem-codegen_x86.obj: codegen_x86.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_x86.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_x86.Tpo -c -o pcem-codegen_x86.obj `if test -f 'codegen_x86.c'; then $(CYGPATH_W) 'codegen_x86.c'; else $(CYGPATH_W) '$(srcdir)/codegen_x86.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_x86.Tpo $(DEPDIR)/pcem-codegen_x86.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_x86.c' object='pcem-codegen_x86.obj' libtool=no @AMDEPBACKSLASH@ +minivhd/pcem-cwalk.obj: minivhd/cwalk.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-cwalk.obj -MD -MP -MF minivhd/$(DEPDIR)/pcem-cwalk.Tpo -c -o minivhd/pcem-cwalk.obj `if test -f 'minivhd/cwalk.c'; then $(CYGPATH_W) 'minivhd/cwalk.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/cwalk.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-cwalk.Tpo minivhd/$(DEPDIR)/pcem-cwalk.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/cwalk.c' object='minivhd/pcem-cwalk.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_x86.obj `if test -f 'codegen_x86.c'; then $(CYGPATH_W) 'codegen_x86.c'; else $(CYGPATH_W) '$(srcdir)/codegen_x86.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-cwalk.obj `if test -f 'minivhd/cwalk.c'; then $(CYGPATH_W) 'minivhd/cwalk.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/cwalk.c'; fi` -pcem-codegen_x86-64.o: codegen_x86-64.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_x86-64.o -MD -MP -MF $(DEPDIR)/pcem-codegen_x86-64.Tpo -c -o pcem-codegen_x86-64.o `test -f 'codegen_x86-64.c' || echo '$(srcdir)/'`codegen_x86-64.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_x86-64.Tpo $(DEPDIR)/pcem-codegen_x86-64.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_x86-64.c' object='pcem-codegen_x86-64.o' libtool=no @AMDEPBACKSLASH@ +minivhd/pcem-libxml2_encoding.o: minivhd/libxml2_encoding.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-libxml2_encoding.o -MD -MP -MF minivhd/$(DEPDIR)/pcem-libxml2_encoding.Tpo -c -o minivhd/pcem-libxml2_encoding.o `test -f 'minivhd/libxml2_encoding.c' || echo '$(srcdir)/'`minivhd/libxml2_encoding.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-libxml2_encoding.Tpo minivhd/$(DEPDIR)/pcem-libxml2_encoding.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/libxml2_encoding.c' object='minivhd/pcem-libxml2_encoding.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_x86-64.o `test -f 'codegen_x86-64.c' || echo '$(srcdir)/'`codegen_x86-64.c +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-libxml2_encoding.o `test -f 'minivhd/libxml2_encoding.c' || echo '$(srcdir)/'`minivhd/libxml2_encoding.c -pcem-codegen_x86-64.obj: codegen_x86-64.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_x86-64.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_x86-64.Tpo -c -o pcem-codegen_x86-64.obj `if test -f 'codegen_x86-64.c'; then $(CYGPATH_W) 'codegen_x86-64.c'; else $(CYGPATH_W) '$(srcdir)/codegen_x86-64.c'; fi` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_x86-64.Tpo $(DEPDIR)/pcem-codegen_x86-64.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_x86-64.c' object='pcem-codegen_x86-64.obj' libtool=no @AMDEPBACKSLASH@ +minivhd/pcem-libxml2_encoding.obj: minivhd/libxml2_encoding.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-libxml2_encoding.obj -MD -MP -MF minivhd/$(DEPDIR)/pcem-libxml2_encoding.Tpo -c -o minivhd/pcem-libxml2_encoding.obj `if test -f 'minivhd/libxml2_encoding.c'; then $(CYGPATH_W) 'minivhd/libxml2_encoding.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/libxml2_encoding.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-libxml2_encoding.Tpo minivhd/$(DEPDIR)/pcem-libxml2_encoding.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/libxml2_encoding.c' object='minivhd/pcem-libxml2_encoding.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_x86-64.obj `if test -f 'codegen_x86-64.c'; then $(CYGPATH_W) 'codegen_x86-64.c'; else $(CYGPATH_W) '$(srcdir)/codegen_x86-64.c'; fi` +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-libxml2_encoding.obj `if test -f 'minivhd/libxml2_encoding.c'; then $(CYGPATH_W) 'minivhd/libxml2_encoding.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/libxml2_encoding.c'; fi` + +minivhd/pcem-minivhd_convert.o: minivhd/minivhd_convert.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_convert.o -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_convert.Tpo -c -o minivhd/pcem-minivhd_convert.o `test -f 'minivhd/minivhd_convert.c' || echo '$(srcdir)/'`minivhd/minivhd_convert.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_convert.Tpo minivhd/$(DEPDIR)/pcem-minivhd_convert.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_convert.c' object='minivhd/pcem-minivhd_convert.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_convert.o `test -f 'minivhd/minivhd_convert.c' || echo '$(srcdir)/'`minivhd/minivhd_convert.c + +minivhd/pcem-minivhd_convert.obj: minivhd/minivhd_convert.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_convert.obj -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_convert.Tpo -c -o minivhd/pcem-minivhd_convert.obj `if test -f 'minivhd/minivhd_convert.c'; then $(CYGPATH_W) 'minivhd/minivhd_convert.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_convert.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_convert.Tpo minivhd/$(DEPDIR)/pcem-minivhd_convert.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_convert.c' object='minivhd/pcem-minivhd_convert.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_convert.obj `if test -f 'minivhd/minivhd_convert.c'; then $(CYGPATH_W) 'minivhd/minivhd_convert.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_convert.c'; fi` + +minivhd/pcem-minivhd_create.o: minivhd/minivhd_create.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_create.o -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_create.Tpo -c -o minivhd/pcem-minivhd_create.o `test -f 'minivhd/minivhd_create.c' || echo '$(srcdir)/'`minivhd/minivhd_create.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_create.Tpo minivhd/$(DEPDIR)/pcem-minivhd_create.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_create.c' object='minivhd/pcem-minivhd_create.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_create.o `test -f 'minivhd/minivhd_create.c' || echo '$(srcdir)/'`minivhd/minivhd_create.c + +minivhd/pcem-minivhd_create.obj: minivhd/minivhd_create.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_create.obj -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_create.Tpo -c -o minivhd/pcem-minivhd_create.obj `if test -f 'minivhd/minivhd_create.c'; then $(CYGPATH_W) 'minivhd/minivhd_create.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_create.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_create.Tpo minivhd/$(DEPDIR)/pcem-minivhd_create.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_create.c' object='minivhd/pcem-minivhd_create.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_create.obj `if test -f 'minivhd/minivhd_create.c'; then $(CYGPATH_W) 'minivhd/minivhd_create.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_create.c'; fi` + +minivhd/pcem-minivhd_io.o: minivhd/minivhd_io.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_io.o -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_io.Tpo -c -o minivhd/pcem-minivhd_io.o `test -f 'minivhd/minivhd_io.c' || echo '$(srcdir)/'`minivhd/minivhd_io.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_io.Tpo minivhd/$(DEPDIR)/pcem-minivhd_io.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_io.c' object='minivhd/pcem-minivhd_io.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_io.o `test -f 'minivhd/minivhd_io.c' || echo '$(srcdir)/'`minivhd/minivhd_io.c + +minivhd/pcem-minivhd_io.obj: minivhd/minivhd_io.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_io.obj -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_io.Tpo -c -o minivhd/pcem-minivhd_io.obj `if test -f 'minivhd/minivhd_io.c'; then $(CYGPATH_W) 'minivhd/minivhd_io.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_io.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_io.Tpo minivhd/$(DEPDIR)/pcem-minivhd_io.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_io.c' object='minivhd/pcem-minivhd_io.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_io.obj `if test -f 'minivhd/minivhd_io.c'; then $(CYGPATH_W) 'minivhd/minivhd_io.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_io.c'; fi` + +minivhd/pcem-minivhd_manage.o: minivhd/minivhd_manage.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_manage.o -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_manage.Tpo -c -o minivhd/pcem-minivhd_manage.o `test -f 'minivhd/minivhd_manage.c' || echo '$(srcdir)/'`minivhd/minivhd_manage.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_manage.Tpo minivhd/$(DEPDIR)/pcem-minivhd_manage.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_manage.c' object='minivhd/pcem-minivhd_manage.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_manage.o `test -f 'minivhd/minivhd_manage.c' || echo '$(srcdir)/'`minivhd/minivhd_manage.c + +minivhd/pcem-minivhd_manage.obj: minivhd/minivhd_manage.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_manage.obj -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_manage.Tpo -c -o minivhd/pcem-minivhd_manage.obj `if test -f 'minivhd/minivhd_manage.c'; then $(CYGPATH_W) 'minivhd/minivhd_manage.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_manage.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_manage.Tpo minivhd/$(DEPDIR)/pcem-minivhd_manage.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_manage.c' object='minivhd/pcem-minivhd_manage.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_manage.obj `if test -f 'minivhd/minivhd_manage.c'; then $(CYGPATH_W) 'minivhd/minivhd_manage.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_manage.c'; fi` + +minivhd/pcem-minivhd_struct_rw.o: minivhd/minivhd_struct_rw.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_struct_rw.o -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Tpo -c -o minivhd/pcem-minivhd_struct_rw.o `test -f 'minivhd/minivhd_struct_rw.c' || echo '$(srcdir)/'`minivhd/minivhd_struct_rw.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Tpo minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_struct_rw.c' object='minivhd/pcem-minivhd_struct_rw.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_struct_rw.o `test -f 'minivhd/minivhd_struct_rw.c' || echo '$(srcdir)/'`minivhd/minivhd_struct_rw.c + +minivhd/pcem-minivhd_struct_rw.obj: minivhd/minivhd_struct_rw.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_struct_rw.obj -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Tpo -c -o minivhd/pcem-minivhd_struct_rw.obj `if test -f 'minivhd/minivhd_struct_rw.c'; then $(CYGPATH_W) 'minivhd/minivhd_struct_rw.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_struct_rw.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Tpo minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_struct_rw.c' object='minivhd/pcem-minivhd_struct_rw.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_struct_rw.obj `if test -f 'minivhd/minivhd_struct_rw.c'; then $(CYGPATH_W) 'minivhd/minivhd_struct_rw.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_struct_rw.c'; fi` + +minivhd/pcem-minivhd_util.o: minivhd/minivhd_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_util.o -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_util.Tpo -c -o minivhd/pcem-minivhd_util.o `test -f 'minivhd/minivhd_util.c' || echo '$(srcdir)/'`minivhd/minivhd_util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_util.Tpo minivhd/$(DEPDIR)/pcem-minivhd_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_util.c' object='minivhd/pcem-minivhd_util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_util.o `test -f 'minivhd/minivhd_util.c' || echo '$(srcdir)/'`minivhd/minivhd_util.c + +minivhd/pcem-minivhd_util.obj: minivhd/minivhd_util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT minivhd/pcem-minivhd_util.obj -MD -MP -MF minivhd/$(DEPDIR)/pcem-minivhd_util.Tpo -c -o minivhd/pcem-minivhd_util.obj `if test -f 'minivhd/minivhd_util.c'; then $(CYGPATH_W) 'minivhd/minivhd_util.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) minivhd/$(DEPDIR)/pcem-minivhd_util.Tpo minivhd/$(DEPDIR)/pcem-minivhd_util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='minivhd/minivhd_util.c' object='minivhd/pcem-minivhd_util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o minivhd/pcem-minivhd_util.obj `if test -f 'minivhd/minivhd_util.c'; then $(CYGPATH_W) 'minivhd/minivhd_util.c'; else $(CYGPATH_W) '$(srcdir)/minivhd/minivhd_util.c'; fi` + +pcem-wx-config_sel.o: wx-config_sel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-config_sel.o -MD -MP -MF $(DEPDIR)/pcem-wx-config_sel.Tpo -c -o pcem-wx-config_sel.o `test -f 'wx-config_sel.c' || echo '$(srcdir)/'`wx-config_sel.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-config_sel.Tpo $(DEPDIR)/pcem-wx-config_sel.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-config_sel.c' object='pcem-wx-config_sel.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-config_sel.o `test -f 'wx-config_sel.c' || echo '$(srcdir)/'`wx-config_sel.c + +pcem-wx-config_sel.obj: wx-config_sel.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-config_sel.obj -MD -MP -MF $(DEPDIR)/pcem-wx-config_sel.Tpo -c -o pcem-wx-config_sel.obj `if test -f 'wx-config_sel.c'; then $(CYGPATH_W) 'wx-config_sel.c'; else $(CYGPATH_W) '$(srcdir)/wx-config_sel.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-config_sel.Tpo $(DEPDIR)/pcem-wx-config_sel.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-config_sel.c' object='pcem-wx-config_sel.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-config_sel.obj `if test -f 'wx-config_sel.c'; then $(CYGPATH_W) 'wx-config_sel.c'; else $(CYGPATH_W) '$(srcdir)/wx-config_sel.c'; fi` + +pcem-wx-sdl2-joystick.o: wx-sdl2-joystick.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-joystick.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-joystick.Tpo -c -o pcem-wx-sdl2-joystick.o `test -f 'wx-sdl2-joystick.c' || echo '$(srcdir)/'`wx-sdl2-joystick.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-joystick.Tpo $(DEPDIR)/pcem-wx-sdl2-joystick.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-joystick.c' object='pcem-wx-sdl2-joystick.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-joystick.o `test -f 'wx-sdl2-joystick.c' || echo '$(srcdir)/'`wx-sdl2-joystick.c + +pcem-wx-sdl2-joystick.obj: wx-sdl2-joystick.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-joystick.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-joystick.Tpo -c -o pcem-wx-sdl2-joystick.obj `if test -f 'wx-sdl2-joystick.c'; then $(CYGPATH_W) 'wx-sdl2-joystick.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-joystick.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-joystick.Tpo $(DEPDIR)/pcem-wx-sdl2-joystick.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-joystick.c' object='pcem-wx-sdl2-joystick.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-joystick.obj `if test -f 'wx-sdl2-joystick.c'; then $(CYGPATH_W) 'wx-sdl2-joystick.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-joystick.c'; fi` + +pcem-wx-sdl2-mouse.o: wx-sdl2-mouse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-mouse.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-mouse.Tpo -c -o pcem-wx-sdl2-mouse.o `test -f 'wx-sdl2-mouse.c' || echo '$(srcdir)/'`wx-sdl2-mouse.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-mouse.Tpo $(DEPDIR)/pcem-wx-sdl2-mouse.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-mouse.c' object='pcem-wx-sdl2-mouse.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-mouse.o `test -f 'wx-sdl2-mouse.c' || echo '$(srcdir)/'`wx-sdl2-mouse.c + +pcem-wx-sdl2-mouse.obj: wx-sdl2-mouse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-mouse.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-mouse.Tpo -c -o pcem-wx-sdl2-mouse.obj `if test -f 'wx-sdl2-mouse.c'; then $(CYGPATH_W) 'wx-sdl2-mouse.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-mouse.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-mouse.Tpo $(DEPDIR)/pcem-wx-sdl2-mouse.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-mouse.c' object='pcem-wx-sdl2-mouse.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-mouse.obj `if test -f 'wx-sdl2-mouse.c'; then $(CYGPATH_W) 'wx-sdl2-mouse.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-mouse.c'; fi` + +pcem-wx-sdl2-keyboard.o: wx-sdl2-keyboard.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-keyboard.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-keyboard.Tpo -c -o pcem-wx-sdl2-keyboard.o `test -f 'wx-sdl2-keyboard.c' || echo '$(srcdir)/'`wx-sdl2-keyboard.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-keyboard.Tpo $(DEPDIR)/pcem-wx-sdl2-keyboard.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-keyboard.c' object='pcem-wx-sdl2-keyboard.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-keyboard.o `test -f 'wx-sdl2-keyboard.c' || echo '$(srcdir)/'`wx-sdl2-keyboard.c + +pcem-wx-sdl2-keyboard.obj: wx-sdl2-keyboard.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-keyboard.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-keyboard.Tpo -c -o pcem-wx-sdl2-keyboard.obj `if test -f 'wx-sdl2-keyboard.c'; then $(CYGPATH_W) 'wx-sdl2-keyboard.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-keyboard.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-keyboard.Tpo $(DEPDIR)/pcem-wx-sdl2-keyboard.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-keyboard.c' object='pcem-wx-sdl2-keyboard.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-keyboard.obj `if test -f 'wx-sdl2-keyboard.c'; then $(CYGPATH_W) 'wx-sdl2-keyboard.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-keyboard.c'; fi` + +pcem-wx-sdl2-video.o: wx-sdl2-video.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-video.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-video.Tpo -c -o pcem-wx-sdl2-video.o `test -f 'wx-sdl2-video.c' || echo '$(srcdir)/'`wx-sdl2-video.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-video.Tpo $(DEPDIR)/pcem-wx-sdl2-video.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-video.c' object='pcem-wx-sdl2-video.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-video.o `test -f 'wx-sdl2-video.c' || echo '$(srcdir)/'`wx-sdl2-video.c + +pcem-wx-sdl2-video.obj: wx-sdl2-video.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-video.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-video.Tpo -c -o pcem-wx-sdl2-video.obj `if test -f 'wx-sdl2-video.c'; then $(CYGPATH_W) 'wx-sdl2-video.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-video.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-video.Tpo $(DEPDIR)/pcem-wx-sdl2-video.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-video.c' object='pcem-wx-sdl2-video.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-video.obj `if test -f 'wx-sdl2-video.c'; then $(CYGPATH_W) 'wx-sdl2-video.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-video.c'; fi` + +pcem-wx-sdl2.o: wx-sdl2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2.Tpo -c -o pcem-wx-sdl2.o `test -f 'wx-sdl2.c' || echo '$(srcdir)/'`wx-sdl2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2.Tpo $(DEPDIR)/pcem-wx-sdl2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2.c' object='pcem-wx-sdl2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2.o `test -f 'wx-sdl2.c' || echo '$(srcdir)/'`wx-sdl2.c + +pcem-wx-sdl2.obj: wx-sdl2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2.Tpo -c -o pcem-wx-sdl2.obj `if test -f 'wx-sdl2.c'; then $(CYGPATH_W) 'wx-sdl2.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2.Tpo $(DEPDIR)/pcem-wx-sdl2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2.c' object='pcem-wx-sdl2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2.obj `if test -f 'wx-sdl2.c'; then $(CYGPATH_W) 'wx-sdl2.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2.c'; fi` + +pcem-wx-config.o: wx-config.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-config.o -MD -MP -MF $(DEPDIR)/pcem-wx-config.Tpo -c -o pcem-wx-config.o `test -f 'wx-config.c' || echo '$(srcdir)/'`wx-config.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-config.Tpo $(DEPDIR)/pcem-wx-config.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-config.c' object='pcem-wx-config.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-config.o `test -f 'wx-config.c' || echo '$(srcdir)/'`wx-config.c + +pcem-wx-config.obj: wx-config.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-config.obj -MD -MP -MF $(DEPDIR)/pcem-wx-config.Tpo -c -o pcem-wx-config.obj `if test -f 'wx-config.c'; then $(CYGPATH_W) 'wx-config.c'; else $(CYGPATH_W) '$(srcdir)/wx-config.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-config.Tpo $(DEPDIR)/pcem-wx-config.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-config.c' object='pcem-wx-config.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-config.obj `if test -f 'wx-config.c'; then $(CYGPATH_W) 'wx-config.c'; else $(CYGPATH_W) '$(srcdir)/wx-config.c'; fi` + +pcem-wx-sdl2-status.o: wx-sdl2-status.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-status.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-status.Tpo -c -o pcem-wx-sdl2-status.o `test -f 'wx-sdl2-status.c' || echo '$(srcdir)/'`wx-sdl2-status.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-status.Tpo $(DEPDIR)/pcem-wx-sdl2-status.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-status.c' object='pcem-wx-sdl2-status.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-status.o `test -f 'wx-sdl2-status.c' || echo '$(srcdir)/'`wx-sdl2-status.c + +pcem-wx-sdl2-status.obj: wx-sdl2-status.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-status.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-status.Tpo -c -o pcem-wx-sdl2-status.obj `if test -f 'wx-sdl2-status.c'; then $(CYGPATH_W) 'wx-sdl2-status.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-status.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-status.Tpo $(DEPDIR)/pcem-wx-sdl2-status.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-status.c' object='pcem-wx-sdl2-status.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-status.obj `if test -f 'wx-sdl2-status.c'; then $(CYGPATH_W) 'wx-sdl2-status.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-status.c'; fi` + +pcem-wx-thread.o: wx-thread.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-thread.o -MD -MP -MF $(DEPDIR)/pcem-wx-thread.Tpo -c -o pcem-wx-thread.o `test -f 'wx-thread.c' || echo '$(srcdir)/'`wx-thread.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-thread.Tpo $(DEPDIR)/pcem-wx-thread.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-thread.c' object='pcem-wx-thread.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-thread.o `test -f 'wx-thread.c' || echo '$(srcdir)/'`wx-thread.c + +pcem-wx-thread.obj: wx-thread.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-thread.obj -MD -MP -MF $(DEPDIR)/pcem-wx-thread.Tpo -c -o pcem-wx-thread.obj `if test -f 'wx-thread.c'; then $(CYGPATH_W) 'wx-thread.c'; else $(CYGPATH_W) '$(srcdir)/wx-thread.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-thread.Tpo $(DEPDIR)/pcem-wx-thread.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-thread.c' object='pcem-wx-thread.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-thread.obj `if test -f 'wx-thread.c'; then $(CYGPATH_W) 'wx-thread.c'; else $(CYGPATH_W) '$(srcdir)/wx-thread.c'; fi` + +pcem-wx-common.o: wx-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-common.o -MD -MP -MF $(DEPDIR)/pcem-wx-common.Tpo -c -o pcem-wx-common.o `test -f 'wx-common.c' || echo '$(srcdir)/'`wx-common.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-common.Tpo $(DEPDIR)/pcem-wx-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-common.c' object='pcem-wx-common.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-common.o `test -f 'wx-common.c' || echo '$(srcdir)/'`wx-common.c + +pcem-wx-common.obj: wx-common.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-common.obj -MD -MP -MF $(DEPDIR)/pcem-wx-common.Tpo -c -o pcem-wx-common.obj `if test -f 'wx-common.c'; then $(CYGPATH_W) 'wx-common.c'; else $(CYGPATH_W) '$(srcdir)/wx-common.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-common.Tpo $(DEPDIR)/pcem-wx-common.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-common.c' object='pcem-wx-common.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-common.obj `if test -f 'wx-common.c'; then $(CYGPATH_W) 'wx-common.c'; else $(CYGPATH_W) '$(srcdir)/wx-common.c'; fi` + +pcem-wx-sdl2-video-renderer.o: wx-sdl2-video-renderer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-video-renderer.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-video-renderer.Tpo -c -o pcem-wx-sdl2-video-renderer.o `test -f 'wx-sdl2-video-renderer.c' || echo '$(srcdir)/'`wx-sdl2-video-renderer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-video-renderer.Tpo $(DEPDIR)/pcem-wx-sdl2-video-renderer.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-video-renderer.c' object='pcem-wx-sdl2-video-renderer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-video-renderer.o `test -f 'wx-sdl2-video-renderer.c' || echo '$(srcdir)/'`wx-sdl2-video-renderer.c + +pcem-wx-sdl2-video-renderer.obj: wx-sdl2-video-renderer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-video-renderer.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-video-renderer.Tpo -c -o pcem-wx-sdl2-video-renderer.obj `if test -f 'wx-sdl2-video-renderer.c'; then $(CYGPATH_W) 'wx-sdl2-video-renderer.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-video-renderer.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-video-renderer.Tpo $(DEPDIR)/pcem-wx-sdl2-video-renderer.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-video-renderer.c' object='pcem-wx-sdl2-video-renderer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-video-renderer.obj `if test -f 'wx-sdl2-video-renderer.c'; then $(CYGPATH_W) 'wx-sdl2-video-renderer.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-video-renderer.c'; fi` + +pcem-wx-sdl2-video-gl3.o: wx-sdl2-video-gl3.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-video-gl3.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-video-gl3.Tpo -c -o pcem-wx-sdl2-video-gl3.o `test -f 'wx-sdl2-video-gl3.c' || echo '$(srcdir)/'`wx-sdl2-video-gl3.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-video-gl3.Tpo $(DEPDIR)/pcem-wx-sdl2-video-gl3.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-video-gl3.c' object='pcem-wx-sdl2-video-gl3.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-video-gl3.o `test -f 'wx-sdl2-video-gl3.c' || echo '$(srcdir)/'`wx-sdl2-video-gl3.c + +pcem-wx-sdl2-video-gl3.obj: wx-sdl2-video-gl3.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-video-gl3.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-video-gl3.Tpo -c -o pcem-wx-sdl2-video-gl3.obj `if test -f 'wx-sdl2-video-gl3.c'; then $(CYGPATH_W) 'wx-sdl2-video-gl3.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-video-gl3.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-video-gl3.Tpo $(DEPDIR)/pcem-wx-sdl2-video-gl3.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-video-gl3.c' object='pcem-wx-sdl2-video-gl3.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-video-gl3.obj `if test -f 'wx-sdl2-video-gl3.c'; then $(CYGPATH_W) 'wx-sdl2-video-gl3.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-video-gl3.c'; fi` + +pcem-wx-glslp-parser.o: wx-glslp-parser.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-glslp-parser.o -MD -MP -MF $(DEPDIR)/pcem-wx-glslp-parser.Tpo -c -o pcem-wx-glslp-parser.o `test -f 'wx-glslp-parser.c' || echo '$(srcdir)/'`wx-glslp-parser.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-glslp-parser.Tpo $(DEPDIR)/pcem-wx-glslp-parser.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-glslp-parser.c' object='pcem-wx-glslp-parser.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-glslp-parser.o `test -f 'wx-glslp-parser.c' || echo '$(srcdir)/'`wx-glslp-parser.c + +pcem-wx-glslp-parser.obj: wx-glslp-parser.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-glslp-parser.obj -MD -MP -MF $(DEPDIR)/pcem-wx-glslp-parser.Tpo -c -o pcem-wx-glslp-parser.obj `if test -f 'wx-glslp-parser.c'; then $(CYGPATH_W) 'wx-glslp-parser.c'; else $(CYGPATH_W) '$(srcdir)/wx-glslp-parser.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-glslp-parser.Tpo $(DEPDIR)/pcem-wx-glslp-parser.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-glslp-parser.c' object='pcem-wx-glslp-parser.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-glslp-parser.obj `if test -f 'wx-glslp-parser.c'; then $(CYGPATH_W) 'wx-glslp-parser.c'; else $(CYGPATH_W) '$(srcdir)/wx-glslp-parser.c'; fi` + +pcem-wx-shader_man.o: wx-shader_man.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-shader_man.o -MD -MP -MF $(DEPDIR)/pcem-wx-shader_man.Tpo -c -o pcem-wx-shader_man.o `test -f 'wx-shader_man.c' || echo '$(srcdir)/'`wx-shader_man.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-shader_man.Tpo $(DEPDIR)/pcem-wx-shader_man.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-shader_man.c' object='pcem-wx-shader_man.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-shader_man.o `test -f 'wx-shader_man.c' || echo '$(srcdir)/'`wx-shader_man.c + +pcem-wx-shader_man.obj: wx-shader_man.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-shader_man.obj -MD -MP -MF $(DEPDIR)/pcem-wx-shader_man.Tpo -c -o pcem-wx-shader_man.obj `if test -f 'wx-shader_man.c'; then $(CYGPATH_W) 'wx-shader_man.c'; else $(CYGPATH_W) '$(srcdir)/wx-shader_man.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-shader_man.Tpo $(DEPDIR)/pcem-wx-shader_man.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-shader_man.c' object='pcem-wx-shader_man.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-shader_man.obj `if test -f 'wx-shader_man.c'; then $(CYGPATH_W) 'wx-shader_man.c'; else $(CYGPATH_W) '$(srcdir)/wx-shader_man.c'; fi` + +pcem-midi_alsa.o: midi_alsa.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-midi_alsa.o -MD -MP -MF $(DEPDIR)/pcem-midi_alsa.Tpo -c -o pcem-midi_alsa.o `test -f 'midi_alsa.c' || echo '$(srcdir)/'`midi_alsa.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-midi_alsa.Tpo $(DEPDIR)/pcem-midi_alsa.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='midi_alsa.c' object='pcem-midi_alsa.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-midi_alsa.o `test -f 'midi_alsa.c' || echo '$(srcdir)/'`midi_alsa.c + +pcem-midi_alsa.obj: midi_alsa.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-midi_alsa.obj -MD -MP -MF $(DEPDIR)/pcem-midi_alsa.Tpo -c -o pcem-midi_alsa.obj `if test -f 'midi_alsa.c'; then $(CYGPATH_W) 'midi_alsa.c'; else $(CYGPATH_W) '$(srcdir)/midi_alsa.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-midi_alsa.Tpo $(DEPDIR)/pcem-midi_alsa.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='midi_alsa.c' object='pcem-midi_alsa.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-midi_alsa.obj `if test -f 'midi_alsa.c'; then $(CYGPATH_W) 'midi_alsa.c'; else $(CYGPATH_W) '$(srcdir)/midi_alsa.c'; fi` + +pcem-wx-sdl2-midi.o: wx-sdl2-midi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-midi.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-midi.Tpo -c -o pcem-wx-sdl2-midi.o `test -f 'wx-sdl2-midi.c' || echo '$(srcdir)/'`wx-sdl2-midi.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-midi.Tpo $(DEPDIR)/pcem-wx-sdl2-midi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-midi.c' object='pcem-wx-sdl2-midi.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-midi.o `test -f 'wx-sdl2-midi.c' || echo '$(srcdir)/'`wx-sdl2-midi.c + +pcem-wx-sdl2-midi.obj: wx-sdl2-midi.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-midi.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-midi.Tpo -c -o pcem-wx-sdl2-midi.obj `if test -f 'wx-sdl2-midi.c'; then $(CYGPATH_W) 'wx-sdl2-midi.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-midi.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-midi.Tpo $(DEPDIR)/pcem-wx-sdl2-midi.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-midi.c' object='pcem-wx-sdl2-midi.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-midi.obj `if test -f 'wx-sdl2-midi.c'; then $(CYGPATH_W) 'wx-sdl2-midi.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-midi.c'; fi` + +pcem-codegen_backend_x86.o: codegen_backend_x86.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86.Tpo -c -o pcem-codegen_backend_x86.o `test -f 'codegen_backend_x86.c' || echo '$(srcdir)/'`codegen_backend_x86.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86.Tpo $(DEPDIR)/pcem-codegen_backend_x86.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86.c' object='pcem-codegen_backend_x86.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86.o `test -f 'codegen_backend_x86.c' || echo '$(srcdir)/'`codegen_backend_x86.c + +pcem-codegen_backend_x86.obj: codegen_backend_x86.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86.Tpo -c -o pcem-codegen_backend_x86.obj `if test -f 'codegen_backend_x86.c'; then $(CYGPATH_W) 'codegen_backend_x86.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86.Tpo $(DEPDIR)/pcem-codegen_backend_x86.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86.c' object='pcem-codegen_backend_x86.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86.obj `if test -f 'codegen_backend_x86.c'; then $(CYGPATH_W) 'codegen_backend_x86.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86.c'; fi` + +pcem-codegen_backend_x86_ops.o: codegen_backend_x86_ops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86_ops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86_ops.Tpo -c -o pcem-codegen_backend_x86_ops.o `test -f 'codegen_backend_x86_ops.c' || echo '$(srcdir)/'`codegen_backend_x86_ops.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86_ops.Tpo $(DEPDIR)/pcem-codegen_backend_x86_ops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86_ops.c' object='pcem-codegen_backend_x86_ops.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86_ops.o `test -f 'codegen_backend_x86_ops.c' || echo '$(srcdir)/'`codegen_backend_x86_ops.c + +pcem-codegen_backend_x86_ops.obj: codegen_backend_x86_ops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86_ops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86_ops.Tpo -c -o pcem-codegen_backend_x86_ops.obj `if test -f 'codegen_backend_x86_ops.c'; then $(CYGPATH_W) 'codegen_backend_x86_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86_ops.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86_ops.Tpo $(DEPDIR)/pcem-codegen_backend_x86_ops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86_ops.c' object='pcem-codegen_backend_x86_ops.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86_ops.obj `if test -f 'codegen_backend_x86_ops.c'; then $(CYGPATH_W) 'codegen_backend_x86_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86_ops.c'; fi` + +pcem-codegen_backend_x86_ops_fpu.o: codegen_backend_x86_ops_fpu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86_ops_fpu.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Tpo -c -o pcem-codegen_backend_x86_ops_fpu.o `test -f 'codegen_backend_x86_ops_fpu.c' || echo '$(srcdir)/'`codegen_backend_x86_ops_fpu.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Tpo $(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86_ops_fpu.c' object='pcem-codegen_backend_x86_ops_fpu.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86_ops_fpu.o `test -f 'codegen_backend_x86_ops_fpu.c' || echo '$(srcdir)/'`codegen_backend_x86_ops_fpu.c + +pcem-codegen_backend_x86_ops_fpu.obj: codegen_backend_x86_ops_fpu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86_ops_fpu.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Tpo -c -o pcem-codegen_backend_x86_ops_fpu.obj `if test -f 'codegen_backend_x86_ops_fpu.c'; then $(CYGPATH_W) 'codegen_backend_x86_ops_fpu.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86_ops_fpu.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Tpo $(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86_ops_fpu.c' object='pcem-codegen_backend_x86_ops_fpu.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86_ops_fpu.obj `if test -f 'codegen_backend_x86_ops_fpu.c'; then $(CYGPATH_W) 'codegen_backend_x86_ops_fpu.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86_ops_fpu.c'; fi` + +pcem-codegen_backend_x86_ops_sse.o: codegen_backend_x86_ops_sse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86_ops_sse.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Tpo -c -o pcem-codegen_backend_x86_ops_sse.o `test -f 'codegen_backend_x86_ops_sse.c' || echo '$(srcdir)/'`codegen_backend_x86_ops_sse.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Tpo $(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86_ops_sse.c' object='pcem-codegen_backend_x86_ops_sse.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86_ops_sse.o `test -f 'codegen_backend_x86_ops_sse.c' || echo '$(srcdir)/'`codegen_backend_x86_ops_sse.c + +pcem-codegen_backend_x86_ops_sse.obj: codegen_backend_x86_ops_sse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86_ops_sse.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Tpo -c -o pcem-codegen_backend_x86_ops_sse.obj `if test -f 'codegen_backend_x86_ops_sse.c'; then $(CYGPATH_W) 'codegen_backend_x86_ops_sse.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86_ops_sse.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Tpo $(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86_ops_sse.c' object='pcem-codegen_backend_x86_ops_sse.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86_ops_sse.obj `if test -f 'codegen_backend_x86_ops_sse.c'; then $(CYGPATH_W) 'codegen_backend_x86_ops_sse.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86_ops_sse.c'; fi` + +pcem-codegen_backend_x86_uops.o: codegen_backend_x86_uops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86_uops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86_uops.Tpo -c -o pcem-codegen_backend_x86_uops.o `test -f 'codegen_backend_x86_uops.c' || echo '$(srcdir)/'`codegen_backend_x86_uops.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86_uops.Tpo $(DEPDIR)/pcem-codegen_backend_x86_uops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86_uops.c' object='pcem-codegen_backend_x86_uops.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86_uops.o `test -f 'codegen_backend_x86_uops.c' || echo '$(srcdir)/'`codegen_backend_x86_uops.c + +pcem-codegen_backend_x86_uops.obj: codegen_backend_x86_uops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86_uops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86_uops.Tpo -c -o pcem-codegen_backend_x86_uops.obj `if test -f 'codegen_backend_x86_uops.c'; then $(CYGPATH_W) 'codegen_backend_x86_uops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86_uops.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86_uops.Tpo $(DEPDIR)/pcem-codegen_backend_x86_uops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86_uops.c' object='pcem-codegen_backend_x86_uops.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86_uops.obj `if test -f 'codegen_backend_x86_uops.c'; then $(CYGPATH_W) 'codegen_backend_x86_uops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86_uops.c'; fi` + +pcem-codegen_backend_x86-64.o: codegen_backend_x86-64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86-64.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86-64.Tpo -c -o pcem-codegen_backend_x86-64.o `test -f 'codegen_backend_x86-64.c' || echo '$(srcdir)/'`codegen_backend_x86-64.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86-64.Tpo $(DEPDIR)/pcem-codegen_backend_x86-64.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86-64.c' object='pcem-codegen_backend_x86-64.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86-64.o `test -f 'codegen_backend_x86-64.c' || echo '$(srcdir)/'`codegen_backend_x86-64.c + +pcem-codegen_backend_x86-64.obj: codegen_backend_x86-64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86-64.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86-64.Tpo -c -o pcem-codegen_backend_x86-64.obj `if test -f 'codegen_backend_x86-64.c'; then $(CYGPATH_W) 'codegen_backend_x86-64.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86-64.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86-64.Tpo $(DEPDIR)/pcem-codegen_backend_x86-64.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86-64.c' object='pcem-codegen_backend_x86-64.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86-64.obj `if test -f 'codegen_backend_x86-64.c'; then $(CYGPATH_W) 'codegen_backend_x86-64.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86-64.c'; fi` + +pcem-codegen_backend_x86-64_ops.o: codegen_backend_x86-64_ops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86-64_ops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86-64_ops.Tpo -c -o pcem-codegen_backend_x86-64_ops.o `test -f 'codegen_backend_x86-64_ops.c' || echo '$(srcdir)/'`codegen_backend_x86-64_ops.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86-64_ops.Tpo $(DEPDIR)/pcem-codegen_backend_x86-64_ops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86-64_ops.c' object='pcem-codegen_backend_x86-64_ops.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86-64_ops.o `test -f 'codegen_backend_x86-64_ops.c' || echo '$(srcdir)/'`codegen_backend_x86-64_ops.c + +pcem-codegen_backend_x86-64_ops.obj: codegen_backend_x86-64_ops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86-64_ops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86-64_ops.Tpo -c -o pcem-codegen_backend_x86-64_ops.obj `if test -f 'codegen_backend_x86-64_ops.c'; then $(CYGPATH_W) 'codegen_backend_x86-64_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86-64_ops.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86-64_ops.Tpo $(DEPDIR)/pcem-codegen_backend_x86-64_ops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86-64_ops.c' object='pcem-codegen_backend_x86-64_ops.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86-64_ops.obj `if test -f 'codegen_backend_x86-64_ops.c'; then $(CYGPATH_W) 'codegen_backend_x86-64_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86-64_ops.c'; fi` + +pcem-codegen_backend_x86-64_ops_sse.o: codegen_backend_x86-64_ops_sse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86-64_ops_sse.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Tpo -c -o pcem-codegen_backend_x86-64_ops_sse.o `test -f 'codegen_backend_x86-64_ops_sse.c' || echo '$(srcdir)/'`codegen_backend_x86-64_ops_sse.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Tpo $(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86-64_ops_sse.c' object='pcem-codegen_backend_x86-64_ops_sse.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86-64_ops_sse.o `test -f 'codegen_backend_x86-64_ops_sse.c' || echo '$(srcdir)/'`codegen_backend_x86-64_ops_sse.c + +pcem-codegen_backend_x86-64_ops_sse.obj: codegen_backend_x86-64_ops_sse.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86-64_ops_sse.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Tpo -c -o pcem-codegen_backend_x86-64_ops_sse.obj `if test -f 'codegen_backend_x86-64_ops_sse.c'; then $(CYGPATH_W) 'codegen_backend_x86-64_ops_sse.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86-64_ops_sse.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Tpo $(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86-64_ops_sse.c' object='pcem-codegen_backend_x86-64_ops_sse.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86-64_ops_sse.obj `if test -f 'codegen_backend_x86-64_ops_sse.c'; then $(CYGPATH_W) 'codegen_backend_x86-64_ops_sse.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86-64_ops_sse.c'; fi` + +pcem-codegen_backend_x86-64_uops.o: codegen_backend_x86-64_uops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86-64_uops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86-64_uops.Tpo -c -o pcem-codegen_backend_x86-64_uops.o `test -f 'codegen_backend_x86-64_uops.c' || echo '$(srcdir)/'`codegen_backend_x86-64_uops.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86-64_uops.Tpo $(DEPDIR)/pcem-codegen_backend_x86-64_uops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86-64_uops.c' object='pcem-codegen_backend_x86-64_uops.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86-64_uops.o `test -f 'codegen_backend_x86-64_uops.c' || echo '$(srcdir)/'`codegen_backend_x86-64_uops.c + +pcem-codegen_backend_x86-64_uops.obj: codegen_backend_x86-64_uops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_x86-64_uops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_x86-64_uops.Tpo -c -o pcem-codegen_backend_x86-64_uops.obj `if test -f 'codegen_backend_x86-64_uops.c'; then $(CYGPATH_W) 'codegen_backend_x86-64_uops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86-64_uops.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_x86-64_uops.Tpo $(DEPDIR)/pcem-codegen_backend_x86-64_uops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_x86-64_uops.c' object='pcem-codegen_backend_x86-64_uops.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_x86-64_uops.obj `if test -f 'codegen_backend_x86-64_uops.c'; then $(CYGPATH_W) 'codegen_backend_x86-64_uops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_x86-64_uops.c'; fi` + +pcem-codegen_backend_arm.o: codegen_backend_arm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm.Tpo -c -o pcem-codegen_backend_arm.o `test -f 'codegen_backend_arm.c' || echo '$(srcdir)/'`codegen_backend_arm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm.Tpo $(DEPDIR)/pcem-codegen_backend_arm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm.c' object='pcem-codegen_backend_arm.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm.o `test -f 'codegen_backend_arm.c' || echo '$(srcdir)/'`codegen_backend_arm.c + +pcem-codegen_backend_arm.obj: codegen_backend_arm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm.Tpo -c -o pcem-codegen_backend_arm.obj `if test -f 'codegen_backend_arm.c'; then $(CYGPATH_W) 'codegen_backend_arm.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm.Tpo $(DEPDIR)/pcem-codegen_backend_arm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm.c' object='pcem-codegen_backend_arm.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm.obj `if test -f 'codegen_backend_arm.c'; then $(CYGPATH_W) 'codegen_backend_arm.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm.c'; fi` + +pcem-codegen_backend_arm_ops.o: codegen_backend_arm_ops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm_ops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm_ops.Tpo -c -o pcem-codegen_backend_arm_ops.o `test -f 'codegen_backend_arm_ops.c' || echo '$(srcdir)/'`codegen_backend_arm_ops.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm_ops.Tpo $(DEPDIR)/pcem-codegen_backend_arm_ops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm_ops.c' object='pcem-codegen_backend_arm_ops.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm_ops.o `test -f 'codegen_backend_arm_ops.c' || echo '$(srcdir)/'`codegen_backend_arm_ops.c + +pcem-codegen_backend_arm_ops.obj: codegen_backend_arm_ops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm_ops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm_ops.Tpo -c -o pcem-codegen_backend_arm_ops.obj `if test -f 'codegen_backend_arm_ops.c'; then $(CYGPATH_W) 'codegen_backend_arm_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm_ops.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm_ops.Tpo $(DEPDIR)/pcem-codegen_backend_arm_ops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm_ops.c' object='pcem-codegen_backend_arm_ops.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm_ops.obj `if test -f 'codegen_backend_arm_ops.c'; then $(CYGPATH_W) 'codegen_backend_arm_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm_ops.c'; fi` + +pcem-codegen_backend_arm_uops.o: codegen_backend_arm_uops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm_uops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm_uops.Tpo -c -o pcem-codegen_backend_arm_uops.o `test -f 'codegen_backend_arm_uops.c' || echo '$(srcdir)/'`codegen_backend_arm_uops.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm_uops.Tpo $(DEPDIR)/pcem-codegen_backend_arm_uops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm_uops.c' object='pcem-codegen_backend_arm_uops.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm_uops.o `test -f 'codegen_backend_arm_uops.c' || echo '$(srcdir)/'`codegen_backend_arm_uops.c + +pcem-codegen_backend_arm_uops.obj: codegen_backend_arm_uops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm_uops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm_uops.Tpo -c -o pcem-codegen_backend_arm_uops.obj `if test -f 'codegen_backend_arm_uops.c'; then $(CYGPATH_W) 'codegen_backend_arm_uops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm_uops.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm_uops.Tpo $(DEPDIR)/pcem-codegen_backend_arm_uops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm_uops.c' object='pcem-codegen_backend_arm_uops.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm_uops.obj `if test -f 'codegen_backend_arm_uops.c'; then $(CYGPATH_W) 'codegen_backend_arm_uops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm_uops.c'; fi` + +pcem-codegen_backend_arm64.o: codegen_backend_arm64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm64.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm64.Tpo -c -o pcem-codegen_backend_arm64.o `test -f 'codegen_backend_arm64.c' || echo '$(srcdir)/'`codegen_backend_arm64.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm64.Tpo $(DEPDIR)/pcem-codegen_backend_arm64.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm64.c' object='pcem-codegen_backend_arm64.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm64.o `test -f 'codegen_backend_arm64.c' || echo '$(srcdir)/'`codegen_backend_arm64.c + +pcem-codegen_backend_arm64.obj: codegen_backend_arm64.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm64.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm64.Tpo -c -o pcem-codegen_backend_arm64.obj `if test -f 'codegen_backend_arm64.c'; then $(CYGPATH_W) 'codegen_backend_arm64.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm64.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm64.Tpo $(DEPDIR)/pcem-codegen_backend_arm64.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm64.c' object='pcem-codegen_backend_arm64.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm64.obj `if test -f 'codegen_backend_arm64.c'; then $(CYGPATH_W) 'codegen_backend_arm64.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm64.c'; fi` + +pcem-codegen_backend_arm64_imm.o: codegen_backend_arm64_imm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm64_imm.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm64_imm.Tpo -c -o pcem-codegen_backend_arm64_imm.o `test -f 'codegen_backend_arm64_imm.c' || echo '$(srcdir)/'`codegen_backend_arm64_imm.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm64_imm.Tpo $(DEPDIR)/pcem-codegen_backend_arm64_imm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm64_imm.c' object='pcem-codegen_backend_arm64_imm.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm64_imm.o `test -f 'codegen_backend_arm64_imm.c' || echo '$(srcdir)/'`codegen_backend_arm64_imm.c + +pcem-codegen_backend_arm64_imm.obj: codegen_backend_arm64_imm.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm64_imm.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm64_imm.Tpo -c -o pcem-codegen_backend_arm64_imm.obj `if test -f 'codegen_backend_arm64_imm.c'; then $(CYGPATH_W) 'codegen_backend_arm64_imm.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm64_imm.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm64_imm.Tpo $(DEPDIR)/pcem-codegen_backend_arm64_imm.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm64_imm.c' object='pcem-codegen_backend_arm64_imm.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm64_imm.obj `if test -f 'codegen_backend_arm64_imm.c'; then $(CYGPATH_W) 'codegen_backend_arm64_imm.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm64_imm.c'; fi` + +pcem-codegen_backend_arm64_ops.o: codegen_backend_arm64_ops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm64_ops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm64_ops.Tpo -c -o pcem-codegen_backend_arm64_ops.o `test -f 'codegen_backend_arm64_ops.c' || echo '$(srcdir)/'`codegen_backend_arm64_ops.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm64_ops.Tpo $(DEPDIR)/pcem-codegen_backend_arm64_ops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm64_ops.c' object='pcem-codegen_backend_arm64_ops.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm64_ops.o `test -f 'codegen_backend_arm64_ops.c' || echo '$(srcdir)/'`codegen_backend_arm64_ops.c + +pcem-codegen_backend_arm64_ops.obj: codegen_backend_arm64_ops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm64_ops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm64_ops.Tpo -c -o pcem-codegen_backend_arm64_ops.obj `if test -f 'codegen_backend_arm64_ops.c'; then $(CYGPATH_W) 'codegen_backend_arm64_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm64_ops.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm64_ops.Tpo $(DEPDIR)/pcem-codegen_backend_arm64_ops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm64_ops.c' object='pcem-codegen_backend_arm64_ops.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm64_ops.obj `if test -f 'codegen_backend_arm64_ops.c'; then $(CYGPATH_W) 'codegen_backend_arm64_ops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm64_ops.c'; fi` + +pcem-codegen_backend_arm64_uops.o: codegen_backend_arm64_uops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm64_uops.o -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm64_uops.Tpo -c -o pcem-codegen_backend_arm64_uops.o `test -f 'codegen_backend_arm64_uops.c' || echo '$(srcdir)/'`codegen_backend_arm64_uops.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm64_uops.Tpo $(DEPDIR)/pcem-codegen_backend_arm64_uops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm64_uops.c' object='pcem-codegen_backend_arm64_uops.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm64_uops.o `test -f 'codegen_backend_arm64_uops.c' || echo '$(srcdir)/'`codegen_backend_arm64_uops.c + +pcem-codegen_backend_arm64_uops.obj: codegen_backend_arm64_uops.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-codegen_backend_arm64_uops.obj -MD -MP -MF $(DEPDIR)/pcem-codegen_backend_arm64_uops.Tpo -c -o pcem-codegen_backend_arm64_uops.obj `if test -f 'codegen_backend_arm64_uops.c'; then $(CYGPATH_W) 'codegen_backend_arm64_uops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm64_uops.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-codegen_backend_arm64_uops.Tpo $(DEPDIR)/pcem-codegen_backend_arm64_uops.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='codegen_backend_arm64_uops.c' object='pcem-codegen_backend_arm64_uops.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-codegen_backend_arm64_uops.obj `if test -f 'codegen_backend_arm64_uops.c'; then $(CYGPATH_W) 'codegen_backend_arm64_uops.c'; else $(CYGPATH_W) '$(srcdir)/codegen_backend_arm64_uops.c'; fi` + +pcem-ne2000.o: ne2000.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ne2000.o -MD -MP -MF $(DEPDIR)/pcem-ne2000.Tpo -c -o pcem-ne2000.o `test -f 'ne2000.c' || echo '$(srcdir)/'`ne2000.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-ne2000.Tpo $(DEPDIR)/pcem-ne2000.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ne2000.c' object='pcem-ne2000.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ne2000.o `test -f 'ne2000.c' || echo '$(srcdir)/'`ne2000.c + +pcem-ne2000.obj: ne2000.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-ne2000.obj -MD -MP -MF $(DEPDIR)/pcem-ne2000.Tpo -c -o pcem-ne2000.obj `if test -f 'ne2000.c'; then $(CYGPATH_W) 'ne2000.c'; else $(CYGPATH_W) '$(srcdir)/ne2000.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-ne2000.Tpo $(DEPDIR)/pcem-ne2000.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ne2000.c' object='pcem-ne2000.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-ne2000.obj `if test -f 'ne2000.c'; then $(CYGPATH_W) 'ne2000.c'; else $(CYGPATH_W) '$(srcdir)/ne2000.c'; fi` + +pcem-nethandler.o: nethandler.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-nethandler.o -MD -MP -MF $(DEPDIR)/pcem-nethandler.Tpo -c -o pcem-nethandler.o `test -f 'nethandler.c' || echo '$(srcdir)/'`nethandler.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-nethandler.Tpo $(DEPDIR)/pcem-nethandler.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nethandler.c' object='pcem-nethandler.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-nethandler.o `test -f 'nethandler.c' || echo '$(srcdir)/'`nethandler.c + +pcem-nethandler.obj: nethandler.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-nethandler.obj -MD -MP -MF $(DEPDIR)/pcem-nethandler.Tpo -c -o pcem-nethandler.obj `if test -f 'nethandler.c'; then $(CYGPATH_W) 'nethandler.c'; else $(CYGPATH_W) '$(srcdir)/nethandler.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-nethandler.Tpo $(DEPDIR)/pcem-nethandler.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nethandler.c' object='pcem-nethandler.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-nethandler.obj `if test -f 'nethandler.c'; then $(CYGPATH_W) 'nethandler.c'; else $(CYGPATH_W) '$(srcdir)/nethandler.c'; fi` + +pcem-wx-hostconfig.o: wx-hostconfig.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-hostconfig.o -MD -MP -MF $(DEPDIR)/pcem-wx-hostconfig.Tpo -c -o pcem-wx-hostconfig.o `test -f 'wx-hostconfig.c' || echo '$(srcdir)/'`wx-hostconfig.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-hostconfig.Tpo $(DEPDIR)/pcem-wx-hostconfig.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-hostconfig.c' object='pcem-wx-hostconfig.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-hostconfig.o `test -f 'wx-hostconfig.c' || echo '$(srcdir)/'`wx-hostconfig.c + +pcem-wx-hostconfig.obj: wx-hostconfig.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-hostconfig.obj -MD -MP -MF $(DEPDIR)/pcem-wx-hostconfig.Tpo -c -o pcem-wx-hostconfig.obj `if test -f 'wx-hostconfig.c'; then $(CYGPATH_W) 'wx-hostconfig.c'; else $(CYGPATH_W) '$(srcdir)/wx-hostconfig.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-hostconfig.Tpo $(DEPDIR)/pcem-wx-hostconfig.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-hostconfig.c' object='pcem-wx-hostconfig.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-hostconfig.obj `if test -f 'wx-hostconfig.c'; then $(CYGPATH_W) 'wx-hostconfig.c'; else $(CYGPATH_W) '$(srcdir)/wx-hostconfig.c'; fi` + +slirp/pcem-bootp.o: slirp/bootp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-bootp.o -MD -MP -MF slirp/$(DEPDIR)/pcem-bootp.Tpo -c -o slirp/pcem-bootp.o `test -f 'slirp/bootp.c' || echo '$(srcdir)/'`slirp/bootp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-bootp.Tpo slirp/$(DEPDIR)/pcem-bootp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/bootp.c' object='slirp/pcem-bootp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-bootp.o `test -f 'slirp/bootp.c' || echo '$(srcdir)/'`slirp/bootp.c + +slirp/pcem-bootp.obj: slirp/bootp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-bootp.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-bootp.Tpo -c -o slirp/pcem-bootp.obj `if test -f 'slirp/bootp.c'; then $(CYGPATH_W) 'slirp/bootp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/bootp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-bootp.Tpo slirp/$(DEPDIR)/pcem-bootp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/bootp.c' object='slirp/pcem-bootp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-bootp.obj `if test -f 'slirp/bootp.c'; then $(CYGPATH_W) 'slirp/bootp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/bootp.c'; fi` + +slirp/pcem-cksum.o: slirp/cksum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-cksum.o -MD -MP -MF slirp/$(DEPDIR)/pcem-cksum.Tpo -c -o slirp/pcem-cksum.o `test -f 'slirp/cksum.c' || echo '$(srcdir)/'`slirp/cksum.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-cksum.Tpo slirp/$(DEPDIR)/pcem-cksum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/cksum.c' object='slirp/pcem-cksum.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-cksum.o `test -f 'slirp/cksum.c' || echo '$(srcdir)/'`slirp/cksum.c + +slirp/pcem-cksum.obj: slirp/cksum.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-cksum.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-cksum.Tpo -c -o slirp/pcem-cksum.obj `if test -f 'slirp/cksum.c'; then $(CYGPATH_W) 'slirp/cksum.c'; else $(CYGPATH_W) '$(srcdir)/slirp/cksum.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-cksum.Tpo slirp/$(DEPDIR)/pcem-cksum.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/cksum.c' object='slirp/pcem-cksum.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-cksum.obj `if test -f 'slirp/cksum.c'; then $(CYGPATH_W) 'slirp/cksum.c'; else $(CYGPATH_W) '$(srcdir)/slirp/cksum.c'; fi` + +slirp/pcem-debug.o: slirp/debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-debug.o -MD -MP -MF slirp/$(DEPDIR)/pcem-debug.Tpo -c -o slirp/pcem-debug.o `test -f 'slirp/debug.c' || echo '$(srcdir)/'`slirp/debug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-debug.Tpo slirp/$(DEPDIR)/pcem-debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/debug.c' object='slirp/pcem-debug.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-debug.o `test -f 'slirp/debug.c' || echo '$(srcdir)/'`slirp/debug.c + +slirp/pcem-debug.obj: slirp/debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-debug.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-debug.Tpo -c -o slirp/pcem-debug.obj `if test -f 'slirp/debug.c'; then $(CYGPATH_W) 'slirp/debug.c'; else $(CYGPATH_W) '$(srcdir)/slirp/debug.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-debug.Tpo slirp/$(DEPDIR)/pcem-debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/debug.c' object='slirp/pcem-debug.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-debug.obj `if test -f 'slirp/debug.c'; then $(CYGPATH_W) 'slirp/debug.c'; else $(CYGPATH_W) '$(srcdir)/slirp/debug.c'; fi` + +slirp/pcem-if.o: slirp/if.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-if.o -MD -MP -MF slirp/$(DEPDIR)/pcem-if.Tpo -c -o slirp/pcem-if.o `test -f 'slirp/if.c' || echo '$(srcdir)/'`slirp/if.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-if.Tpo slirp/$(DEPDIR)/pcem-if.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/if.c' object='slirp/pcem-if.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-if.o `test -f 'slirp/if.c' || echo '$(srcdir)/'`slirp/if.c + +slirp/pcem-if.obj: slirp/if.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-if.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-if.Tpo -c -o slirp/pcem-if.obj `if test -f 'slirp/if.c'; then $(CYGPATH_W) 'slirp/if.c'; else $(CYGPATH_W) '$(srcdir)/slirp/if.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-if.Tpo slirp/$(DEPDIR)/pcem-if.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/if.c' object='slirp/pcem-if.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-if.obj `if test -f 'slirp/if.c'; then $(CYGPATH_W) 'slirp/if.c'; else $(CYGPATH_W) '$(srcdir)/slirp/if.c'; fi` + +slirp/pcem-ip_icmp.o: slirp/ip_icmp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-ip_icmp.o -MD -MP -MF slirp/$(DEPDIR)/pcem-ip_icmp.Tpo -c -o slirp/pcem-ip_icmp.o `test -f 'slirp/ip_icmp.c' || echo '$(srcdir)/'`slirp/ip_icmp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-ip_icmp.Tpo slirp/$(DEPDIR)/pcem-ip_icmp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/ip_icmp.c' object='slirp/pcem-ip_icmp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-ip_icmp.o `test -f 'slirp/ip_icmp.c' || echo '$(srcdir)/'`slirp/ip_icmp.c + +slirp/pcem-ip_icmp.obj: slirp/ip_icmp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-ip_icmp.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-ip_icmp.Tpo -c -o slirp/pcem-ip_icmp.obj `if test -f 'slirp/ip_icmp.c'; then $(CYGPATH_W) 'slirp/ip_icmp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/ip_icmp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-ip_icmp.Tpo slirp/$(DEPDIR)/pcem-ip_icmp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/ip_icmp.c' object='slirp/pcem-ip_icmp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-ip_icmp.obj `if test -f 'slirp/ip_icmp.c'; then $(CYGPATH_W) 'slirp/ip_icmp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/ip_icmp.c'; fi` + +slirp/pcem-ip_input.o: slirp/ip_input.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-ip_input.o -MD -MP -MF slirp/$(DEPDIR)/pcem-ip_input.Tpo -c -o slirp/pcem-ip_input.o `test -f 'slirp/ip_input.c' || echo '$(srcdir)/'`slirp/ip_input.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-ip_input.Tpo slirp/$(DEPDIR)/pcem-ip_input.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/ip_input.c' object='slirp/pcem-ip_input.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-ip_input.o `test -f 'slirp/ip_input.c' || echo '$(srcdir)/'`slirp/ip_input.c + +slirp/pcem-ip_input.obj: slirp/ip_input.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-ip_input.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-ip_input.Tpo -c -o slirp/pcem-ip_input.obj `if test -f 'slirp/ip_input.c'; then $(CYGPATH_W) 'slirp/ip_input.c'; else $(CYGPATH_W) '$(srcdir)/slirp/ip_input.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-ip_input.Tpo slirp/$(DEPDIR)/pcem-ip_input.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/ip_input.c' object='slirp/pcem-ip_input.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-ip_input.obj `if test -f 'slirp/ip_input.c'; then $(CYGPATH_W) 'slirp/ip_input.c'; else $(CYGPATH_W) '$(srcdir)/slirp/ip_input.c'; fi` + +slirp/pcem-ip_output.o: slirp/ip_output.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-ip_output.o -MD -MP -MF slirp/$(DEPDIR)/pcem-ip_output.Tpo -c -o slirp/pcem-ip_output.o `test -f 'slirp/ip_output.c' || echo '$(srcdir)/'`slirp/ip_output.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-ip_output.Tpo slirp/$(DEPDIR)/pcem-ip_output.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/ip_output.c' object='slirp/pcem-ip_output.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-ip_output.o `test -f 'slirp/ip_output.c' || echo '$(srcdir)/'`slirp/ip_output.c + +slirp/pcem-ip_output.obj: slirp/ip_output.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-ip_output.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-ip_output.Tpo -c -o slirp/pcem-ip_output.obj `if test -f 'slirp/ip_output.c'; then $(CYGPATH_W) 'slirp/ip_output.c'; else $(CYGPATH_W) '$(srcdir)/slirp/ip_output.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-ip_output.Tpo slirp/$(DEPDIR)/pcem-ip_output.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/ip_output.c' object='slirp/pcem-ip_output.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-ip_output.obj `if test -f 'slirp/ip_output.c'; then $(CYGPATH_W) 'slirp/ip_output.c'; else $(CYGPATH_W) '$(srcdir)/slirp/ip_output.c'; fi` + +slirp/pcem-mbuf.o: slirp/mbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-mbuf.o -MD -MP -MF slirp/$(DEPDIR)/pcem-mbuf.Tpo -c -o slirp/pcem-mbuf.o `test -f 'slirp/mbuf.c' || echo '$(srcdir)/'`slirp/mbuf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-mbuf.Tpo slirp/$(DEPDIR)/pcem-mbuf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/mbuf.c' object='slirp/pcem-mbuf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-mbuf.o `test -f 'slirp/mbuf.c' || echo '$(srcdir)/'`slirp/mbuf.c + +slirp/pcem-mbuf.obj: slirp/mbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-mbuf.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-mbuf.Tpo -c -o slirp/pcem-mbuf.obj `if test -f 'slirp/mbuf.c'; then $(CYGPATH_W) 'slirp/mbuf.c'; else $(CYGPATH_W) '$(srcdir)/slirp/mbuf.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-mbuf.Tpo slirp/$(DEPDIR)/pcem-mbuf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/mbuf.c' object='slirp/pcem-mbuf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-mbuf.obj `if test -f 'slirp/mbuf.c'; then $(CYGPATH_W) 'slirp/mbuf.c'; else $(CYGPATH_W) '$(srcdir)/slirp/mbuf.c'; fi` + +slirp/pcem-misc.o: slirp/misc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-misc.o -MD -MP -MF slirp/$(DEPDIR)/pcem-misc.Tpo -c -o slirp/pcem-misc.o `test -f 'slirp/misc.c' || echo '$(srcdir)/'`slirp/misc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-misc.Tpo slirp/$(DEPDIR)/pcem-misc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/misc.c' object='slirp/pcem-misc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-misc.o `test -f 'slirp/misc.c' || echo '$(srcdir)/'`slirp/misc.c + +slirp/pcem-misc.obj: slirp/misc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-misc.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-misc.Tpo -c -o slirp/pcem-misc.obj `if test -f 'slirp/misc.c'; then $(CYGPATH_W) 'slirp/misc.c'; else $(CYGPATH_W) '$(srcdir)/slirp/misc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-misc.Tpo slirp/$(DEPDIR)/pcem-misc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/misc.c' object='slirp/pcem-misc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-misc.obj `if test -f 'slirp/misc.c'; then $(CYGPATH_W) 'slirp/misc.c'; else $(CYGPATH_W) '$(srcdir)/slirp/misc.c'; fi` + +slirp/pcem-queue.o: slirp/queue.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-queue.o -MD -MP -MF slirp/$(DEPDIR)/pcem-queue.Tpo -c -o slirp/pcem-queue.o `test -f 'slirp/queue.c' || echo '$(srcdir)/'`slirp/queue.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-queue.Tpo slirp/$(DEPDIR)/pcem-queue.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/queue.c' object='slirp/pcem-queue.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-queue.o `test -f 'slirp/queue.c' || echo '$(srcdir)/'`slirp/queue.c + +slirp/pcem-queue.obj: slirp/queue.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-queue.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-queue.Tpo -c -o slirp/pcem-queue.obj `if test -f 'slirp/queue.c'; then $(CYGPATH_W) 'slirp/queue.c'; else $(CYGPATH_W) '$(srcdir)/slirp/queue.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-queue.Tpo slirp/$(DEPDIR)/pcem-queue.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/queue.c' object='slirp/pcem-queue.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-queue.obj `if test -f 'slirp/queue.c'; then $(CYGPATH_W) 'slirp/queue.c'; else $(CYGPATH_W) '$(srcdir)/slirp/queue.c'; fi` + +slirp/pcem-sbuf.o: slirp/sbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-sbuf.o -MD -MP -MF slirp/$(DEPDIR)/pcem-sbuf.Tpo -c -o slirp/pcem-sbuf.o `test -f 'slirp/sbuf.c' || echo '$(srcdir)/'`slirp/sbuf.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-sbuf.Tpo slirp/$(DEPDIR)/pcem-sbuf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/sbuf.c' object='slirp/pcem-sbuf.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-sbuf.o `test -f 'slirp/sbuf.c' || echo '$(srcdir)/'`slirp/sbuf.c + +slirp/pcem-sbuf.obj: slirp/sbuf.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-sbuf.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-sbuf.Tpo -c -o slirp/pcem-sbuf.obj `if test -f 'slirp/sbuf.c'; then $(CYGPATH_W) 'slirp/sbuf.c'; else $(CYGPATH_W) '$(srcdir)/slirp/sbuf.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-sbuf.Tpo slirp/$(DEPDIR)/pcem-sbuf.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/sbuf.c' object='slirp/pcem-sbuf.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-sbuf.obj `if test -f 'slirp/sbuf.c'; then $(CYGPATH_W) 'slirp/sbuf.c'; else $(CYGPATH_W) '$(srcdir)/slirp/sbuf.c'; fi` + +slirp/pcem-slirp.o: slirp/slirp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-slirp.o -MD -MP -MF slirp/$(DEPDIR)/pcem-slirp.Tpo -c -o slirp/pcem-slirp.o `test -f 'slirp/slirp.c' || echo '$(srcdir)/'`slirp/slirp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-slirp.Tpo slirp/$(DEPDIR)/pcem-slirp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/slirp.c' object='slirp/pcem-slirp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-slirp.o `test -f 'slirp/slirp.c' || echo '$(srcdir)/'`slirp/slirp.c + +slirp/pcem-slirp.obj: slirp/slirp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-slirp.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-slirp.Tpo -c -o slirp/pcem-slirp.obj `if test -f 'slirp/slirp.c'; then $(CYGPATH_W) 'slirp/slirp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/slirp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-slirp.Tpo slirp/$(DEPDIR)/pcem-slirp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/slirp.c' object='slirp/pcem-slirp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-slirp.obj `if test -f 'slirp/slirp.c'; then $(CYGPATH_W) 'slirp/slirp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/slirp.c'; fi` + +slirp/pcem-socket.o: slirp/socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-socket.o -MD -MP -MF slirp/$(DEPDIR)/pcem-socket.Tpo -c -o slirp/pcem-socket.o `test -f 'slirp/socket.c' || echo '$(srcdir)/'`slirp/socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-socket.Tpo slirp/$(DEPDIR)/pcem-socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/socket.c' object='slirp/pcem-socket.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-socket.o `test -f 'slirp/socket.c' || echo '$(srcdir)/'`slirp/socket.c + +slirp/pcem-socket.obj: slirp/socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-socket.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-socket.Tpo -c -o slirp/pcem-socket.obj `if test -f 'slirp/socket.c'; then $(CYGPATH_W) 'slirp/socket.c'; else $(CYGPATH_W) '$(srcdir)/slirp/socket.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-socket.Tpo slirp/$(DEPDIR)/pcem-socket.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/socket.c' object='slirp/pcem-socket.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-socket.obj `if test -f 'slirp/socket.c'; then $(CYGPATH_W) 'slirp/socket.c'; else $(CYGPATH_W) '$(srcdir)/slirp/socket.c'; fi` + +slirp/pcem-tcp_input.o: slirp/tcp_input.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tcp_input.o -MD -MP -MF slirp/$(DEPDIR)/pcem-tcp_input.Tpo -c -o slirp/pcem-tcp_input.o `test -f 'slirp/tcp_input.c' || echo '$(srcdir)/'`slirp/tcp_input.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tcp_input.Tpo slirp/$(DEPDIR)/pcem-tcp_input.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tcp_input.c' object='slirp/pcem-tcp_input.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tcp_input.o `test -f 'slirp/tcp_input.c' || echo '$(srcdir)/'`slirp/tcp_input.c + +slirp/pcem-tcp_input.obj: slirp/tcp_input.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tcp_input.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-tcp_input.Tpo -c -o slirp/pcem-tcp_input.obj `if test -f 'slirp/tcp_input.c'; then $(CYGPATH_W) 'slirp/tcp_input.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tcp_input.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tcp_input.Tpo slirp/$(DEPDIR)/pcem-tcp_input.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tcp_input.c' object='slirp/pcem-tcp_input.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tcp_input.obj `if test -f 'slirp/tcp_input.c'; then $(CYGPATH_W) 'slirp/tcp_input.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tcp_input.c'; fi` + +slirp/pcem-tcp_output.o: slirp/tcp_output.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tcp_output.o -MD -MP -MF slirp/$(DEPDIR)/pcem-tcp_output.Tpo -c -o slirp/pcem-tcp_output.o `test -f 'slirp/tcp_output.c' || echo '$(srcdir)/'`slirp/tcp_output.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tcp_output.Tpo slirp/$(DEPDIR)/pcem-tcp_output.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tcp_output.c' object='slirp/pcem-tcp_output.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tcp_output.o `test -f 'slirp/tcp_output.c' || echo '$(srcdir)/'`slirp/tcp_output.c + +slirp/pcem-tcp_output.obj: slirp/tcp_output.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tcp_output.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-tcp_output.Tpo -c -o slirp/pcem-tcp_output.obj `if test -f 'slirp/tcp_output.c'; then $(CYGPATH_W) 'slirp/tcp_output.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tcp_output.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tcp_output.Tpo slirp/$(DEPDIR)/pcem-tcp_output.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tcp_output.c' object='slirp/pcem-tcp_output.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tcp_output.obj `if test -f 'slirp/tcp_output.c'; then $(CYGPATH_W) 'slirp/tcp_output.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tcp_output.c'; fi` + +slirp/pcem-tcp_subr.o: slirp/tcp_subr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tcp_subr.o -MD -MP -MF slirp/$(DEPDIR)/pcem-tcp_subr.Tpo -c -o slirp/pcem-tcp_subr.o `test -f 'slirp/tcp_subr.c' || echo '$(srcdir)/'`slirp/tcp_subr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tcp_subr.Tpo slirp/$(DEPDIR)/pcem-tcp_subr.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tcp_subr.c' object='slirp/pcem-tcp_subr.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tcp_subr.o `test -f 'slirp/tcp_subr.c' || echo '$(srcdir)/'`slirp/tcp_subr.c + +slirp/pcem-tcp_subr.obj: slirp/tcp_subr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tcp_subr.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-tcp_subr.Tpo -c -o slirp/pcem-tcp_subr.obj `if test -f 'slirp/tcp_subr.c'; then $(CYGPATH_W) 'slirp/tcp_subr.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tcp_subr.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tcp_subr.Tpo slirp/$(DEPDIR)/pcem-tcp_subr.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tcp_subr.c' object='slirp/pcem-tcp_subr.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tcp_subr.obj `if test -f 'slirp/tcp_subr.c'; then $(CYGPATH_W) 'slirp/tcp_subr.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tcp_subr.c'; fi` + +slirp/pcem-tcp_timer.o: slirp/tcp_timer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tcp_timer.o -MD -MP -MF slirp/$(DEPDIR)/pcem-tcp_timer.Tpo -c -o slirp/pcem-tcp_timer.o `test -f 'slirp/tcp_timer.c' || echo '$(srcdir)/'`slirp/tcp_timer.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tcp_timer.Tpo slirp/$(DEPDIR)/pcem-tcp_timer.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tcp_timer.c' object='slirp/pcem-tcp_timer.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tcp_timer.o `test -f 'slirp/tcp_timer.c' || echo '$(srcdir)/'`slirp/tcp_timer.c + +slirp/pcem-tcp_timer.obj: slirp/tcp_timer.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tcp_timer.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-tcp_timer.Tpo -c -o slirp/pcem-tcp_timer.obj `if test -f 'slirp/tcp_timer.c'; then $(CYGPATH_W) 'slirp/tcp_timer.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tcp_timer.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tcp_timer.Tpo slirp/$(DEPDIR)/pcem-tcp_timer.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tcp_timer.c' object='slirp/pcem-tcp_timer.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tcp_timer.obj `if test -f 'slirp/tcp_timer.c'; then $(CYGPATH_W) 'slirp/tcp_timer.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tcp_timer.c'; fi` + +slirp/pcem-tftp.o: slirp/tftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tftp.o -MD -MP -MF slirp/$(DEPDIR)/pcem-tftp.Tpo -c -o slirp/pcem-tftp.o `test -f 'slirp/tftp.c' || echo '$(srcdir)/'`slirp/tftp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tftp.Tpo slirp/$(DEPDIR)/pcem-tftp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tftp.c' object='slirp/pcem-tftp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tftp.o `test -f 'slirp/tftp.c' || echo '$(srcdir)/'`slirp/tftp.c + +slirp/pcem-tftp.obj: slirp/tftp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-tftp.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-tftp.Tpo -c -o slirp/pcem-tftp.obj `if test -f 'slirp/tftp.c'; then $(CYGPATH_W) 'slirp/tftp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tftp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-tftp.Tpo slirp/$(DEPDIR)/pcem-tftp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/tftp.c' object='slirp/pcem-tftp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-tftp.obj `if test -f 'slirp/tftp.c'; then $(CYGPATH_W) 'slirp/tftp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/tftp.c'; fi` + +slirp/pcem-udp.o: slirp/udp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-udp.o -MD -MP -MF slirp/$(DEPDIR)/pcem-udp.Tpo -c -o slirp/pcem-udp.o `test -f 'slirp/udp.c' || echo '$(srcdir)/'`slirp/udp.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-udp.Tpo slirp/$(DEPDIR)/pcem-udp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/udp.c' object='slirp/pcem-udp.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-udp.o `test -f 'slirp/udp.c' || echo '$(srcdir)/'`slirp/udp.c + +slirp/pcem-udp.obj: slirp/udp.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT slirp/pcem-udp.obj -MD -MP -MF slirp/$(DEPDIR)/pcem-udp.Tpo -c -o slirp/pcem-udp.obj `if test -f 'slirp/udp.c'; then $(CYGPATH_W) 'slirp/udp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/udp.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) slirp/$(DEPDIR)/pcem-udp.Tpo slirp/$(DEPDIR)/pcem-udp.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='slirp/udp.c' object='slirp/pcem-udp.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o slirp/pcem-udp.obj `if test -f 'slirp/udp.c'; then $(CYGPATH_W) 'slirp/udp.c'; else $(CYGPATH_W) '$(srcdir)/slirp/udp.c'; fi` + +pcem-cdrom-ioctl-linux.o: cdrom-ioctl-linux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-linux.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo -c -o pcem-cdrom-ioctl-linux.o `test -f 'cdrom-ioctl-linux.c' || echo '$(srcdir)/'`cdrom-ioctl-linux.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo $(DEPDIR)/pcem-cdrom-ioctl-linux.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl-linux.c' object='pcem-cdrom-ioctl-linux.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-linux.o `test -f 'cdrom-ioctl-linux.c' || echo '$(srcdir)/'`cdrom-ioctl-linux.c + +pcem-cdrom-ioctl-linux.obj: cdrom-ioctl-linux.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-linux.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo -c -o pcem-cdrom-ioctl-linux.obj `if test -f 'cdrom-ioctl-linux.c'; then $(CYGPATH_W) 'cdrom-ioctl-linux.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-linux.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-linux.Tpo $(DEPDIR)/pcem-cdrom-ioctl-linux.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl-linux.c' object='pcem-cdrom-ioctl-linux.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-linux.obj `if test -f 'cdrom-ioctl-linux.c'; then $(CYGPATH_W) 'cdrom-ioctl-linux.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-linux.c'; fi` + +pcem-wx-sdl2-display.o: wx-sdl2-display.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-display.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-display.Tpo -c -o pcem-wx-sdl2-display.o `test -f 'wx-sdl2-display.c' || echo '$(srcdir)/'`wx-sdl2-display.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-display.Tpo $(DEPDIR)/pcem-wx-sdl2-display.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-display.c' object='pcem-wx-sdl2-display.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-display.o `test -f 'wx-sdl2-display.c' || echo '$(srcdir)/'`wx-sdl2-display.c + +pcem-wx-sdl2-display.obj: wx-sdl2-display.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-display.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-display.Tpo -c -o pcem-wx-sdl2-display.obj `if test -f 'wx-sdl2-display.c'; then $(CYGPATH_W) 'wx-sdl2-display.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-display.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-display.Tpo $(DEPDIR)/pcem-wx-sdl2-display.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-display.c' object='pcem-wx-sdl2-display.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-display.obj `if test -f 'wx-sdl2-display.c'; then $(CYGPATH_W) 'wx-sdl2-display.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-display.c'; fi` + +pcem-cdrom-ioctl-dummy.o: cdrom-ioctl-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-dummy.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-dummy.Tpo -c -o pcem-cdrom-ioctl-dummy.o `test -f 'cdrom-ioctl-dummy.c' || echo '$(srcdir)/'`cdrom-ioctl-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-dummy.Tpo $(DEPDIR)/pcem-cdrom-ioctl-dummy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl-dummy.c' object='pcem-cdrom-ioctl-dummy.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-dummy.o `test -f 'cdrom-ioctl-dummy.c' || echo '$(srcdir)/'`cdrom-ioctl-dummy.c + +pcem-cdrom-ioctl-dummy.obj: cdrom-ioctl-dummy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-dummy.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-dummy.Tpo -c -o pcem-cdrom-ioctl-dummy.obj `if test -f 'cdrom-ioctl-dummy.c'; then $(CYGPATH_W) 'cdrom-ioctl-dummy.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-dummy.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-dummy.Tpo $(DEPDIR)/pcem-cdrom-ioctl-dummy.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl-dummy.c' object='pcem-cdrom-ioctl-dummy.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-dummy.obj `if test -f 'cdrom-ioctl-dummy.c'; then $(CYGPATH_W) 'cdrom-ioctl-dummy.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-dummy.c'; fi` + +pcem-cdrom-ioctl-osx.o: cdrom-ioctl-osx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-osx.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-osx.Tpo -c -o pcem-cdrom-ioctl-osx.o `test -f 'cdrom-ioctl-osx.c' || echo '$(srcdir)/'`cdrom-ioctl-osx.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-osx.Tpo $(DEPDIR)/pcem-cdrom-ioctl-osx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl-osx.c' object='pcem-cdrom-ioctl-osx.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-osx.o `test -f 'cdrom-ioctl-osx.c' || echo '$(srcdir)/'`cdrom-ioctl-osx.c + +pcem-cdrom-ioctl-osx.obj: cdrom-ioctl-osx.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl-osx.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl-osx.Tpo -c -o pcem-cdrom-ioctl-osx.obj `if test -f 'cdrom-ioctl-osx.c'; then $(CYGPATH_W) 'cdrom-ioctl-osx.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-osx.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl-osx.Tpo $(DEPDIR)/pcem-cdrom-ioctl-osx.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl-osx.c' object='pcem-cdrom-ioctl-osx.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl-osx.obj `if test -f 'cdrom-ioctl-osx.c'; then $(CYGPATH_W) 'cdrom-ioctl-osx.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl-osx.c'; fi` + +pcem-cdrom-ioctl.o: cdrom-ioctl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl.Tpo -c -o pcem-cdrom-ioctl.o `test -f 'cdrom-ioctl.c' || echo '$(srcdir)/'`cdrom-ioctl.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl.Tpo $(DEPDIR)/pcem-cdrom-ioctl.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl.c' object='pcem-cdrom-ioctl.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl.o `test -f 'cdrom-ioctl.c' || echo '$(srcdir)/'`cdrom-ioctl.c + +pcem-cdrom-ioctl.obj: cdrom-ioctl.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-cdrom-ioctl.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-ioctl.Tpo -c -o pcem-cdrom-ioctl.obj `if test -f 'cdrom-ioctl.c'; then $(CYGPATH_W) 'cdrom-ioctl.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-ioctl.Tpo $(DEPDIR)/pcem-cdrom-ioctl.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cdrom-ioctl.c' object='pcem-cdrom-ioctl.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-cdrom-ioctl.obj `if test -f 'cdrom-ioctl.c'; then $(CYGPATH_W) 'cdrom-ioctl.c'; else $(CYGPATH_W) '$(srcdir)/cdrom-ioctl.c'; fi` + +pcem-wx-sdl2-display-win.o: wx-sdl2-display-win.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-display-win.o -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-display-win.Tpo -c -o pcem-wx-sdl2-display-win.o `test -f 'wx-sdl2-display-win.c' || echo '$(srcdir)/'`wx-sdl2-display-win.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-display-win.Tpo $(DEPDIR)/pcem-wx-sdl2-display-win.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-display-win.c' object='pcem-wx-sdl2-display-win.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-display-win.o `test -f 'wx-sdl2-display-win.c' || echo '$(srcdir)/'`wx-sdl2-display-win.c + +pcem-wx-sdl2-display-win.obj: wx-sdl2-display-win.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -MT pcem-wx-sdl2-display-win.obj -MD -MP -MF $(DEPDIR)/pcem-wx-sdl2-display-win.Tpo -c -o pcem-wx-sdl2-display-win.obj `if test -f 'wx-sdl2-display-win.c'; then $(CYGPATH_W) 'wx-sdl2-display-win.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-display-win.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-sdl2-display-win.Tpo $(DEPDIR)/pcem-wx-sdl2-display-win.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wx-sdl2-display-win.c' object='pcem-wx-sdl2-display-win.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CFLAGS) $(CFLAGS) -c -o pcem-wx-sdl2-display-win.obj `if test -f 'wx-sdl2-display-win.c'; then $(CYGPATH_W) 'wx-sdl2-display-win.c'; else $(CYGPATH_W) '$(srcdir)/wx-sdl2-display-win.c'; fi` .cc.o: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cc.obj: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` -dbopl.o: dosbox/dbopl.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dbopl.o -MD -MP -MF $(DEPDIR)/dbopl.Tpo -c -o dbopl.o `test -f 'dosbox/dbopl.cpp' || echo '$(srcdir)/'`dosbox/dbopl.cpp -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbopl.Tpo $(DEPDIR)/dbopl.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dosbox/dbopl.cpp' object='dbopl.o' libtool=no @AMDEPBACKSLASH@ +pcem-cdrom-image.o: cdrom-image.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-cdrom-image.o -MD -MP -MF $(DEPDIR)/pcem-cdrom-image.Tpo -c -o pcem-cdrom-image.o `test -f 'cdrom-image.cc' || echo '$(srcdir)/'`cdrom-image.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-image.Tpo $(DEPDIR)/pcem-cdrom-image.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdrom-image.cc' object='pcem-cdrom-image.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dbopl.o `test -f 'dosbox/dbopl.cpp' || echo '$(srcdir)/'`dosbox/dbopl.cpp +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-cdrom-image.o `test -f 'cdrom-image.cc' || echo '$(srcdir)/'`cdrom-image.cc -dbopl.obj: dosbox/dbopl.cpp -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT dbopl.obj -MD -MP -MF $(DEPDIR)/dbopl.Tpo -c -o dbopl.obj `if test -f 'dosbox/dbopl.cpp'; then $(CYGPATH_W) 'dosbox/dbopl.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/dbopl.cpp'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/dbopl.Tpo $(DEPDIR)/dbopl.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dosbox/dbopl.cpp' object='dbopl.obj' libtool=no @AMDEPBACKSLASH@ +pcem-cdrom-image.obj: cdrom-image.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-cdrom-image.obj -MD -MP -MF $(DEPDIR)/pcem-cdrom-image.Tpo -c -o pcem-cdrom-image.obj `if test -f 'cdrom-image.cc'; then $(CYGPATH_W) 'cdrom-image.cc'; else $(CYGPATH_W) '$(srcdir)/cdrom-image.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-cdrom-image.Tpo $(DEPDIR)/pcem-cdrom-image.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='cdrom-image.cc' object='pcem-cdrom-image.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o dbopl.obj `if test -f 'dosbox/dbopl.cpp'; then $(CYGPATH_W) 'dosbox/dbopl.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/dbopl.cpp'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-cdrom-image.obj `if test -f 'cdrom-image.cc'; then $(CYGPATH_W) 'cdrom-image.cc'; else $(CYGPATH_W) '$(srcdir)/cdrom-image.cc'; fi` -convolve.o: resid-fp/convolve.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT convolve.o -MD -MP -MF $(DEPDIR)/convolve.Tpo -c -o convolve.o `test -f 'resid-fp/convolve.cc' || echo '$(srcdir)/'`resid-fp/convolve.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/convolve.Tpo $(DEPDIR)/convolve.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/convolve.cc' object='convolve.o' libtool=no @AMDEPBACKSLASH@ +pcem-sound_dbopl.o: sound_dbopl.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-sound_dbopl.o -MD -MP -MF $(DEPDIR)/pcem-sound_dbopl.Tpo -c -o pcem-sound_dbopl.o `test -f 'sound_dbopl.cc' || echo '$(srcdir)/'`sound_dbopl.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_dbopl.Tpo $(DEPDIR)/pcem-sound_dbopl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sound_dbopl.cc' object='pcem-sound_dbopl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o convolve.o `test -f 'resid-fp/convolve.cc' || echo '$(srcdir)/'`resid-fp/convolve.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-sound_dbopl.o `test -f 'sound_dbopl.cc' || echo '$(srcdir)/'`sound_dbopl.cc -convolve.obj: resid-fp/convolve.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT convolve.obj -MD -MP -MF $(DEPDIR)/convolve.Tpo -c -o convolve.obj `if test -f 'resid-fp/convolve.cc'; then $(CYGPATH_W) 'resid-fp/convolve.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/convolve.Tpo $(DEPDIR)/convolve.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/convolve.cc' object='convolve.obj' libtool=no @AMDEPBACKSLASH@ +pcem-sound_dbopl.obj: sound_dbopl.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-sound_dbopl.obj -MD -MP -MF $(DEPDIR)/pcem-sound_dbopl.Tpo -c -o pcem-sound_dbopl.obj `if test -f 'sound_dbopl.cc'; then $(CYGPATH_W) 'sound_dbopl.cc'; else $(CYGPATH_W) '$(srcdir)/sound_dbopl.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_dbopl.Tpo $(DEPDIR)/pcem-sound_dbopl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sound_dbopl.cc' object='pcem-sound_dbopl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o convolve.obj `if test -f 'resid-fp/convolve.cc'; then $(CYGPATH_W) 'resid-fp/convolve.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-sound_dbopl.obj `if test -f 'sound_dbopl.cc'; then $(CYGPATH_W) 'sound_dbopl.cc'; else $(CYGPATH_W) '$(srcdir)/sound_dbopl.cc'; fi` -convolve-sse.o: resid-fp/convolve-sse.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT convolve-sse.o -MD -MP -MF $(DEPDIR)/convolve-sse.Tpo -c -o convolve-sse.o `test -f 'resid-fp/convolve-sse.cc' || echo '$(srcdir)/'`resid-fp/convolve-sse.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/convolve-sse.Tpo $(DEPDIR)/convolve-sse.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/convolve-sse.cc' object='convolve-sse.o' libtool=no @AMDEPBACKSLASH@ +pcem-sound_resid.o: sound_resid.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-sound_resid.o -MD -MP -MF $(DEPDIR)/pcem-sound_resid.Tpo -c -o pcem-sound_resid.o `test -f 'sound_resid.cc' || echo '$(srcdir)/'`sound_resid.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_resid.Tpo $(DEPDIR)/pcem-sound_resid.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sound_resid.cc' object='pcem-sound_resid.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o convolve-sse.o `test -f 'resid-fp/convolve-sse.cc' || echo '$(srcdir)/'`resid-fp/convolve-sse.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-sound_resid.o `test -f 'sound_resid.cc' || echo '$(srcdir)/'`sound_resid.cc -convolve-sse.obj: resid-fp/convolve-sse.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT convolve-sse.obj -MD -MP -MF $(DEPDIR)/convolve-sse.Tpo -c -o convolve-sse.obj `if test -f 'resid-fp/convolve-sse.cc'; then $(CYGPATH_W) 'resid-fp/convolve-sse.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve-sse.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/convolve-sse.Tpo $(DEPDIR)/convolve-sse.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/convolve-sse.cc' object='convolve-sse.obj' libtool=no @AMDEPBACKSLASH@ +pcem-sound_resid.obj: sound_resid.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-sound_resid.obj -MD -MP -MF $(DEPDIR)/pcem-sound_resid.Tpo -c -o pcem-sound_resid.obj `if test -f 'sound_resid.cc'; then $(CYGPATH_W) 'sound_resid.cc'; else $(CYGPATH_W) '$(srcdir)/sound_resid.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-sound_resid.Tpo $(DEPDIR)/pcem-sound_resid.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='sound_resid.cc' object='pcem-sound_resid.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o convolve-sse.obj `if test -f 'resid-fp/convolve-sse.cc'; then $(CYGPATH_W) 'resid-fp/convolve-sse.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve-sse.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-sound_resid.obj `if test -f 'sound_resid.cc'; then $(CYGPATH_W) 'sound_resid.cc'; else $(CYGPATH_W) '$(srcdir)/sound_resid.cc'; fi` -envelope.o: resid-fp/envelope.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT envelope.o -MD -MP -MF $(DEPDIR)/envelope.Tpo -c -o envelope.o `test -f 'resid-fp/envelope.cc' || echo '$(srcdir)/'`resid-fp/envelope.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/envelope.Tpo $(DEPDIR)/envelope.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/envelope.cc' object='envelope.o' libtool=no @AMDEPBACKSLASH@ +dosbox/pcem-cdrom_image.o: dosbox/cdrom_image.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT dosbox/pcem-cdrom_image.o -MD -MP -MF dosbox/$(DEPDIR)/pcem-cdrom_image.Tpo -c -o dosbox/pcem-cdrom_image.o `test -f 'dosbox/cdrom_image.cpp' || echo '$(srcdir)/'`dosbox/cdrom_image.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) dosbox/$(DEPDIR)/pcem-cdrom_image.Tpo dosbox/$(DEPDIR)/pcem-cdrom_image.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dosbox/cdrom_image.cpp' object='dosbox/pcem-cdrom_image.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o envelope.o `test -f 'resid-fp/envelope.cc' || echo '$(srcdir)/'`resid-fp/envelope.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o dosbox/pcem-cdrom_image.o `test -f 'dosbox/cdrom_image.cpp' || echo '$(srcdir)/'`dosbox/cdrom_image.cpp -envelope.obj: resid-fp/envelope.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT envelope.obj -MD -MP -MF $(DEPDIR)/envelope.Tpo -c -o envelope.obj `if test -f 'resid-fp/envelope.cc'; then $(CYGPATH_W) 'resid-fp/envelope.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/envelope.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/envelope.Tpo $(DEPDIR)/envelope.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/envelope.cc' object='envelope.obj' libtool=no @AMDEPBACKSLASH@ +dosbox/pcem-cdrom_image.obj: dosbox/cdrom_image.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT dosbox/pcem-cdrom_image.obj -MD -MP -MF dosbox/$(DEPDIR)/pcem-cdrom_image.Tpo -c -o dosbox/pcem-cdrom_image.obj `if test -f 'dosbox/cdrom_image.cpp'; then $(CYGPATH_W) 'dosbox/cdrom_image.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/cdrom_image.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) dosbox/$(DEPDIR)/pcem-cdrom_image.Tpo dosbox/$(DEPDIR)/pcem-cdrom_image.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dosbox/cdrom_image.cpp' object='dosbox/pcem-cdrom_image.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o envelope.obj `if test -f 'resid-fp/envelope.cc'; then $(CYGPATH_W) 'resid-fp/envelope.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/envelope.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o dosbox/pcem-cdrom_image.obj `if test -f 'dosbox/cdrom_image.cpp'; then $(CYGPATH_W) 'dosbox/cdrom_image.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/cdrom_image.cpp'; fi` -extfilt.o: resid-fp/extfilt.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT extfilt.o -MD -MP -MF $(DEPDIR)/extfilt.Tpo -c -o extfilt.o `test -f 'resid-fp/extfilt.cc' || echo '$(srcdir)/'`resid-fp/extfilt.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/extfilt.Tpo $(DEPDIR)/extfilt.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/extfilt.cc' object='extfilt.o' libtool=no @AMDEPBACKSLASH@ +dosbox/pcem-dbopl.o: dosbox/dbopl.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT dosbox/pcem-dbopl.o -MD -MP -MF dosbox/$(DEPDIR)/pcem-dbopl.Tpo -c -o dosbox/pcem-dbopl.o `test -f 'dosbox/dbopl.cpp' || echo '$(srcdir)/'`dosbox/dbopl.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) dosbox/$(DEPDIR)/pcem-dbopl.Tpo dosbox/$(DEPDIR)/pcem-dbopl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dosbox/dbopl.cpp' object='dosbox/pcem-dbopl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o extfilt.o `test -f 'resid-fp/extfilt.cc' || echo '$(srcdir)/'`resid-fp/extfilt.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o dosbox/pcem-dbopl.o `test -f 'dosbox/dbopl.cpp' || echo '$(srcdir)/'`dosbox/dbopl.cpp -extfilt.obj: resid-fp/extfilt.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT extfilt.obj -MD -MP -MF $(DEPDIR)/extfilt.Tpo -c -o extfilt.obj `if test -f 'resid-fp/extfilt.cc'; then $(CYGPATH_W) 'resid-fp/extfilt.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/extfilt.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/extfilt.Tpo $(DEPDIR)/extfilt.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/extfilt.cc' object='extfilt.obj' libtool=no @AMDEPBACKSLASH@ +dosbox/pcem-dbopl.obj: dosbox/dbopl.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT dosbox/pcem-dbopl.obj -MD -MP -MF dosbox/$(DEPDIR)/pcem-dbopl.Tpo -c -o dosbox/pcem-dbopl.obj `if test -f 'dosbox/dbopl.cpp'; then $(CYGPATH_W) 'dosbox/dbopl.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/dbopl.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) dosbox/$(DEPDIR)/pcem-dbopl.Tpo dosbox/$(DEPDIR)/pcem-dbopl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dosbox/dbopl.cpp' object='dosbox/pcem-dbopl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o extfilt.obj `if test -f 'resid-fp/extfilt.cc'; then $(CYGPATH_W) 'resid-fp/extfilt.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/extfilt.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o dosbox/pcem-dbopl.obj `if test -f 'dosbox/dbopl.cpp'; then $(CYGPATH_W) 'dosbox/dbopl.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/dbopl.cpp'; fi` -filter.o: resid-fp/filter.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filter.o -MD -MP -MF $(DEPDIR)/filter.Tpo -c -o filter.o `test -f 'resid-fp/filter.cc' || echo '$(srcdir)/'`resid-fp/filter.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/filter.Tpo $(DEPDIR)/filter.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/filter.cc' object='filter.o' libtool=no @AMDEPBACKSLASH@ +dosbox/pcem-nukedopl.o: dosbox/nukedopl.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT dosbox/pcem-nukedopl.o -MD -MP -MF dosbox/$(DEPDIR)/pcem-nukedopl.Tpo -c -o dosbox/pcem-nukedopl.o `test -f 'dosbox/nukedopl.cpp' || echo '$(srcdir)/'`dosbox/nukedopl.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) dosbox/$(DEPDIR)/pcem-nukedopl.Tpo dosbox/$(DEPDIR)/pcem-nukedopl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dosbox/nukedopl.cpp' object='dosbox/pcem-nukedopl.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filter.o `test -f 'resid-fp/filter.cc' || echo '$(srcdir)/'`resid-fp/filter.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o dosbox/pcem-nukedopl.o `test -f 'dosbox/nukedopl.cpp' || echo '$(srcdir)/'`dosbox/nukedopl.cpp -filter.obj: resid-fp/filter.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT filter.obj -MD -MP -MF $(DEPDIR)/filter.Tpo -c -o filter.obj `if test -f 'resid-fp/filter.cc'; then $(CYGPATH_W) 'resid-fp/filter.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/filter.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/filter.Tpo $(DEPDIR)/filter.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/filter.cc' object='filter.obj' libtool=no @AMDEPBACKSLASH@ +dosbox/pcem-nukedopl.obj: dosbox/nukedopl.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT dosbox/pcem-nukedopl.obj -MD -MP -MF dosbox/$(DEPDIR)/pcem-nukedopl.Tpo -c -o dosbox/pcem-nukedopl.obj `if test -f 'dosbox/nukedopl.cpp'; then $(CYGPATH_W) 'dosbox/nukedopl.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/nukedopl.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) dosbox/$(DEPDIR)/pcem-nukedopl.Tpo dosbox/$(DEPDIR)/pcem-nukedopl.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='dosbox/nukedopl.cpp' object='dosbox/pcem-nukedopl.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o filter.obj `if test -f 'resid-fp/filter.cc'; then $(CYGPATH_W) 'resid-fp/filter.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/filter.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o dosbox/pcem-nukedopl.obj `if test -f 'dosbox/nukedopl.cpp'; then $(CYGPATH_W) 'dosbox/nukedopl.cpp'; else $(CYGPATH_W) '$(srcdir)/dosbox/nukedopl.cpp'; fi` -pot.o: resid-fp/pot.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pot.o -MD -MP -MF $(DEPDIR)/pot.Tpo -c -o pot.o `test -f 'resid-fp/pot.cc' || echo '$(srcdir)/'`resid-fp/pot.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pot.Tpo $(DEPDIR)/pot.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/pot.cc' object='pot.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-convolve.o: resid-fp/convolve.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-convolve.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-convolve.Tpo -c -o resid-fp/pcem-convolve.o `test -f 'resid-fp/convolve.cc' || echo '$(srcdir)/'`resid-fp/convolve.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-convolve.Tpo resid-fp/$(DEPDIR)/pcem-convolve.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/convolve.cc' object='resid-fp/pcem-convolve.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pot.o `test -f 'resid-fp/pot.cc' || echo '$(srcdir)/'`resid-fp/pot.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-convolve.o `test -f 'resid-fp/convolve.cc' || echo '$(srcdir)/'`resid-fp/convolve.cc -pot.obj: resid-fp/pot.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT pot.obj -MD -MP -MF $(DEPDIR)/pot.Tpo -c -o pot.obj `if test -f 'resid-fp/pot.cc'; then $(CYGPATH_W) 'resid-fp/pot.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/pot.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pot.Tpo $(DEPDIR)/pot.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/pot.cc' object='pot.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-convolve.obj: resid-fp/convolve.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-convolve.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-convolve.Tpo -c -o resid-fp/pcem-convolve.obj `if test -f 'resid-fp/convolve.cc'; then $(CYGPATH_W) 'resid-fp/convolve.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-convolve.Tpo resid-fp/$(DEPDIR)/pcem-convolve.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/convolve.cc' object='resid-fp/pcem-convolve.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o pot.obj `if test -f 'resid-fp/pot.cc'; then $(CYGPATH_W) 'resid-fp/pot.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/pot.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-convolve.obj `if test -f 'resid-fp/convolve.cc'; then $(CYGPATH_W) 'resid-fp/convolve.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve.cc'; fi` -sid.o: resid-fp/sid.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sid.o -MD -MP -MF $(DEPDIR)/sid.Tpo -c -o sid.o `test -f 'resid-fp/sid.cc' || echo '$(srcdir)/'`resid-fp/sid.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sid.Tpo $(DEPDIR)/sid.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/sid.cc' object='sid.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-convolve-sse.o: resid-fp/convolve-sse.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-convolve-sse.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-convolve-sse.Tpo -c -o resid-fp/pcem-convolve-sse.o `test -f 'resid-fp/convolve-sse.cc' || echo '$(srcdir)/'`resid-fp/convolve-sse.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-convolve-sse.Tpo resid-fp/$(DEPDIR)/pcem-convolve-sse.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/convolve-sse.cc' object='resid-fp/pcem-convolve-sse.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sid.o `test -f 'resid-fp/sid.cc' || echo '$(srcdir)/'`resid-fp/sid.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-convolve-sse.o `test -f 'resid-fp/convolve-sse.cc' || echo '$(srcdir)/'`resid-fp/convolve-sse.cc -sid.obj: resid-fp/sid.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT sid.obj -MD -MP -MF $(DEPDIR)/sid.Tpo -c -o sid.obj `if test -f 'resid-fp/sid.cc'; then $(CYGPATH_W) 'resid-fp/sid.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/sid.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/sid.Tpo $(DEPDIR)/sid.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/sid.cc' object='sid.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-convolve-sse.obj: resid-fp/convolve-sse.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-convolve-sse.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-convolve-sse.Tpo -c -o resid-fp/pcem-convolve-sse.obj `if test -f 'resid-fp/convolve-sse.cc'; then $(CYGPATH_W) 'resid-fp/convolve-sse.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve-sse.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-convolve-sse.Tpo resid-fp/$(DEPDIR)/pcem-convolve-sse.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/convolve-sse.cc' object='resid-fp/pcem-convolve-sse.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o sid.obj `if test -f 'resid-fp/sid.cc'; then $(CYGPATH_W) 'resid-fp/sid.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/sid.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-convolve-sse.obj `if test -f 'resid-fp/convolve-sse.cc'; then $(CYGPATH_W) 'resid-fp/convolve-sse.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/convolve-sse.cc'; fi` -voice.o: resid-fp/voice.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT voice.o -MD -MP -MF $(DEPDIR)/voice.Tpo -c -o voice.o `test -f 'resid-fp/voice.cc' || echo '$(srcdir)/'`resid-fp/voice.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/voice.Tpo $(DEPDIR)/voice.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/voice.cc' object='voice.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-envelope.o: resid-fp/envelope.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-envelope.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-envelope.Tpo -c -o resid-fp/pcem-envelope.o `test -f 'resid-fp/envelope.cc' || echo '$(srcdir)/'`resid-fp/envelope.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-envelope.Tpo resid-fp/$(DEPDIR)/pcem-envelope.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/envelope.cc' object='resid-fp/pcem-envelope.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o voice.o `test -f 'resid-fp/voice.cc' || echo '$(srcdir)/'`resid-fp/voice.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-envelope.o `test -f 'resid-fp/envelope.cc' || echo '$(srcdir)/'`resid-fp/envelope.cc -voice.obj: resid-fp/voice.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT voice.obj -MD -MP -MF $(DEPDIR)/voice.Tpo -c -o voice.obj `if test -f 'resid-fp/voice.cc'; then $(CYGPATH_W) 'resid-fp/voice.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/voice.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/voice.Tpo $(DEPDIR)/voice.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/voice.cc' object='voice.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-envelope.obj: resid-fp/envelope.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-envelope.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-envelope.Tpo -c -o resid-fp/pcem-envelope.obj `if test -f 'resid-fp/envelope.cc'; then $(CYGPATH_W) 'resid-fp/envelope.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/envelope.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-envelope.Tpo resid-fp/$(DEPDIR)/pcem-envelope.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/envelope.cc' object='resid-fp/pcem-envelope.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o voice.obj `if test -f 'resid-fp/voice.cc'; then $(CYGPATH_W) 'resid-fp/voice.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/voice.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-envelope.obj `if test -f 'resid-fp/envelope.cc'; then $(CYGPATH_W) 'resid-fp/envelope.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/envelope.cc'; fi` -wave6581_PS_.o: resid-fp/wave6581_PS_.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_PS_.o -MD -MP -MF $(DEPDIR)/wave6581_PS_.Tpo -c -o wave6581_PS_.o `test -f 'resid-fp/wave6581_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PS_.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave6581_PS_.Tpo $(DEPDIR)/wave6581_PS_.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_PS_.cc' object='wave6581_PS_.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-extfilt.o: resid-fp/extfilt.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-extfilt.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-extfilt.Tpo -c -o resid-fp/pcem-extfilt.o `test -f 'resid-fp/extfilt.cc' || echo '$(srcdir)/'`resid-fp/extfilt.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-extfilt.Tpo resid-fp/$(DEPDIR)/pcem-extfilt.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/extfilt.cc' object='resid-fp/pcem-extfilt.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_PS_.o `test -f 'resid-fp/wave6581_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PS_.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-extfilt.o `test -f 'resid-fp/extfilt.cc' || echo '$(srcdir)/'`resid-fp/extfilt.cc -wave6581_PS_.obj: resid-fp/wave6581_PS_.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_PS_.obj -MD -MP -MF $(DEPDIR)/wave6581_PS_.Tpo -c -o wave6581_PS_.obj `if test -f 'resid-fp/wave6581_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PS_.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave6581_PS_.Tpo $(DEPDIR)/wave6581_PS_.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_PS_.cc' object='wave6581_PS_.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-extfilt.obj: resid-fp/extfilt.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-extfilt.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-extfilt.Tpo -c -o resid-fp/pcem-extfilt.obj `if test -f 'resid-fp/extfilt.cc'; then $(CYGPATH_W) 'resid-fp/extfilt.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/extfilt.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-extfilt.Tpo resid-fp/$(DEPDIR)/pcem-extfilt.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/extfilt.cc' object='resid-fp/pcem-extfilt.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_PS_.obj `if test -f 'resid-fp/wave6581_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PS_.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-extfilt.obj `if test -f 'resid-fp/extfilt.cc'; then $(CYGPATH_W) 'resid-fp/extfilt.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/extfilt.cc'; fi` -wave6581_PST.o: resid-fp/wave6581_PST.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_PST.o -MD -MP -MF $(DEPDIR)/wave6581_PST.Tpo -c -o wave6581_PST.o `test -f 'resid-fp/wave6581_PST.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PST.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave6581_PST.Tpo $(DEPDIR)/wave6581_PST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_PST.cc' object='wave6581_PST.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-filter.o: resid-fp/filter.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-filter.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-filter.Tpo -c -o resid-fp/pcem-filter.o `test -f 'resid-fp/filter.cc' || echo '$(srcdir)/'`resid-fp/filter.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-filter.Tpo resid-fp/$(DEPDIR)/pcem-filter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/filter.cc' object='resid-fp/pcem-filter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_PST.o `test -f 'resid-fp/wave6581_PST.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PST.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-filter.o `test -f 'resid-fp/filter.cc' || echo '$(srcdir)/'`resid-fp/filter.cc -wave6581_PST.obj: resid-fp/wave6581_PST.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_PST.obj -MD -MP -MF $(DEPDIR)/wave6581_PST.Tpo -c -o wave6581_PST.obj `if test -f 'resid-fp/wave6581_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PST.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave6581_PST.Tpo $(DEPDIR)/wave6581_PST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_PST.cc' object='wave6581_PST.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-filter.obj: resid-fp/filter.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-filter.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-filter.Tpo -c -o resid-fp/pcem-filter.obj `if test -f 'resid-fp/filter.cc'; then $(CYGPATH_W) 'resid-fp/filter.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/filter.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-filter.Tpo resid-fp/$(DEPDIR)/pcem-filter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/filter.cc' object='resid-fp/pcem-filter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_PST.obj `if test -f 'resid-fp/wave6581_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PST.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-filter.obj `if test -f 'resid-fp/filter.cc'; then $(CYGPATH_W) 'resid-fp/filter.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/filter.cc'; fi` -wave6581_P_T.o: resid-fp/wave6581_P_T.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_P_T.o -MD -MP -MF $(DEPDIR)/wave6581_P_T.Tpo -c -o wave6581_P_T.o `test -f 'resid-fp/wave6581_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave6581_P_T.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave6581_P_T.Tpo $(DEPDIR)/wave6581_P_T.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_P_T.cc' object='wave6581_P_T.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-pot.o: resid-fp/pot.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-pot.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-pot.Tpo -c -o resid-fp/pcem-pot.o `test -f 'resid-fp/pot.cc' || echo '$(srcdir)/'`resid-fp/pot.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-pot.Tpo resid-fp/$(DEPDIR)/pcem-pot.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/pot.cc' object='resid-fp/pcem-pot.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_P_T.o `test -f 'resid-fp/wave6581_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave6581_P_T.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-pot.o `test -f 'resid-fp/pot.cc' || echo '$(srcdir)/'`resid-fp/pot.cc -wave6581_P_T.obj: resid-fp/wave6581_P_T.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581_P_T.obj -MD -MP -MF $(DEPDIR)/wave6581_P_T.Tpo -c -o wave6581_P_T.obj `if test -f 'resid-fp/wave6581_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_P_T.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave6581_P_T.Tpo $(DEPDIR)/wave6581_P_T.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_P_T.cc' object='wave6581_P_T.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-pot.obj: resid-fp/pot.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-pot.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-pot.Tpo -c -o resid-fp/pcem-pot.obj `if test -f 'resid-fp/pot.cc'; then $(CYGPATH_W) 'resid-fp/pot.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/pot.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-pot.Tpo resid-fp/$(DEPDIR)/pcem-pot.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/pot.cc' object='resid-fp/pcem-pot.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581_P_T.obj `if test -f 'resid-fp/wave6581_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_P_T.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-pot.obj `if test -f 'resid-fp/pot.cc'; then $(CYGPATH_W) 'resid-fp/pot.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/pot.cc'; fi` -wave6581__ST.o: resid-fp/wave6581__ST.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581__ST.o -MD -MP -MF $(DEPDIR)/wave6581__ST.Tpo -c -o wave6581__ST.o `test -f 'resid-fp/wave6581__ST.cc' || echo '$(srcdir)/'`resid-fp/wave6581__ST.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave6581__ST.Tpo $(DEPDIR)/wave6581__ST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581__ST.cc' object='wave6581__ST.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-sid.o: resid-fp/sid.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-sid.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-sid.Tpo -c -o resid-fp/pcem-sid.o `test -f 'resid-fp/sid.cc' || echo '$(srcdir)/'`resid-fp/sid.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-sid.Tpo resid-fp/$(DEPDIR)/pcem-sid.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/sid.cc' object='resid-fp/pcem-sid.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581__ST.o `test -f 'resid-fp/wave6581__ST.cc' || echo '$(srcdir)/'`resid-fp/wave6581__ST.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-sid.o `test -f 'resid-fp/sid.cc' || echo '$(srcdir)/'`resid-fp/sid.cc -wave6581__ST.obj: resid-fp/wave6581__ST.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave6581__ST.obj -MD -MP -MF $(DEPDIR)/wave6581__ST.Tpo -c -o wave6581__ST.obj `if test -f 'resid-fp/wave6581__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581__ST.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave6581__ST.Tpo $(DEPDIR)/wave6581__ST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581__ST.cc' object='wave6581__ST.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-sid.obj: resid-fp/sid.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-sid.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-sid.Tpo -c -o resid-fp/pcem-sid.obj `if test -f 'resid-fp/sid.cc'; then $(CYGPATH_W) 'resid-fp/sid.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/sid.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-sid.Tpo resid-fp/$(DEPDIR)/pcem-sid.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/sid.cc' object='resid-fp/pcem-sid.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave6581__ST.obj `if test -f 'resid-fp/wave6581__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581__ST.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-sid.obj `if test -f 'resid-fp/sid.cc'; then $(CYGPATH_W) 'resid-fp/sid.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/sid.cc'; fi` -wave8580_PS_.o: resid-fp/wave8580_PS_.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_PS_.o -MD -MP -MF $(DEPDIR)/wave8580_PS_.Tpo -c -o wave8580_PS_.o `test -f 'resid-fp/wave8580_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PS_.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave8580_PS_.Tpo $(DEPDIR)/wave8580_PS_.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_PS_.cc' object='wave8580_PS_.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-voice.o: resid-fp/voice.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-voice.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-voice.Tpo -c -o resid-fp/pcem-voice.o `test -f 'resid-fp/voice.cc' || echo '$(srcdir)/'`resid-fp/voice.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-voice.Tpo resid-fp/$(DEPDIR)/pcem-voice.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/voice.cc' object='resid-fp/pcem-voice.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_PS_.o `test -f 'resid-fp/wave8580_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PS_.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-voice.o `test -f 'resid-fp/voice.cc' || echo '$(srcdir)/'`resid-fp/voice.cc -wave8580_PS_.obj: resid-fp/wave8580_PS_.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_PS_.obj -MD -MP -MF $(DEPDIR)/wave8580_PS_.Tpo -c -o wave8580_PS_.obj `if test -f 'resid-fp/wave8580_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PS_.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave8580_PS_.Tpo $(DEPDIR)/wave8580_PS_.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_PS_.cc' object='wave8580_PS_.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-voice.obj: resid-fp/voice.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-voice.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-voice.Tpo -c -o resid-fp/pcem-voice.obj `if test -f 'resid-fp/voice.cc'; then $(CYGPATH_W) 'resid-fp/voice.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/voice.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-voice.Tpo resid-fp/$(DEPDIR)/pcem-voice.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/voice.cc' object='resid-fp/pcem-voice.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_PS_.obj `if test -f 'resid-fp/wave8580_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PS_.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-voice.obj `if test -f 'resid-fp/voice.cc'; then $(CYGPATH_W) 'resid-fp/voice.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/voice.cc'; fi` -wave8580_PST.o: resid-fp/wave8580_PST.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_PST.o -MD -MP -MF $(DEPDIR)/wave8580_PST.Tpo -c -o wave8580_PST.o `test -f 'resid-fp/wave8580_PST.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PST.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave8580_PST.Tpo $(DEPDIR)/wave8580_PST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_PST.cc' object='wave8580_PST.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-wave6581_PS_.o: resid-fp/wave6581_PS_.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave6581_PS_.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Tpo -c -o resid-fp/pcem-wave6581_PS_.o `test -f 'resid-fp/wave6581_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PS_.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Tpo resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_PS_.cc' object='resid-fp/pcem-wave6581_PS_.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_PST.o `test -f 'resid-fp/wave8580_PST.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PST.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave6581_PS_.o `test -f 'resid-fp/wave6581_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PS_.cc -wave8580_PST.obj: resid-fp/wave8580_PST.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_PST.obj -MD -MP -MF $(DEPDIR)/wave8580_PST.Tpo -c -o wave8580_PST.obj `if test -f 'resid-fp/wave8580_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PST.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave8580_PST.Tpo $(DEPDIR)/wave8580_PST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_PST.cc' object='wave8580_PST.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-wave6581_PS_.obj: resid-fp/wave6581_PS_.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave6581_PS_.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Tpo -c -o resid-fp/pcem-wave6581_PS_.obj `if test -f 'resid-fp/wave6581_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PS_.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Tpo resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_PS_.cc' object='resid-fp/pcem-wave6581_PS_.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_PST.obj `if test -f 'resid-fp/wave8580_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PST.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave6581_PS_.obj `if test -f 'resid-fp/wave6581_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PS_.cc'; fi` -wave8580_P_T.o: resid-fp/wave8580_P_T.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_P_T.o -MD -MP -MF $(DEPDIR)/wave8580_P_T.Tpo -c -o wave8580_P_T.o `test -f 'resid-fp/wave8580_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave8580_P_T.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave8580_P_T.Tpo $(DEPDIR)/wave8580_P_T.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_P_T.cc' object='wave8580_P_T.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-wave6581_PST.o: resid-fp/wave6581_PST.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave6581_PST.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave6581_PST.Tpo -c -o resid-fp/pcem-wave6581_PST.o `test -f 'resid-fp/wave6581_PST.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PST.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave6581_PST.Tpo resid-fp/$(DEPDIR)/pcem-wave6581_PST.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_PST.cc' object='resid-fp/pcem-wave6581_PST.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_P_T.o `test -f 'resid-fp/wave8580_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave8580_P_T.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave6581_PST.o `test -f 'resid-fp/wave6581_PST.cc' || echo '$(srcdir)/'`resid-fp/wave6581_PST.cc -wave8580_P_T.obj: resid-fp/wave8580_P_T.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580_P_T.obj -MD -MP -MF $(DEPDIR)/wave8580_P_T.Tpo -c -o wave8580_P_T.obj `if test -f 'resid-fp/wave8580_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_P_T.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave8580_P_T.Tpo $(DEPDIR)/wave8580_P_T.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_P_T.cc' object='wave8580_P_T.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-wave6581_PST.obj: resid-fp/wave6581_PST.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave6581_PST.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave6581_PST.Tpo -c -o resid-fp/pcem-wave6581_PST.obj `if test -f 'resid-fp/wave6581_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PST.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave6581_PST.Tpo resid-fp/$(DEPDIR)/pcem-wave6581_PST.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_PST.cc' object='resid-fp/pcem-wave6581_PST.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580_P_T.obj `if test -f 'resid-fp/wave8580_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_P_T.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave6581_PST.obj `if test -f 'resid-fp/wave6581_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_PST.cc'; fi` -wave8580__ST.o: resid-fp/wave8580__ST.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580__ST.o -MD -MP -MF $(DEPDIR)/wave8580__ST.Tpo -c -o wave8580__ST.o `test -f 'resid-fp/wave8580__ST.cc' || echo '$(srcdir)/'`resid-fp/wave8580__ST.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave8580__ST.Tpo $(DEPDIR)/wave8580__ST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580__ST.cc' object='wave8580__ST.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-wave6581_P_T.o: resid-fp/wave6581_P_T.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave6581_P_T.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Tpo -c -o resid-fp/pcem-wave6581_P_T.o `test -f 'resid-fp/wave6581_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave6581_P_T.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Tpo resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_P_T.cc' object='resid-fp/pcem-wave6581_P_T.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580__ST.o `test -f 'resid-fp/wave8580__ST.cc' || echo '$(srcdir)/'`resid-fp/wave8580__ST.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave6581_P_T.o `test -f 'resid-fp/wave6581_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave6581_P_T.cc -wave8580__ST.obj: resid-fp/wave8580__ST.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave8580__ST.obj -MD -MP -MF $(DEPDIR)/wave8580__ST.Tpo -c -o wave8580__ST.obj `if test -f 'resid-fp/wave8580__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580__ST.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave8580__ST.Tpo $(DEPDIR)/wave8580__ST.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580__ST.cc' object='wave8580__ST.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-wave6581_P_T.obj: resid-fp/wave6581_P_T.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave6581_P_T.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Tpo -c -o resid-fp/pcem-wave6581_P_T.obj `if test -f 'resid-fp/wave6581_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_P_T.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Tpo resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581_P_T.cc' object='resid-fp/pcem-wave6581_P_T.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave8580__ST.obj `if test -f 'resid-fp/wave8580__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580__ST.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave6581_P_T.obj `if test -f 'resid-fp/wave6581_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave6581_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581_P_T.cc'; fi` -wave.o: resid-fp/wave.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave.o -MD -MP -MF $(DEPDIR)/wave.Tpo -c -o wave.o `test -f 'resid-fp/wave.cc' || echo '$(srcdir)/'`resid-fp/wave.cc -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave.Tpo $(DEPDIR)/wave.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave.cc' object='wave.o' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-wave6581__ST.o: resid-fp/wave6581__ST.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave6581__ST.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave6581__ST.Tpo -c -o resid-fp/pcem-wave6581__ST.o `test -f 'resid-fp/wave6581__ST.cc' || echo '$(srcdir)/'`resid-fp/wave6581__ST.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave6581__ST.Tpo resid-fp/$(DEPDIR)/pcem-wave6581__ST.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581__ST.cc' object='resid-fp/pcem-wave6581__ST.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave.o `test -f 'resid-fp/wave.cc' || echo '$(srcdir)/'`resid-fp/wave.cc +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave6581__ST.o `test -f 'resid-fp/wave6581__ST.cc' || echo '$(srcdir)/'`resid-fp/wave6581__ST.cc -wave.obj: resid-fp/wave.cc -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT wave.obj -MD -MP -MF $(DEPDIR)/wave.Tpo -c -o wave.obj `if test -f 'resid-fp/wave.cc'; then $(CYGPATH_W) 'resid-fp/wave.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave.cc'; fi` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/wave.Tpo $(DEPDIR)/wave.Po -@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave.cc' object='wave.obj' libtool=no @AMDEPBACKSLASH@ +resid-fp/pcem-wave6581__ST.obj: resid-fp/wave6581__ST.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave6581__ST.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave6581__ST.Tpo -c -o resid-fp/pcem-wave6581__ST.obj `if test -f 'resid-fp/wave6581__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581__ST.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave6581__ST.Tpo resid-fp/$(DEPDIR)/pcem-wave6581__ST.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave6581__ST.cc' object='resid-fp/pcem-wave6581__ST.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o wave.obj `if test -f 'resid-fp/wave.cc'; then $(CYGPATH_W) 'resid-fp/wave.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave.cc'; fi` +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave6581__ST.obj `if test -f 'resid-fp/wave6581__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave6581__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave6581__ST.cc'; fi` + +resid-fp/pcem-wave8580_PS_.o: resid-fp/wave8580_PS_.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave8580_PS_.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Tpo -c -o resid-fp/pcem-wave8580_PS_.o `test -f 'resid-fp/wave8580_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PS_.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Tpo resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_PS_.cc' object='resid-fp/pcem-wave8580_PS_.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave8580_PS_.o `test -f 'resid-fp/wave8580_PS_.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PS_.cc + +resid-fp/pcem-wave8580_PS_.obj: resid-fp/wave8580_PS_.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave8580_PS_.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Tpo -c -o resid-fp/pcem-wave8580_PS_.obj `if test -f 'resid-fp/wave8580_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PS_.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Tpo resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_PS_.cc' object='resid-fp/pcem-wave8580_PS_.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave8580_PS_.obj `if test -f 'resid-fp/wave8580_PS_.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PS_.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PS_.cc'; fi` + +resid-fp/pcem-wave8580_PST.o: resid-fp/wave8580_PST.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave8580_PST.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave8580_PST.Tpo -c -o resid-fp/pcem-wave8580_PST.o `test -f 'resid-fp/wave8580_PST.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PST.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave8580_PST.Tpo resid-fp/$(DEPDIR)/pcem-wave8580_PST.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_PST.cc' object='resid-fp/pcem-wave8580_PST.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave8580_PST.o `test -f 'resid-fp/wave8580_PST.cc' || echo '$(srcdir)/'`resid-fp/wave8580_PST.cc + +resid-fp/pcem-wave8580_PST.obj: resid-fp/wave8580_PST.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave8580_PST.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave8580_PST.Tpo -c -o resid-fp/pcem-wave8580_PST.obj `if test -f 'resid-fp/wave8580_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PST.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave8580_PST.Tpo resid-fp/$(DEPDIR)/pcem-wave8580_PST.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_PST.cc' object='resid-fp/pcem-wave8580_PST.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave8580_PST.obj `if test -f 'resid-fp/wave8580_PST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_PST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_PST.cc'; fi` + +resid-fp/pcem-wave8580_P_T.o: resid-fp/wave8580_P_T.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave8580_P_T.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Tpo -c -o resid-fp/pcem-wave8580_P_T.o `test -f 'resid-fp/wave8580_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave8580_P_T.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Tpo resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_P_T.cc' object='resid-fp/pcem-wave8580_P_T.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave8580_P_T.o `test -f 'resid-fp/wave8580_P_T.cc' || echo '$(srcdir)/'`resid-fp/wave8580_P_T.cc + +resid-fp/pcem-wave8580_P_T.obj: resid-fp/wave8580_P_T.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave8580_P_T.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Tpo -c -o resid-fp/pcem-wave8580_P_T.obj `if test -f 'resid-fp/wave8580_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_P_T.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Tpo resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580_P_T.cc' object='resid-fp/pcem-wave8580_P_T.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave8580_P_T.obj `if test -f 'resid-fp/wave8580_P_T.cc'; then $(CYGPATH_W) 'resid-fp/wave8580_P_T.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580_P_T.cc'; fi` + +resid-fp/pcem-wave8580__ST.o: resid-fp/wave8580__ST.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave8580__ST.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave8580__ST.Tpo -c -o resid-fp/pcem-wave8580__ST.o `test -f 'resid-fp/wave8580__ST.cc' || echo '$(srcdir)/'`resid-fp/wave8580__ST.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave8580__ST.Tpo resid-fp/$(DEPDIR)/pcem-wave8580__ST.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580__ST.cc' object='resid-fp/pcem-wave8580__ST.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave8580__ST.o `test -f 'resid-fp/wave8580__ST.cc' || echo '$(srcdir)/'`resid-fp/wave8580__ST.cc + +resid-fp/pcem-wave8580__ST.obj: resid-fp/wave8580__ST.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave8580__ST.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave8580__ST.Tpo -c -o resid-fp/pcem-wave8580__ST.obj `if test -f 'resid-fp/wave8580__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580__ST.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave8580__ST.Tpo resid-fp/$(DEPDIR)/pcem-wave8580__ST.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave8580__ST.cc' object='resid-fp/pcem-wave8580__ST.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave8580__ST.obj `if test -f 'resid-fp/wave8580__ST.cc'; then $(CYGPATH_W) 'resid-fp/wave8580__ST.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave8580__ST.cc'; fi` + +resid-fp/pcem-wave.o: resid-fp/wave.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave.o -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave.Tpo -c -o resid-fp/pcem-wave.o `test -f 'resid-fp/wave.cc' || echo '$(srcdir)/'`resid-fp/wave.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave.Tpo resid-fp/$(DEPDIR)/pcem-wave.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave.cc' object='resid-fp/pcem-wave.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave.o `test -f 'resid-fp/wave.cc' || echo '$(srcdir)/'`resid-fp/wave.cc + +resid-fp/pcem-wave.obj: resid-fp/wave.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT resid-fp/pcem-wave.obj -MD -MP -MF resid-fp/$(DEPDIR)/pcem-wave.Tpo -c -o resid-fp/pcem-wave.obj `if test -f 'resid-fp/wave.cc'; then $(CYGPATH_W) 'resid-fp/wave.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) resid-fp/$(DEPDIR)/pcem-wave.Tpo resid-fp/$(DEPDIR)/pcem-wave.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='resid-fp/wave.cc' object='resid-fp/pcem-wave.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o resid-fp/pcem-wave.obj `if test -f 'resid-fp/wave.cc'; then $(CYGPATH_W) 'resid-fp/wave.cc'; else $(CYGPATH_W) '$(srcdir)/resid-fp/wave.cc'; fi` + +pcem-wx-main.o: wx-main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-main.o -MD -MP -MF $(DEPDIR)/pcem-wx-main.Tpo -c -o pcem-wx-main.o `test -f 'wx-main.cc' || echo '$(srcdir)/'`wx-main.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-main.Tpo $(DEPDIR)/pcem-wx-main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-main.cc' object='pcem-wx-main.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-main.o `test -f 'wx-main.cc' || echo '$(srcdir)/'`wx-main.cc + +pcem-wx-main.obj: wx-main.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-main.obj -MD -MP -MF $(DEPDIR)/pcem-wx-main.Tpo -c -o pcem-wx-main.obj `if test -f 'wx-main.cc'; then $(CYGPATH_W) 'wx-main.cc'; else $(CYGPATH_W) '$(srcdir)/wx-main.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-main.Tpo $(DEPDIR)/pcem-wx-main.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-main.cc' object='pcem-wx-main.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-main.obj `if test -f 'wx-main.cc'; then $(CYGPATH_W) 'wx-main.cc'; else $(CYGPATH_W) '$(srcdir)/wx-main.cc'; fi` + +pcem-wx-dialogbox.o: wx-dialogbox.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-dialogbox.o -MD -MP -MF $(DEPDIR)/pcem-wx-dialogbox.Tpo -c -o pcem-wx-dialogbox.o `test -f 'wx-dialogbox.cc' || echo '$(srcdir)/'`wx-dialogbox.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-dialogbox.Tpo $(DEPDIR)/pcem-wx-dialogbox.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-dialogbox.cc' object='pcem-wx-dialogbox.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-dialogbox.o `test -f 'wx-dialogbox.cc' || echo '$(srcdir)/'`wx-dialogbox.cc + +pcem-wx-dialogbox.obj: wx-dialogbox.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-dialogbox.obj -MD -MP -MF $(DEPDIR)/pcem-wx-dialogbox.Tpo -c -o pcem-wx-dialogbox.obj `if test -f 'wx-dialogbox.cc'; then $(CYGPATH_W) 'wx-dialogbox.cc'; else $(CYGPATH_W) '$(srcdir)/wx-dialogbox.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-dialogbox.Tpo $(DEPDIR)/pcem-wx-dialogbox.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-dialogbox.cc' object='pcem-wx-dialogbox.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-dialogbox.obj `if test -f 'wx-dialogbox.cc'; then $(CYGPATH_W) 'wx-dialogbox.cc'; else $(CYGPATH_W) '$(srcdir)/wx-dialogbox.cc'; fi` + +pcem-wx-utils.o: wx-utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-utils.o -MD -MP -MF $(DEPDIR)/pcem-wx-utils.Tpo -c -o pcem-wx-utils.o `test -f 'wx-utils.cc' || echo '$(srcdir)/'`wx-utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-utils.Tpo $(DEPDIR)/pcem-wx-utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-utils.cc' object='pcem-wx-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-utils.o `test -f 'wx-utils.cc' || echo '$(srcdir)/'`wx-utils.cc + +pcem-wx-utils.obj: wx-utils.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-utils.obj -MD -MP -MF $(DEPDIR)/pcem-wx-utils.Tpo -c -o pcem-wx-utils.obj `if test -f 'wx-utils.cc'; then $(CYGPATH_W) 'wx-utils.cc'; else $(CYGPATH_W) '$(srcdir)/wx-utils.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-utils.Tpo $(DEPDIR)/pcem-wx-utils.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-utils.cc' object='pcem-wx-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-utils.obj `if test -f 'wx-utils.cc'; then $(CYGPATH_W) 'wx-utils.cc'; else $(CYGPATH_W) '$(srcdir)/wx-utils.cc'; fi` + +pcem-wx-app.o: wx-app.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-app.o -MD -MP -MF $(DEPDIR)/pcem-wx-app.Tpo -c -o pcem-wx-app.o `test -f 'wx-app.cc' || echo '$(srcdir)/'`wx-app.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-app.Tpo $(DEPDIR)/pcem-wx-app.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-app.cc' object='pcem-wx-app.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-app.o `test -f 'wx-app.cc' || echo '$(srcdir)/'`wx-app.cc + +pcem-wx-app.obj: wx-app.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-app.obj -MD -MP -MF $(DEPDIR)/pcem-wx-app.Tpo -c -o pcem-wx-app.obj `if test -f 'wx-app.cc'; then $(CYGPATH_W) 'wx-app.cc'; else $(CYGPATH_W) '$(srcdir)/wx-app.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-app.Tpo $(DEPDIR)/pcem-wx-app.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-app.cc' object='pcem-wx-app.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-app.obj `if test -f 'wx-app.cc'; then $(CYGPATH_W) 'wx-app.cc'; else $(CYGPATH_W) '$(srcdir)/wx-app.cc'; fi` + +pcem-wx-deviceconfig.o: wx-deviceconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-deviceconfig.o -MD -MP -MF $(DEPDIR)/pcem-wx-deviceconfig.Tpo -c -o pcem-wx-deviceconfig.o `test -f 'wx-deviceconfig.cc' || echo '$(srcdir)/'`wx-deviceconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-deviceconfig.Tpo $(DEPDIR)/pcem-wx-deviceconfig.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-deviceconfig.cc' object='pcem-wx-deviceconfig.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-deviceconfig.o `test -f 'wx-deviceconfig.cc' || echo '$(srcdir)/'`wx-deviceconfig.cc + +pcem-wx-deviceconfig.obj: wx-deviceconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-deviceconfig.obj -MD -MP -MF $(DEPDIR)/pcem-wx-deviceconfig.Tpo -c -o pcem-wx-deviceconfig.obj `if test -f 'wx-deviceconfig.cc'; then $(CYGPATH_W) 'wx-deviceconfig.cc'; else $(CYGPATH_W) '$(srcdir)/wx-deviceconfig.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-deviceconfig.Tpo $(DEPDIR)/pcem-wx-deviceconfig.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-deviceconfig.cc' object='pcem-wx-deviceconfig.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-deviceconfig.obj `if test -f 'wx-deviceconfig.cc'; then $(CYGPATH_W) 'wx-deviceconfig.cc'; else $(CYGPATH_W) '$(srcdir)/wx-deviceconfig.cc'; fi` + +pcem-wx-status.o: wx-status.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-status.o -MD -MP -MF $(DEPDIR)/pcem-wx-status.Tpo -c -o pcem-wx-status.o `test -f 'wx-status.cc' || echo '$(srcdir)/'`wx-status.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-status.Tpo $(DEPDIR)/pcem-wx-status.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-status.cc' object='pcem-wx-status.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-status.o `test -f 'wx-status.cc' || echo '$(srcdir)/'`wx-status.cc + +pcem-wx-status.obj: wx-status.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-status.obj -MD -MP -MF $(DEPDIR)/pcem-wx-status.Tpo -c -o pcem-wx-status.obj `if test -f 'wx-status.cc'; then $(CYGPATH_W) 'wx-status.cc'; else $(CYGPATH_W) '$(srcdir)/wx-status.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-status.Tpo $(DEPDIR)/pcem-wx-status.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-status.cc' object='pcem-wx-status.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-status.obj `if test -f 'wx-status.cc'; then $(CYGPATH_W) 'wx-status.cc'; else $(CYGPATH_W) '$(srcdir)/wx-status.cc'; fi` + +pcem-wx-shaderconfig.o: wx-shaderconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-shaderconfig.o -MD -MP -MF $(DEPDIR)/pcem-wx-shaderconfig.Tpo -c -o pcem-wx-shaderconfig.o `test -f 'wx-shaderconfig.cc' || echo '$(srcdir)/'`wx-shaderconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-shaderconfig.Tpo $(DEPDIR)/pcem-wx-shaderconfig.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-shaderconfig.cc' object='pcem-wx-shaderconfig.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-shaderconfig.o `test -f 'wx-shaderconfig.cc' || echo '$(srcdir)/'`wx-shaderconfig.cc + +pcem-wx-shaderconfig.obj: wx-shaderconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-shaderconfig.obj -MD -MP -MF $(DEPDIR)/pcem-wx-shaderconfig.Tpo -c -o pcem-wx-shaderconfig.obj `if test -f 'wx-shaderconfig.cc'; then $(CYGPATH_W) 'wx-shaderconfig.cc'; else $(CYGPATH_W) '$(srcdir)/wx-shaderconfig.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-shaderconfig.Tpo $(DEPDIR)/pcem-wx-shaderconfig.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-shaderconfig.cc' object='pcem-wx-shaderconfig.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-shaderconfig.obj `if test -f 'wx-shaderconfig.cc'; then $(CYGPATH_W) 'wx-shaderconfig.cc'; else $(CYGPATH_W) '$(srcdir)/wx-shaderconfig.cc'; fi` + +pcem-wx-joystickconfig.o: wx-joystickconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-joystickconfig.o -MD -MP -MF $(DEPDIR)/pcem-wx-joystickconfig.Tpo -c -o pcem-wx-joystickconfig.o `test -f 'wx-joystickconfig.cc' || echo '$(srcdir)/'`wx-joystickconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-joystickconfig.Tpo $(DEPDIR)/pcem-wx-joystickconfig.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-joystickconfig.cc' object='pcem-wx-joystickconfig.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-joystickconfig.o `test -f 'wx-joystickconfig.cc' || echo '$(srcdir)/'`wx-joystickconfig.cc + +pcem-wx-joystickconfig.obj: wx-joystickconfig.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-joystickconfig.obj -MD -MP -MF $(DEPDIR)/pcem-wx-joystickconfig.Tpo -c -o pcem-wx-joystickconfig.obj `if test -f 'wx-joystickconfig.cc'; then $(CYGPATH_W) 'wx-joystickconfig.cc'; else $(CYGPATH_W) '$(srcdir)/wx-joystickconfig.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-joystickconfig.Tpo $(DEPDIR)/pcem-wx-joystickconfig.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-joystickconfig.cc' object='pcem-wx-joystickconfig.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-joystickconfig.obj `if test -f 'wx-joystickconfig.cc'; then $(CYGPATH_W) 'wx-joystickconfig.cc'; else $(CYGPATH_W) '$(srcdir)/wx-joystickconfig.cc'; fi` + +pcem-wx-createdisc.o: wx-createdisc.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-createdisc.o -MD -MP -MF $(DEPDIR)/pcem-wx-createdisc.Tpo -c -o pcem-wx-createdisc.o `test -f 'wx-createdisc.cc' || echo '$(srcdir)/'`wx-createdisc.cc +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-createdisc.Tpo $(DEPDIR)/pcem-wx-createdisc.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-createdisc.cc' object='pcem-wx-createdisc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-createdisc.o `test -f 'wx-createdisc.cc' || echo '$(srcdir)/'`wx-createdisc.cc + +pcem-wx-createdisc.obj: wx-createdisc.cc +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-createdisc.obj -MD -MP -MF $(DEPDIR)/pcem-wx-createdisc.Tpo -c -o pcem-wx-createdisc.obj `if test -f 'wx-createdisc.cc'; then $(CYGPATH_W) 'wx-createdisc.cc'; else $(CYGPATH_W) '$(srcdir)/wx-createdisc.cc'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-createdisc.Tpo $(DEPDIR)/pcem-wx-createdisc.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-createdisc.cc' object='pcem-wx-createdisc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-createdisc.obj `if test -f 'wx-createdisc.cc'; then $(CYGPATH_W) 'wx-createdisc.cc'; else $(CYGPATH_W) '$(srcdir)/wx-createdisc.cc'; fi` + +pcem-wx-resources.o: wx-resources.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-resources.o -MD -MP -MF $(DEPDIR)/pcem-wx-resources.Tpo -c -o pcem-wx-resources.o `test -f 'wx-resources.cpp' || echo '$(srcdir)/'`wx-resources.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-resources.Tpo $(DEPDIR)/pcem-wx-resources.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-resources.cpp' object='pcem-wx-resources.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-resources.o `test -f 'wx-resources.cpp' || echo '$(srcdir)/'`wx-resources.cpp + +pcem-wx-resources.obj: wx-resources.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -MT pcem-wx-resources.obj -MD -MP -MF $(DEPDIR)/pcem-wx-resources.Tpo -c -o pcem-wx-resources.obj `if test -f 'wx-resources.cpp'; then $(CYGPATH_W) 'wx-resources.cpp'; else $(CYGPATH_W) '$(srcdir)/wx-resources.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/pcem-wx-resources.Tpo $(DEPDIR)/pcem-wx-resources.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='wx-resources.cpp' object='pcem-wx-resources.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(pcem_CXXFLAGS) $(CXXFLAGS) -c -o pcem-wx-resources.obj `if test -f 'wx-resources.cpp'; then $(CYGPATH_W) 'wx-resources.cpp'; else $(CYGPATH_W) '$(srcdir)/wx-resources.cpp'; fi` .cpp.o: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< .cpp.obj: -@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` @@ -3432,7 +6684,10 @@ cscopelist-am: $(am__tagged_files) distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -distdir: $(DISTFILES) +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ @@ -3496,6 +6751,14 @@ clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + -rm -f dosbox/$(DEPDIR)/$(am__dirstamp) + -rm -f dosbox/$(am__dirstamp) + -rm -f minivhd/$(DEPDIR)/$(am__dirstamp) + -rm -f minivhd/$(am__dirstamp) + -rm -f resid-fp/$(DEPDIR)/$(am__dirstamp) + -rm -f resid-fp/$(am__dirstamp) + -rm -f slirp/$(DEPDIR)/$(am__dirstamp) + -rm -f slirp/$(am__dirstamp) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @@ -3505,7 +6768,362 @@ clean: clean-am clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-am - -rm -rf ./$(DEPDIR) + -rm -f ./$(DEPDIR)/pcem-386.Po + -rm -f ./$(DEPDIR)/pcem-386_common.Po + -rm -f ./$(DEPDIR)/pcem-386_dynarec.Po + -rm -f ./$(DEPDIR)/pcem-386_dynarec_ops.Po + -rm -f ./$(DEPDIR)/pcem-808x.Po + -rm -f ./$(DEPDIR)/pcem-82091aa.Po + -rm -f ./$(DEPDIR)/pcem-acc2036.Po + -rm -f ./$(DEPDIR)/pcem-acc2168.Po + -rm -f ./$(DEPDIR)/pcem-acc3221.Po + -rm -f ./$(DEPDIR)/pcem-acer386sx.Po + -rm -f ./$(DEPDIR)/pcem-ali1429.Po + -rm -f ./$(DEPDIR)/pcem-amstrad.Po + -rm -f ./$(DEPDIR)/pcem-cassette.Po + -rm -f ./$(DEPDIR)/pcem-cbm_io.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-image.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-ioctl-dummy.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-ioctl-linux.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-ioctl-osx.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-ioctl.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-null.Po + -rm -f ./$(DEPDIR)/pcem-cmd640.Po + -rm -f ./$(DEPDIR)/pcem-codegen.Po + -rm -f ./$(DEPDIR)/pcem-codegen_accumulate.Po + -rm -f ./$(DEPDIR)/pcem-codegen_allocator.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm64.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm64_imm.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm64_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm64_uops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm_uops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86-64.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86-64_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86-64_uops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86_uops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_block.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ir.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_3dnow.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_arith.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_branch.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_fpu_arith.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_fpu_constant.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_fpu_misc.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_helpers.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_jump.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_logic.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_misc.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_arith.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_cmp.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_logic.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_pack.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_shift.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mov.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_shift.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_stack.Po + -rm -f ./$(DEPDIR)/pcem-codegen_reg.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_486.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_686.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_common.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_cyrixiii.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_k6.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_p6.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_pentium.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_winchip.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_winchip2.Po + -rm -f ./$(DEPDIR)/pcem-compaq.Po + -rm -f ./$(DEPDIR)/pcem-config.Po + -rm -f ./$(DEPDIR)/pcem-cpu.Po + -rm -f ./$(DEPDIR)/pcem-cpu_tables.Po + -rm -f ./$(DEPDIR)/pcem-cs8230.Po + -rm -f ./$(DEPDIR)/pcem-dells200.Po + -rm -f ./$(DEPDIR)/pcem-device.Po + -rm -f ./$(DEPDIR)/pcem-disc.Po + -rm -f ./$(DEPDIR)/pcem-disc_fdi.Po + -rm -f ./$(DEPDIR)/pcem-disc_img.Po + -rm -f ./$(DEPDIR)/pcem-disc_sector.Po + -rm -f ./$(DEPDIR)/pcem-dma.Po + -rm -f ./$(DEPDIR)/pcem-esdi_at.Po + -rm -f ./$(DEPDIR)/pcem-f82c710_upc.Po + -rm -f ./$(DEPDIR)/pcem-fdc.Po + -rm -f ./$(DEPDIR)/pcem-fdc37c665.Po + -rm -f ./$(DEPDIR)/pcem-fdc37c93x.Po + -rm -f ./$(DEPDIR)/pcem-fdd.Po + -rm -f ./$(DEPDIR)/pcem-fdi2raw.Po + -rm -f ./$(DEPDIR)/pcem-gameport.Po + -rm -f ./$(DEPDIR)/pcem-hdd.Po + -rm -f ./$(DEPDIR)/pcem-hdd_esdi.Po + -rm -f ./$(DEPDIR)/pcem-hdd_file.Po + -rm -f ./$(DEPDIR)/pcem-headland.Po + -rm -f ./$(DEPDIR)/pcem-i430fx.Po + -rm -f ./$(DEPDIR)/pcem-i430hx.Po + -rm -f ./$(DEPDIR)/pcem-i430lx.Po + -rm -f ./$(DEPDIR)/pcem-i430vx.Po + -rm -f ./$(DEPDIR)/pcem-i440bx.Po + -rm -f ./$(DEPDIR)/pcem-i440fx.Po + -rm -f ./$(DEPDIR)/pcem-ide.Po + -rm -f ./$(DEPDIR)/pcem-ide_atapi.Po + -rm -f ./$(DEPDIR)/pcem-ide_sff8038i.Po + -rm -f ./$(DEPDIR)/pcem-intel.Po + -rm -f ./$(DEPDIR)/pcem-intel_flash.Po + -rm -f ./$(DEPDIR)/pcem-io.Po + -rm -f ./$(DEPDIR)/pcem-jim.Po + -rm -f ./$(DEPDIR)/pcem-joystick_ch_flightstick_pro.Po + -rm -f ./$(DEPDIR)/pcem-joystick_standard.Po + -rm -f ./$(DEPDIR)/pcem-joystick_sw_pad.Po + -rm -f ./$(DEPDIR)/pcem-joystick_tm_fcs.Po + -rm -f ./$(DEPDIR)/pcem-keyboard.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_amstrad.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_at.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_olim24.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_pcjr.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_xt.Po + -rm -f ./$(DEPDIR)/pcem-laserxt.Po + -rm -f ./$(DEPDIR)/pcem-lpt.Po + -rm -f ./$(DEPDIR)/pcem-lpt_dac.Po + -rm -f ./$(DEPDIR)/pcem-lpt_dss.Po + -rm -f ./$(DEPDIR)/pcem-mca.Po + -rm -f ./$(DEPDIR)/pcem-mcr.Po + -rm -f ./$(DEPDIR)/pcem-mem.Po + -rm -f ./$(DEPDIR)/pcem-mem_bios.Po + -rm -f ./$(DEPDIR)/pcem-mfm_at.Po + -rm -f ./$(DEPDIR)/pcem-mfm_xebec.Po + -rm -f ./$(DEPDIR)/pcem-midi_alsa.Po + -rm -f ./$(DEPDIR)/pcem-model.Po + -rm -f ./$(DEPDIR)/pcem-mouse.Po + -rm -f ./$(DEPDIR)/pcem-mouse_msystems.Po + -rm -f ./$(DEPDIR)/pcem-mouse_ps2.Po + -rm -f ./$(DEPDIR)/pcem-mouse_serial.Po + -rm -f ./$(DEPDIR)/pcem-mvp3.Po + -rm -f ./$(DEPDIR)/pcem-ne2000.Po + -rm -f ./$(DEPDIR)/pcem-neat.Po + -rm -f ./$(DEPDIR)/pcem-nethandler.Po + -rm -f ./$(DEPDIR)/pcem-nmi.Po + -rm -f ./$(DEPDIR)/pcem-nvr.Po + -rm -f ./$(DEPDIR)/pcem-nvr_tc8521.Po + -rm -f ./$(DEPDIR)/pcem-olivetti_m24.Po + -rm -f ./$(DEPDIR)/pcem-opti495.Po + -rm -f ./$(DEPDIR)/pcem-paths.Po + -rm -f ./$(DEPDIR)/pcem-pc.Po + -rm -f ./$(DEPDIR)/pcem-pc87306.Po + -rm -f ./$(DEPDIR)/pcem-pc87307.Po + -rm -f ./$(DEPDIR)/pcem-pci.Po + -rm -f ./$(DEPDIR)/pcem-pic.Po + -rm -f ./$(DEPDIR)/pcem-piix.Po + -rm -f ./$(DEPDIR)/pcem-piix_pm.Po + -rm -f ./$(DEPDIR)/pcem-pit.Po + -rm -f ./$(DEPDIR)/pcem-ppi.Po + -rm -f ./$(DEPDIR)/pcem-ps1.Po + -rm -f ./$(DEPDIR)/pcem-ps2.Po + -rm -f ./$(DEPDIR)/pcem-ps2_mca.Po + -rm -f ./$(DEPDIR)/pcem-ps2_nvr.Po + -rm -f ./$(DEPDIR)/pcem-pzx.Po + -rm -f ./$(DEPDIR)/pcem-rom.Po + -rm -f ./$(DEPDIR)/pcem-rtc.Po + -rm -f ./$(DEPDIR)/pcem-rtc_tc8521.Po + -rm -f ./$(DEPDIR)/pcem-scamp.Po + -rm -f ./$(DEPDIR)/pcem-scat.Po + -rm -f ./$(DEPDIR)/pcem-scsi.Po + -rm -f ./$(DEPDIR)/pcem-scsi_53c400.Po + -rm -f ./$(DEPDIR)/pcem-scsi_aha1540.Po + -rm -f ./$(DEPDIR)/pcem-scsi_cd.Po + -rm -f ./$(DEPDIR)/pcem-scsi_hd.Po + -rm -f ./$(DEPDIR)/pcem-scsi_ibm.Po + -rm -f ./$(DEPDIR)/pcem-scsi_zip.Po + -rm -f ./$(DEPDIR)/pcem-serial.Po + -rm -f ./$(DEPDIR)/pcem-sio.Po + -rm -f ./$(DEPDIR)/pcem-sis496.Po + -rm -f ./$(DEPDIR)/pcem-sl82c460.Po + -rm -f ./$(DEPDIR)/pcem-sound.Po + -rm -f ./$(DEPDIR)/pcem-sound_ad1848.Po + -rm -f ./$(DEPDIR)/pcem-sound_adlib.Po + -rm -f ./$(DEPDIR)/pcem-sound_adlibgold.Po + -rm -f ./$(DEPDIR)/pcem-sound_audiopci.Po + -rm -f ./$(DEPDIR)/pcem-sound_azt2316a.Po + -rm -f ./$(DEPDIR)/pcem-sound_cms.Po + -rm -f ./$(DEPDIR)/pcem-sound_dbopl.Po + -rm -f ./$(DEPDIR)/pcem-sound_emu8k.Po + -rm -f ./$(DEPDIR)/pcem-sound_gus.Po + -rm -f ./$(DEPDIR)/pcem-sound_mpu401_uart.Po + -rm -f ./$(DEPDIR)/pcem-sound_opl.Po + -rm -f ./$(DEPDIR)/pcem-sound_pas16.Po + -rm -f ./$(DEPDIR)/pcem-sound_ps1.Po + -rm -f ./$(DEPDIR)/pcem-sound_pssj.Po + -rm -f ./$(DEPDIR)/pcem-sound_resid.Po + -rm -f ./$(DEPDIR)/pcem-sound_sb.Po + -rm -f ./$(DEPDIR)/pcem-sound_sb_dsp.Po + -rm -f ./$(DEPDIR)/pcem-sound_sn76489.Po + -rm -f ./$(DEPDIR)/pcem-sound_speaker.Po + -rm -f ./$(DEPDIR)/pcem-sound_ssi2001.Po + -rm -f ./$(DEPDIR)/pcem-sound_wss.Po + -rm -f ./$(DEPDIR)/pcem-sound_ym7128.Po + -rm -f ./$(DEPDIR)/pcem-soundopenal.Po + -rm -f ./$(DEPDIR)/pcem-sst39sf010.Po + -rm -f ./$(DEPDIR)/pcem-superxt.Po + -rm -f ./$(DEPDIR)/pcem-t1000.Po + -rm -f ./$(DEPDIR)/pcem-t3100e.Po + -rm -f ./$(DEPDIR)/pcem-tandy_eeprom.Po + -rm -f ./$(DEPDIR)/pcem-tandy_rom.Po + -rm -f ./$(DEPDIR)/pcem-timer.Po + -rm -f ./$(DEPDIR)/pcem-um8669f.Po + -rm -f ./$(DEPDIR)/pcem-um8881f.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati18800.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati28800.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati68860_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati_eeprom.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati_mach64.Po + -rm -f ./$(DEPDIR)/pcem-vid_cga.Po + -rm -f ./$(DEPDIR)/pcem-vid_cl5429.Po + -rm -f ./$(DEPDIR)/pcem-vid_colorplus.Po + -rm -f ./$(DEPDIR)/pcem-vid_compaq_cga.Po + -rm -f ./$(DEPDIR)/pcem-vid_ddc.Po + -rm -f ./$(DEPDIR)/pcem-vid_ega.Po + -rm -f ./$(DEPDIR)/pcem-vid_et4000.Po + -rm -f ./$(DEPDIR)/pcem-vid_et4000w32.Po + -rm -f ./$(DEPDIR)/pcem-vid_genius.Po + -rm -f ./$(DEPDIR)/pcem-vid_hercules.Po + -rm -f ./$(DEPDIR)/pcem-vid_ht216.Po + -rm -f ./$(DEPDIR)/pcem-vid_icd2061.Po + -rm -f ./$(DEPDIR)/pcem-vid_ics2595.Po + -rm -f ./$(DEPDIR)/pcem-vid_im1024.Po + -rm -f ./$(DEPDIR)/pcem-vid_incolor.Po + -rm -f ./$(DEPDIR)/pcem-vid_mda.Po + -rm -f ./$(DEPDIR)/pcem-vid_mga.Po + -rm -f ./$(DEPDIR)/pcem-vid_olivetti_m24.Po + -rm -f ./$(DEPDIR)/pcem-vid_oti037.Po + -rm -f ./$(DEPDIR)/pcem-vid_oti067.Po + -rm -f ./$(DEPDIR)/pcem-vid_paradise.Po + -rm -f ./$(DEPDIR)/pcem-vid_pc1512.Po + -rm -f ./$(DEPDIR)/pcem-vid_pc1640.Po + -rm -f ./$(DEPDIR)/pcem-vid_pc200.Po + -rm -f ./$(DEPDIR)/pcem-vid_pcjr.Po + -rm -f ./$(DEPDIR)/pcem-vid_pgc.Po + -rm -f ./$(DEPDIR)/pcem-vid_ps1_svga.Po + -rm -f ./$(DEPDIR)/pcem-vid_s3.Po + -rm -f ./$(DEPDIR)/pcem-vid_s3_virge.Po + -rm -f ./$(DEPDIR)/pcem-vid_sdac_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_sigma.Po + -rm -f ./$(DEPDIR)/pcem-vid_stg_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_svga.Po + -rm -f ./$(DEPDIR)/pcem-vid_svga_render.Po + -rm -f ./$(DEPDIR)/pcem-vid_t1000.Po + -rm -f ./$(DEPDIR)/pcem-vid_t3100e.Po + -rm -f ./$(DEPDIR)/pcem-vid_tandy.Po + -rm -f ./$(DEPDIR)/pcem-vid_tandysl.Po + -rm -f ./$(DEPDIR)/pcem-vid_tgui9440.Po + -rm -f ./$(DEPDIR)/pcem-vid_tkd8001_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_tvga.Po + -rm -f ./$(DEPDIR)/pcem-vid_unk_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_vga.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_banshee.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_blitter.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_display.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_fb.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_fifo.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_reg.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_render.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_setup.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_texture.Po + -rm -f ./$(DEPDIR)/pcem-vid_wy700.Po + -rm -f ./$(DEPDIR)/pcem-video.Po + -rm -f ./$(DEPDIR)/pcem-vl82c480.Po + -rm -f ./$(DEPDIR)/pcem-vt82c586b.Po + -rm -f ./$(DEPDIR)/pcem-w83877tf.Po + -rm -f ./$(DEPDIR)/pcem-w83977tf.Po + -rm -f ./$(DEPDIR)/pcem-wd76c10.Po + -rm -f ./$(DEPDIR)/pcem-wx-app.Po + -rm -f ./$(DEPDIR)/pcem-wx-common.Po + -rm -f ./$(DEPDIR)/pcem-wx-config.Po + -rm -f ./$(DEPDIR)/pcem-wx-config_sel.Po + -rm -f ./$(DEPDIR)/pcem-wx-createdisc.Po + -rm -f ./$(DEPDIR)/pcem-wx-deviceconfig.Po + -rm -f ./$(DEPDIR)/pcem-wx-dialogbox.Po + -rm -f ./$(DEPDIR)/pcem-wx-glslp-parser.Po + -rm -f ./$(DEPDIR)/pcem-wx-hostconfig.Po + -rm -f ./$(DEPDIR)/pcem-wx-joystickconfig.Po + -rm -f ./$(DEPDIR)/pcem-wx-main.Po + -rm -f ./$(DEPDIR)/pcem-wx-resources.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-display-win.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-display.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-joystick.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-keyboard.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-midi.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-mouse.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-status.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-video-gl3.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-video-renderer.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-video.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2.Po + -rm -f ./$(DEPDIR)/pcem-wx-shader_man.Po + -rm -f ./$(DEPDIR)/pcem-wx-shaderconfig.Po + -rm -f ./$(DEPDIR)/pcem-wx-status.Po + -rm -f ./$(DEPDIR)/pcem-wx-thread.Po + -rm -f ./$(DEPDIR)/pcem-wx-utils.Po + -rm -f ./$(DEPDIR)/pcem-x86seg.Po + -rm -f ./$(DEPDIR)/pcem-x87.Po + -rm -f ./$(DEPDIR)/pcem-x87_timings.Po + -rm -f ./$(DEPDIR)/pcem-xi8088.Po + -rm -f ./$(DEPDIR)/pcem-xtide.Po + -rm -f dosbox/$(DEPDIR)/pcem-cdrom_image.Po + -rm -f dosbox/$(DEPDIR)/pcem-dbopl.Po + -rm -f dosbox/$(DEPDIR)/pcem-nukedopl.Po + -rm -f dosbox/$(DEPDIR)/pcem-vid_cga_comp.Po + -rm -f minivhd/$(DEPDIR)/pcem-cwalk.Po + -rm -f minivhd/$(DEPDIR)/pcem-libxml2_encoding.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_convert.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_create.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_io.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_manage.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_util.Po + -rm -f resid-fp/$(DEPDIR)/pcem-convolve-sse.Po + -rm -f resid-fp/$(DEPDIR)/pcem-convolve.Po + -rm -f resid-fp/$(DEPDIR)/pcem-envelope.Po + -rm -f resid-fp/$(DEPDIR)/pcem-extfilt.Po + -rm -f resid-fp/$(DEPDIR)/pcem-filter.Po + -rm -f resid-fp/$(DEPDIR)/pcem-pot.Po + -rm -f resid-fp/$(DEPDIR)/pcem-sid.Po + -rm -f resid-fp/$(DEPDIR)/pcem-voice.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave6581_PST.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave6581__ST.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave8580_PST.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave8580__ST.Po + -rm -f slirp/$(DEPDIR)/pcem-bootp.Po + -rm -f slirp/$(DEPDIR)/pcem-cksum.Po + -rm -f slirp/$(DEPDIR)/pcem-debug.Po + -rm -f slirp/$(DEPDIR)/pcem-if.Po + -rm -f slirp/$(DEPDIR)/pcem-ip_icmp.Po + -rm -f slirp/$(DEPDIR)/pcem-ip_input.Po + -rm -f slirp/$(DEPDIR)/pcem-ip_output.Po + -rm -f slirp/$(DEPDIR)/pcem-mbuf.Po + -rm -f slirp/$(DEPDIR)/pcem-misc.Po + -rm -f slirp/$(DEPDIR)/pcem-queue.Po + -rm -f slirp/$(DEPDIR)/pcem-sbuf.Po + -rm -f slirp/$(DEPDIR)/pcem-slirp.Po + -rm -f slirp/$(DEPDIR)/pcem-socket.Po + -rm -f slirp/$(DEPDIR)/pcem-tcp_input.Po + -rm -f slirp/$(DEPDIR)/pcem-tcp_output.Po + -rm -f slirp/$(DEPDIR)/pcem-tcp_subr.Po + -rm -f slirp/$(DEPDIR)/pcem-tcp_timer.Po + -rm -f slirp/$(DEPDIR)/pcem-tftp.Po + -rm -f slirp/$(DEPDIR)/pcem-udp.Po -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-tags @@ -3551,7 +7169,362 @@ install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) + -rm -f ./$(DEPDIR)/pcem-386.Po + -rm -f ./$(DEPDIR)/pcem-386_common.Po + -rm -f ./$(DEPDIR)/pcem-386_dynarec.Po + -rm -f ./$(DEPDIR)/pcem-386_dynarec_ops.Po + -rm -f ./$(DEPDIR)/pcem-808x.Po + -rm -f ./$(DEPDIR)/pcem-82091aa.Po + -rm -f ./$(DEPDIR)/pcem-acc2036.Po + -rm -f ./$(DEPDIR)/pcem-acc2168.Po + -rm -f ./$(DEPDIR)/pcem-acc3221.Po + -rm -f ./$(DEPDIR)/pcem-acer386sx.Po + -rm -f ./$(DEPDIR)/pcem-ali1429.Po + -rm -f ./$(DEPDIR)/pcem-amstrad.Po + -rm -f ./$(DEPDIR)/pcem-cassette.Po + -rm -f ./$(DEPDIR)/pcem-cbm_io.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-image.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-ioctl-dummy.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-ioctl-linux.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-ioctl-osx.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-ioctl.Po + -rm -f ./$(DEPDIR)/pcem-cdrom-null.Po + -rm -f ./$(DEPDIR)/pcem-cmd640.Po + -rm -f ./$(DEPDIR)/pcem-codegen.Po + -rm -f ./$(DEPDIR)/pcem-codegen_accumulate.Po + -rm -f ./$(DEPDIR)/pcem-codegen_allocator.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm64.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm64_imm.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm64_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm64_uops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_arm_uops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86-64.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86-64_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86-64_ops_sse.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86-64_uops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86_ops_fpu.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86_ops_sse.Po + -rm -f ./$(DEPDIR)/pcem-codegen_backend_x86_uops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_block.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ir.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_3dnow.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_arith.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_branch.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_fpu_arith.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_fpu_constant.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_fpu_loadstore.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_fpu_misc.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_helpers.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_jump.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_logic.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_misc.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_arith.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_cmp.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_loadstore.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_logic.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_pack.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mmx_shift.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_mov.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_shift.Po + -rm -f ./$(DEPDIR)/pcem-codegen_ops_stack.Po + -rm -f ./$(DEPDIR)/pcem-codegen_reg.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_486.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_686.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_common.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_cyrixiii.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_k6.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_p6.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_pentium.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_winchip.Po + -rm -f ./$(DEPDIR)/pcem-codegen_timing_winchip2.Po + -rm -f ./$(DEPDIR)/pcem-compaq.Po + -rm -f ./$(DEPDIR)/pcem-config.Po + -rm -f ./$(DEPDIR)/pcem-cpu.Po + -rm -f ./$(DEPDIR)/pcem-cpu_tables.Po + -rm -f ./$(DEPDIR)/pcem-cs8230.Po + -rm -f ./$(DEPDIR)/pcem-dells200.Po + -rm -f ./$(DEPDIR)/pcem-device.Po + -rm -f ./$(DEPDIR)/pcem-disc.Po + -rm -f ./$(DEPDIR)/pcem-disc_fdi.Po + -rm -f ./$(DEPDIR)/pcem-disc_img.Po + -rm -f ./$(DEPDIR)/pcem-disc_sector.Po + -rm -f ./$(DEPDIR)/pcem-dma.Po + -rm -f ./$(DEPDIR)/pcem-esdi_at.Po + -rm -f ./$(DEPDIR)/pcem-f82c710_upc.Po + -rm -f ./$(DEPDIR)/pcem-fdc.Po + -rm -f ./$(DEPDIR)/pcem-fdc37c665.Po + -rm -f ./$(DEPDIR)/pcem-fdc37c93x.Po + -rm -f ./$(DEPDIR)/pcem-fdd.Po + -rm -f ./$(DEPDIR)/pcem-fdi2raw.Po + -rm -f ./$(DEPDIR)/pcem-gameport.Po + -rm -f ./$(DEPDIR)/pcem-hdd.Po + -rm -f ./$(DEPDIR)/pcem-hdd_esdi.Po + -rm -f ./$(DEPDIR)/pcem-hdd_file.Po + -rm -f ./$(DEPDIR)/pcem-headland.Po + -rm -f ./$(DEPDIR)/pcem-i430fx.Po + -rm -f ./$(DEPDIR)/pcem-i430hx.Po + -rm -f ./$(DEPDIR)/pcem-i430lx.Po + -rm -f ./$(DEPDIR)/pcem-i430vx.Po + -rm -f ./$(DEPDIR)/pcem-i440bx.Po + -rm -f ./$(DEPDIR)/pcem-i440fx.Po + -rm -f ./$(DEPDIR)/pcem-ide.Po + -rm -f ./$(DEPDIR)/pcem-ide_atapi.Po + -rm -f ./$(DEPDIR)/pcem-ide_sff8038i.Po + -rm -f ./$(DEPDIR)/pcem-intel.Po + -rm -f ./$(DEPDIR)/pcem-intel_flash.Po + -rm -f ./$(DEPDIR)/pcem-io.Po + -rm -f ./$(DEPDIR)/pcem-jim.Po + -rm -f ./$(DEPDIR)/pcem-joystick_ch_flightstick_pro.Po + -rm -f ./$(DEPDIR)/pcem-joystick_standard.Po + -rm -f ./$(DEPDIR)/pcem-joystick_sw_pad.Po + -rm -f ./$(DEPDIR)/pcem-joystick_tm_fcs.Po + -rm -f ./$(DEPDIR)/pcem-keyboard.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_amstrad.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_at.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_olim24.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_pcjr.Po + -rm -f ./$(DEPDIR)/pcem-keyboard_xt.Po + -rm -f ./$(DEPDIR)/pcem-laserxt.Po + -rm -f ./$(DEPDIR)/pcem-lpt.Po + -rm -f ./$(DEPDIR)/pcem-lpt_dac.Po + -rm -f ./$(DEPDIR)/pcem-lpt_dss.Po + -rm -f ./$(DEPDIR)/pcem-mca.Po + -rm -f ./$(DEPDIR)/pcem-mcr.Po + -rm -f ./$(DEPDIR)/pcem-mem.Po + -rm -f ./$(DEPDIR)/pcem-mem_bios.Po + -rm -f ./$(DEPDIR)/pcem-mfm_at.Po + -rm -f ./$(DEPDIR)/pcem-mfm_xebec.Po + -rm -f ./$(DEPDIR)/pcem-midi_alsa.Po + -rm -f ./$(DEPDIR)/pcem-model.Po + -rm -f ./$(DEPDIR)/pcem-mouse.Po + -rm -f ./$(DEPDIR)/pcem-mouse_msystems.Po + -rm -f ./$(DEPDIR)/pcem-mouse_ps2.Po + -rm -f ./$(DEPDIR)/pcem-mouse_serial.Po + -rm -f ./$(DEPDIR)/pcem-mvp3.Po + -rm -f ./$(DEPDIR)/pcem-ne2000.Po + -rm -f ./$(DEPDIR)/pcem-neat.Po + -rm -f ./$(DEPDIR)/pcem-nethandler.Po + -rm -f ./$(DEPDIR)/pcem-nmi.Po + -rm -f ./$(DEPDIR)/pcem-nvr.Po + -rm -f ./$(DEPDIR)/pcem-nvr_tc8521.Po + -rm -f ./$(DEPDIR)/pcem-olivetti_m24.Po + -rm -f ./$(DEPDIR)/pcem-opti495.Po + -rm -f ./$(DEPDIR)/pcem-paths.Po + -rm -f ./$(DEPDIR)/pcem-pc.Po + -rm -f ./$(DEPDIR)/pcem-pc87306.Po + -rm -f ./$(DEPDIR)/pcem-pc87307.Po + -rm -f ./$(DEPDIR)/pcem-pci.Po + -rm -f ./$(DEPDIR)/pcem-pic.Po + -rm -f ./$(DEPDIR)/pcem-piix.Po + -rm -f ./$(DEPDIR)/pcem-piix_pm.Po + -rm -f ./$(DEPDIR)/pcem-pit.Po + -rm -f ./$(DEPDIR)/pcem-ppi.Po + -rm -f ./$(DEPDIR)/pcem-ps1.Po + -rm -f ./$(DEPDIR)/pcem-ps2.Po + -rm -f ./$(DEPDIR)/pcem-ps2_mca.Po + -rm -f ./$(DEPDIR)/pcem-ps2_nvr.Po + -rm -f ./$(DEPDIR)/pcem-pzx.Po + -rm -f ./$(DEPDIR)/pcem-rom.Po + -rm -f ./$(DEPDIR)/pcem-rtc.Po + -rm -f ./$(DEPDIR)/pcem-rtc_tc8521.Po + -rm -f ./$(DEPDIR)/pcem-scamp.Po + -rm -f ./$(DEPDIR)/pcem-scat.Po + -rm -f ./$(DEPDIR)/pcem-scsi.Po + -rm -f ./$(DEPDIR)/pcem-scsi_53c400.Po + -rm -f ./$(DEPDIR)/pcem-scsi_aha1540.Po + -rm -f ./$(DEPDIR)/pcem-scsi_cd.Po + -rm -f ./$(DEPDIR)/pcem-scsi_hd.Po + -rm -f ./$(DEPDIR)/pcem-scsi_ibm.Po + -rm -f ./$(DEPDIR)/pcem-scsi_zip.Po + -rm -f ./$(DEPDIR)/pcem-serial.Po + -rm -f ./$(DEPDIR)/pcem-sio.Po + -rm -f ./$(DEPDIR)/pcem-sis496.Po + -rm -f ./$(DEPDIR)/pcem-sl82c460.Po + -rm -f ./$(DEPDIR)/pcem-sound.Po + -rm -f ./$(DEPDIR)/pcem-sound_ad1848.Po + -rm -f ./$(DEPDIR)/pcem-sound_adlib.Po + -rm -f ./$(DEPDIR)/pcem-sound_adlibgold.Po + -rm -f ./$(DEPDIR)/pcem-sound_audiopci.Po + -rm -f ./$(DEPDIR)/pcem-sound_azt2316a.Po + -rm -f ./$(DEPDIR)/pcem-sound_cms.Po + -rm -f ./$(DEPDIR)/pcem-sound_dbopl.Po + -rm -f ./$(DEPDIR)/pcem-sound_emu8k.Po + -rm -f ./$(DEPDIR)/pcem-sound_gus.Po + -rm -f ./$(DEPDIR)/pcem-sound_mpu401_uart.Po + -rm -f ./$(DEPDIR)/pcem-sound_opl.Po + -rm -f ./$(DEPDIR)/pcem-sound_pas16.Po + -rm -f ./$(DEPDIR)/pcem-sound_ps1.Po + -rm -f ./$(DEPDIR)/pcem-sound_pssj.Po + -rm -f ./$(DEPDIR)/pcem-sound_resid.Po + -rm -f ./$(DEPDIR)/pcem-sound_sb.Po + -rm -f ./$(DEPDIR)/pcem-sound_sb_dsp.Po + -rm -f ./$(DEPDIR)/pcem-sound_sn76489.Po + -rm -f ./$(DEPDIR)/pcem-sound_speaker.Po + -rm -f ./$(DEPDIR)/pcem-sound_ssi2001.Po + -rm -f ./$(DEPDIR)/pcem-sound_wss.Po + -rm -f ./$(DEPDIR)/pcem-sound_ym7128.Po + -rm -f ./$(DEPDIR)/pcem-soundopenal.Po + -rm -f ./$(DEPDIR)/pcem-sst39sf010.Po + -rm -f ./$(DEPDIR)/pcem-superxt.Po + -rm -f ./$(DEPDIR)/pcem-t1000.Po + -rm -f ./$(DEPDIR)/pcem-t3100e.Po + -rm -f ./$(DEPDIR)/pcem-tandy_eeprom.Po + -rm -f ./$(DEPDIR)/pcem-tandy_rom.Po + -rm -f ./$(DEPDIR)/pcem-timer.Po + -rm -f ./$(DEPDIR)/pcem-um8669f.Po + -rm -f ./$(DEPDIR)/pcem-um8881f.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati18800.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati28800.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati68860_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati_eeprom.Po + -rm -f ./$(DEPDIR)/pcem-vid_ati_mach64.Po + -rm -f ./$(DEPDIR)/pcem-vid_cga.Po + -rm -f ./$(DEPDIR)/pcem-vid_cl5429.Po + -rm -f ./$(DEPDIR)/pcem-vid_colorplus.Po + -rm -f ./$(DEPDIR)/pcem-vid_compaq_cga.Po + -rm -f ./$(DEPDIR)/pcem-vid_ddc.Po + -rm -f ./$(DEPDIR)/pcem-vid_ega.Po + -rm -f ./$(DEPDIR)/pcem-vid_et4000.Po + -rm -f ./$(DEPDIR)/pcem-vid_et4000w32.Po + -rm -f ./$(DEPDIR)/pcem-vid_genius.Po + -rm -f ./$(DEPDIR)/pcem-vid_hercules.Po + -rm -f ./$(DEPDIR)/pcem-vid_ht216.Po + -rm -f ./$(DEPDIR)/pcem-vid_icd2061.Po + -rm -f ./$(DEPDIR)/pcem-vid_ics2595.Po + -rm -f ./$(DEPDIR)/pcem-vid_im1024.Po + -rm -f ./$(DEPDIR)/pcem-vid_incolor.Po + -rm -f ./$(DEPDIR)/pcem-vid_mda.Po + -rm -f ./$(DEPDIR)/pcem-vid_mga.Po + -rm -f ./$(DEPDIR)/pcem-vid_olivetti_m24.Po + -rm -f ./$(DEPDIR)/pcem-vid_oti037.Po + -rm -f ./$(DEPDIR)/pcem-vid_oti067.Po + -rm -f ./$(DEPDIR)/pcem-vid_paradise.Po + -rm -f ./$(DEPDIR)/pcem-vid_pc1512.Po + -rm -f ./$(DEPDIR)/pcem-vid_pc1640.Po + -rm -f ./$(DEPDIR)/pcem-vid_pc200.Po + -rm -f ./$(DEPDIR)/pcem-vid_pcjr.Po + -rm -f ./$(DEPDIR)/pcem-vid_pgc.Po + -rm -f ./$(DEPDIR)/pcem-vid_ps1_svga.Po + -rm -f ./$(DEPDIR)/pcem-vid_s3.Po + -rm -f ./$(DEPDIR)/pcem-vid_s3_virge.Po + -rm -f ./$(DEPDIR)/pcem-vid_sdac_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_sigma.Po + -rm -f ./$(DEPDIR)/pcem-vid_stg_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_svga.Po + -rm -f ./$(DEPDIR)/pcem-vid_svga_render.Po + -rm -f ./$(DEPDIR)/pcem-vid_t1000.Po + -rm -f ./$(DEPDIR)/pcem-vid_t3100e.Po + -rm -f ./$(DEPDIR)/pcem-vid_tandy.Po + -rm -f ./$(DEPDIR)/pcem-vid_tandysl.Po + -rm -f ./$(DEPDIR)/pcem-vid_tgui9440.Po + -rm -f ./$(DEPDIR)/pcem-vid_tkd8001_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_tvga.Po + -rm -f ./$(DEPDIR)/pcem-vid_unk_ramdac.Po + -rm -f ./$(DEPDIR)/pcem-vid_vga.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_banshee.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_banshee_blitter.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_blitter.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_display.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_fb.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_fifo.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_reg.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_render.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_setup.Po + -rm -f ./$(DEPDIR)/pcem-vid_voodoo_texture.Po + -rm -f ./$(DEPDIR)/pcem-vid_wy700.Po + -rm -f ./$(DEPDIR)/pcem-video.Po + -rm -f ./$(DEPDIR)/pcem-vl82c480.Po + -rm -f ./$(DEPDIR)/pcem-vt82c586b.Po + -rm -f ./$(DEPDIR)/pcem-w83877tf.Po + -rm -f ./$(DEPDIR)/pcem-w83977tf.Po + -rm -f ./$(DEPDIR)/pcem-wd76c10.Po + -rm -f ./$(DEPDIR)/pcem-wx-app.Po + -rm -f ./$(DEPDIR)/pcem-wx-common.Po + -rm -f ./$(DEPDIR)/pcem-wx-config.Po + -rm -f ./$(DEPDIR)/pcem-wx-config_sel.Po + -rm -f ./$(DEPDIR)/pcem-wx-createdisc.Po + -rm -f ./$(DEPDIR)/pcem-wx-deviceconfig.Po + -rm -f ./$(DEPDIR)/pcem-wx-dialogbox.Po + -rm -f ./$(DEPDIR)/pcem-wx-glslp-parser.Po + -rm -f ./$(DEPDIR)/pcem-wx-hostconfig.Po + -rm -f ./$(DEPDIR)/pcem-wx-joystickconfig.Po + -rm -f ./$(DEPDIR)/pcem-wx-main.Po + -rm -f ./$(DEPDIR)/pcem-wx-resources.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-display-win.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-display.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-joystick.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-keyboard.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-midi.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-mouse.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-status.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-video-gl3.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-video-renderer.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2-video.Po + -rm -f ./$(DEPDIR)/pcem-wx-sdl2.Po + -rm -f ./$(DEPDIR)/pcem-wx-shader_man.Po + -rm -f ./$(DEPDIR)/pcem-wx-shaderconfig.Po + -rm -f ./$(DEPDIR)/pcem-wx-status.Po + -rm -f ./$(DEPDIR)/pcem-wx-thread.Po + -rm -f ./$(DEPDIR)/pcem-wx-utils.Po + -rm -f ./$(DEPDIR)/pcem-x86seg.Po + -rm -f ./$(DEPDIR)/pcem-x87.Po + -rm -f ./$(DEPDIR)/pcem-x87_timings.Po + -rm -f ./$(DEPDIR)/pcem-xi8088.Po + -rm -f ./$(DEPDIR)/pcem-xtide.Po + -rm -f dosbox/$(DEPDIR)/pcem-cdrom_image.Po + -rm -f dosbox/$(DEPDIR)/pcem-dbopl.Po + -rm -f dosbox/$(DEPDIR)/pcem-nukedopl.Po + -rm -f dosbox/$(DEPDIR)/pcem-vid_cga_comp.Po + -rm -f minivhd/$(DEPDIR)/pcem-cwalk.Po + -rm -f minivhd/$(DEPDIR)/pcem-libxml2_encoding.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_convert.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_create.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_io.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_manage.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_struct_rw.Po + -rm -f minivhd/$(DEPDIR)/pcem-minivhd_util.Po + -rm -f resid-fp/$(DEPDIR)/pcem-convolve-sse.Po + -rm -f resid-fp/$(DEPDIR)/pcem-convolve.Po + -rm -f resid-fp/$(DEPDIR)/pcem-envelope.Po + -rm -f resid-fp/$(DEPDIR)/pcem-extfilt.Po + -rm -f resid-fp/$(DEPDIR)/pcem-filter.Po + -rm -f resid-fp/$(DEPDIR)/pcem-pot.Po + -rm -f resid-fp/$(DEPDIR)/pcem-sid.Po + -rm -f resid-fp/$(DEPDIR)/pcem-voice.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave6581_PST.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave6581_PS_.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave6581_P_T.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave6581__ST.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave8580_PST.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave8580_PS_.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave8580_P_T.Po + -rm -f resid-fp/$(DEPDIR)/pcem-wave8580__ST.Po + -rm -f slirp/$(DEPDIR)/pcem-bootp.Po + -rm -f slirp/$(DEPDIR)/pcem-cksum.Po + -rm -f slirp/$(DEPDIR)/pcem-debug.Po + -rm -f slirp/$(DEPDIR)/pcem-if.Po + -rm -f slirp/$(DEPDIR)/pcem-ip_icmp.Po + -rm -f slirp/$(DEPDIR)/pcem-ip_input.Po + -rm -f slirp/$(DEPDIR)/pcem-ip_output.Po + -rm -f slirp/$(DEPDIR)/pcem-mbuf.Po + -rm -f slirp/$(DEPDIR)/pcem-misc.Po + -rm -f slirp/$(DEPDIR)/pcem-queue.Po + -rm -f slirp/$(DEPDIR)/pcem-sbuf.Po + -rm -f slirp/$(DEPDIR)/pcem-slirp.Po + -rm -f slirp/$(DEPDIR)/pcem-socket.Po + -rm -f slirp/$(DEPDIR)/pcem-tcp_input.Po + -rm -f slirp/$(DEPDIR)/pcem-tcp_output.Po + -rm -f slirp/$(DEPDIR)/pcem-tcp_subr.Po + -rm -f slirp/$(DEPDIR)/pcem-tcp_timer.Po + -rm -f slirp/$(DEPDIR)/pcem-tftp.Po + -rm -f slirp/$(DEPDIR)/pcem-udp.Po -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic @@ -3571,7 +7544,7 @@ uninstall-am: uninstall-binPROGRAMS .MAKE: install-am install-strip -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean \ +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ clean-binPROGRAMS clean-generic cscopelist-am ctags ctags-am \ distclean distclean-compile distclean-generic distclean-tags \ distdir dvi dvi-am html html-am info info-am install \ @@ -3587,11 +7560,23 @@ uninstall-am: uninstall-binPROGRAMS .PRECIOUS: Makefile - -../pcem: pcem - cp pcem .. +@OS_WINDOWS_FALSE@../pcem: pcem +@OS_WINDOWS_FALSE@ cp pcem .. amrefresh: +wx.res: wx.rc + $(WINDRES) -i wx.rc --input-format=rc -o wx.res -O coff + +wx-resources.cpp : pc.xrc + -wxrc -c pc.xrc -o wx-resources.cpp + +#pcem_CFLAGS += -mtune=cortex-a53 +#pcem_CXXFLAGS += -mtune=cortex-a53 +#pcem_LDFLAGS = -flto -O3 -mtune=cortex-a15 + +# pcem_CFLAGS += -fprofile-use +# pcem_CXXFLAGS += -fprofile-use +# pcem_LDFLAGS = -fprofile-use # 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. diff --git a/src/Makefile.linux32 b/src/Makefile.linux32 deleted file mode 100644 index 622d3f8..0000000 --- a/src/Makefile.linux32 +++ /dev/null @@ -1,47 +0,0 @@ -VPATH = . dosbox resid-fp -CPP = g++ -CC = gcc -CFLAGS = -O3 -fomit-frame-pointer -msse2 -m32 -LDFLAGS = -m32 -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o allegro-gui.o \ -allegro-gui-configure.o allegro-gui-deviceconfig.o allegro-gui-hdconf.o allegro-joystick.o allegro-keyboard.o allegro-main.o \ -allegro-midi.o allegro-mouse.o allegro-video.o amstrad.o cdrom-ioctl-linux.o cdrom-iso.o cdrom-null.o \ -codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.c compaq.o config.o cpu.o \ -dac.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \ -hdd.o hdd_esdi.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ -joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ -lpt.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ -opti495.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o serial.o sis496.o sound.o \ -sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ -sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ -sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o thread-pthread.o \ -timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ -vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o vid_et4000w32.o vid_genius.o vid_hercules.o \ -vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc200.o \ -vid_pc1512.o vid_pc1640.o vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o \ -vid_stg_ramdac.o vid_svga.o vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o \ -vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o vid_wy700.o vid_voodoo.o video.o wd76c10.o \ -x86seg.o x87.o xtide.o sound_dbopl.o sound_resid.o -DBOBJ = dbopl.o vid_cga_comp.o -SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o - - -LIBS = -lopenal -lstdc++ -lalleg -lpthread -lm - -PCem: $(OBJ) $(DBOBJ) $(SIDOBJ) - $(CC) $(LDFLAGS) $(OBJ) $(DBOBJ) $(SIDOBJ) -o "PCem" $(LIBS) - -all : PCem - -clean : - rm *.o - rm PCem - -%.o : %.c - $(CC) $(CFLAGS) -c $< - -%.o : %.cc - $(CPP) $(CFLAGS) -c $< - -%.o : %.cpp - $(CPP) $(CFLAGS) -c $< diff --git a/src/Makefile.linux64 b/src/Makefile.linux64 deleted file mode 100644 index 2c5d4c7..0000000 --- a/src/Makefile.linux64 +++ /dev/null @@ -1,46 +0,0 @@ -VPATH = . dosbox resid-fp -CPP = g++ -CC = gcc -CFLAGS = -O3 -fomit-frame-pointer -msse2 -m64 -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o allegro-gui.o \ -allegro-gui-configure.o allegro-gui-deviceconfig.o allegro-gui-hdconf.o allegro-joystick.o allegro-keyboard.o allegro-main.o \ -allegro-midi.o allegro-mouse.o allegro-video.o amstrad.o cdrom-ioctl-linux.o cdrom-iso.o cdrom-null.o \ -codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.c compaq.o config.o cpu.o \ -dac.o device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o \ -hdd.o hdd_esdi.o headland.o i430lx.o i430fx.o i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o \ -joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o \ -lpt.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_ps2.o mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o \ -opti495.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o scat.o serial.o sis496.o sound.o \ -sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_emu8k.o sound_gus.o \ -sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_sb.o sound_sb_dsp.o sound_sn76489.o \ -sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o thread-pthread.o \ -timer.o um8669f.o um8881f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o \ -vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o vid_et4000w32.o vid_genius.o vid_hercules.o \ -vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc200.o \ -vid_pc1512.o vid_pc1640.o vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o \ -vid_stg_ramdac.o vid_svga.o vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o \ -vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o vid_voodoo.o vid_wy700.o video.o wd76c10.o \ -x86seg.o x87.o xtide.o sound_dbopl.o sound_resid.o -DBOBJ = dbopl.o vid_cga_comp.o -SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o - - -LIBS = -lopenal -lstdc++ -lalleg -lpthread -lm - -PCem64: $(OBJ) $(DBOBJ) $(SIDOBJ) - $(CC) $(OBJ) $(DBOBJ) $(SIDOBJ) -o "PCem64" $(LIBS) - -all : PCem64 - -clean : - rm *.o - rm PCem64 - -%.o : %.c - $(CC) $(CFLAGS) -c $< - -%.o : %.cc - $(CPP) $(CFLAGS) -c $< - -%.o : %.cpp - $(CPP) $(CFLAGS) -c $< diff --git a/src/Makefile.mingw b/src/Makefile.mingw deleted file mode 100644 index 9d143f9..0000000 --- a/src/Makefile.mingw +++ /dev/null @@ -1,47 +0,0 @@ -VPATH = . dosbox resid-fp -CPP = g++.exe -CC = gcc.exe -WINDRES = windres.exe -CFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -Wall -Werror -fno-strict-aliasing -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ - codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86.o compaq.o config.o cpu.o dac.o \ - device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o headland.o i430lx.o i430fx.o \ - i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ - keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_ps2.o \ - mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o \ - scat.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ - sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ - sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ - sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ - vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o \ - vid_et4000w32.o vid_et4000w32i.o vid_genius.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \ - vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ - vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o \ - vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \ - vid_vga.o vid_voodoo.o vid_wy700.o video.o wd76c10.o win.o win-config.o win-config_sel.o win-d3d.o win-d3d-fs.o win-ddraw.o \ - win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-joystickconfig.o win-keyboard.o win-midi.o win-mouse.o \ - win-status.o win-video.o x86seg.o x87.o xtide.o pc.res -DBOBJ = dbopl.o vid_cga_comp.o -SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o - - -LIBS = -mwindows -lwinmm -lopenal32 -lddraw -ldinput -ldxguid -ld3d9 -lstdc++ - -PCem.exe: $(OBJ) $(DBOBJ) $(SIDOBJ) - $(CC) $(OBJ) $(DBOBJ) $(SIDOBJ) -o "PCem.exe" $(LIBS) - -all : PCem.exe - -clean : - rm *.o - rm *.exe - rm *.res - -%.o : %.c - $(CC) $(CFLAGS) -c $< - -%.o : %.cc - $(CPP) $(CFLAGS) -c $< - -pc.res: pc.rc - $(WINDRES) -i pc.rc --input-format=rc -o pc.res -O coff diff --git a/src/Makefile.mingw-wx-sdl2 b/src/Makefile.mingw-wx-sdl2 new file mode 100644 index 0000000..cc37a09 --- /dev/null +++ b/src/Makefile.mingw-wx-sdl2 @@ -0,0 +1,79 @@ +VPATH = . dosbox resid-fp minivhd +CPP = g++ +CC = gcc +WINDRES = windres.exe +WXVERSION = 31 +WXINCLUDE = e:/MinGWget/include/wx/ +CFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -Werror -fno-strict-aliasing +CXXFLAGS = $(CFLAGS) +OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cassette.o \ + cbm_io.o cdrom-ioctl.o cdrom-image.o cmd640.o codegen.o codegen_accumulate.o codegen_allocator.o \ + codegen_backend_x86.o codegen_backend_x86_ops.o codegen_backend_x86_ops_fpu.o codegen_backend_x86_ops_sse.o \ + codegen_backend_x86_uops.o codegen_block.o codegen_ir.o codegen_ops.o \ + codegen_ops_3dnow.o codegen_ops_branch.o codegen_ops_arith.o codegen_ops_fpu_arith.o \ + codegen_ops_fpu_constant.o codegen_ops_fpu_loadstore.o codegen_ops_fpu_misc.o codegen_ops_helpers.o codegen_ops_jump.o \ + codegen_ops_logic.o codegen_ops_misc.o codegen_ops_mmx_arith.o codegen_ops_mmx_cmp.o \ + codegen_ops_mmx_loadstore.o codegen_ops_mmx_logic.o codegen_ops_mmx_pack.o codegen_ops_mmx_shift.o \ + codegen_ops_mov.o codegen_ops_shift.o codegen_ops_stack.o codegen_reg.o codegen_timing_486.o \ + codegen_timing_686.o codegen_timing_common.o codegen_timing_cyrixiii.o codegen_timing_k6.o codegen_timing_p6.o codegen_timing_pentium.o \ + codegen_timing_winchip.o codegen_timing_winchip2.o compaq.o config.o cpu.o cpu_tables.o cs8230.o device.o \ + dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o f82c710_upc.o fdc.o fdc37c665.o fdc37c93x.o fdd.o \ + fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430hx.o i430lx.o i430fx.o i430vx.o i440fx.o i440bx.o ide.o \ + ide_atapi.o ide_sff8038i.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o \ + joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ + keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o \ + mem.o mem_bios.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o \ + mvp3.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pc87307.o pci.o pic.o \ + piix.o piix_pm.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scamp.o scat.o scsi.o \ + scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_ibm.o scsi_zip.o serial.o sio.o sis496.o sl82c460.o \ + sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_azt2316a.o sound_cms.o sound_dbopl.o \ + sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o \ + sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ + sound_ym7128.o soundopenal.o sst39sf010.o superxt.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \ + vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \ + vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ddc.o vid_ega.o vid_et4000.o vid_et4000w32.o \ + vid_et4000w32i.o vid_genius.o vid_hercules.o vid_ht216.o vid_icd2061.o vid_ics2595.o vid_im1024.o vid_incolor.o vid_mda.o \ + vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ + vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \ + vid_svga_render.o vid_t1000.o vid_t3100e.o vid_tandy.o vid_tandysl.o vid_tgui9440.o \ + vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o vid_voodoo.o vid_voodoo_banshee.o vid_voodoo_banshee_blitter.o \ + vid_voodoo_blitter.o vid_voodoo_display.o vid_voodoo_fb.o vid_voodoo_fifo.o vid_voodoo_reg.o \ + vid_voodoo_render.o vid_voodoo_setup.o vid_voodoo_texture.o vid_wy700.o video.o vl82c480.o \ + vt82c586b.o w83877tf.o w83977tf.o wd76c10.o x86seg.o x87.o x87_timings.o xi8088.c xtide.o zenith.o win-midi.o wx-main.o \ + wx-config_sel.o wx-dialogbox.o wx-utils.o wx-app.o wx-sdl2-joystick.o wx-sdl2-mouse.o \ + wx-sdl2-keyboard.o wx-sdl2-video.o wx-sdl2.o wx-config.o wx-deviceconfig.o wx-status.o \ + wx-sdl2-status.o wx-resources.o wx-thread.o wx-common.o wx-sdl2-display-win.o \ + wx-sdl2-video-renderer.o wx-sdl2-video-gl3.o wx-glslp-parser.o wx-shader_man.o wx-shaderconfig.o \ + wx-joystickconfig.o wx-createdisc.o wx.res +DBOBJ = cdrom_image.o dbopl.o nukedopl.o vid_cga_comp.o +SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o +MVHDOBJ = cwalk.o libxml2_encoding.o minivhd_convert.o minivhd_create.o minivhd_io.o minivhd_manage.o minivhd_struct_rw.o minivhd_util.o + +LIBS = -Wl,--subsystem,windows -mthreads -mwindows -lwxmsw$(WXVERSION)u_xrc -lwxmsw$(WXVERSION)u_html -lwxmsw$(WXVERSION)u_adv -lwxbase$(WXVERSION)u_xml -lwxmsw$(WXVERSION)u_core -lwxbase$(WXVERSION)u -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregexu -lwxexpat -lkernel32 -lcomdlg32 -lwinspool -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lmingw32 -lopengl32 -lopenal32 -lstdc++ -lSDL2main -lSDL2 -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -static-libgcc + +PCem-wx-SDL2.exe: $(OBJ) $(DBOBJ) $(SIDOBJ) $(MVHDOBJ) + $(CC) $(OBJ) $(DBOBJ) $(SIDOBJ) $(MVHDOBJ) -o "PCem-wx-SDL2.exe" $(LIBS) + strip -s PCem-wx-SDL2.exe + +all : PCem-wx-SDL2.exe + +clean : + rm *.o + rm PCem-wx-SDL2.exe + rm *.res + +wx-resources.o : pc.xrc + -wxrc -c pc.xrc -o wx-resources.cpp + $(CPP) $(CXXFLAGS) -c wx-resources.cpp + +%.o : %.c + $(CC) $(CFLAGS) -c $< + +%.o : %.cc + $(CPP) $(CXXFLAGS) -c $< + +%.o : %.cpp + $(CPP) $(CXXFLAGS) -c $< + +wx.res: wx.rc + $(WINDRES) -I$(WXINCLUDE)/../ -i wx.rc --input-format=rc -o wx.res -O coff diff --git a/src/Makefile.mingw-wx-sdl2-network b/src/Makefile.mingw-wx-sdl2-network new file mode 100644 index 0000000..c1d7771 --- /dev/null +++ b/src/Makefile.mingw-wx-sdl2-network @@ -0,0 +1,83 @@ +VPATH = . dosbox resid-fp minivhd +CPP = g++ +CC = gcc +WINDRES = windres.exe +WXVERSION = 31 +WXINCLUDE = e:/mingwget/include/wx/ +CFLAGS = -O3 -march=i686 -fomit-frame-pointer -msse2 -mstackrealign -Werror -fno-strict-aliasing -DUSE_NETWORKING +CXXFLAGS = $(CFLAGS) +OBJ = 386.o 386_common.o 386_dynarec.o 386_dynarec_ops.o 808x.o 82091aa.o acc2036.o acc2168.o acc3221.o acer386sx.o ali1429.o amstrad.o cassette.o \ + cbm_io.o cdrom-ioctl.o cdrom-image.o cmd640.o codegen.o codegen_accumulate.o codegen_allocator.o \ + codegen_backend_x86.o codegen_backend_x86_ops.o codegen_backend_x86_ops_fpu.o codegen_backend_x86_ops_sse.o \ + codegen_backend_x86_uops.o codegen_block.o codegen_ir.o codegen_ops.o \ + codegen_ops_3dnow.o codegen_ops_branch.o codegen_ops_arith.o codegen_ops_fpu_arith.o \ + codegen_ops_fpu_constant.o codegen_ops_fpu_loadstore.o codegen_ops_fpu_misc.o codegen_ops_helpers.o codegen_ops_jump.o \ + codegen_ops_logic.o codegen_ops_misc.o codegen_ops_mmx_arith.o codegen_ops_mmx_cmp.o \ + codegen_ops_mmx_loadstore.o codegen_ops_mmx_logic.o codegen_ops_mmx_pack.o codegen_ops_mmx_shift.o \ + codegen_ops_mov.o codegen_ops_shift.o codegen_ops_stack.o codegen_reg.o codegen_timing_486.o \ + codegen_timing_686.o codegen_timing_common.o codegen_timing_cyrixiii.o codegen_timing_k6.o codegen_timing_p6.o codegen_timing_pentium.o \ + codegen_timing_winchip.o codegen_timing_winchip2.o compaq.o config.o cpu.o cpu_tables.o cs8230.o device.o \ + dells200.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o esdi_at.o f82c710_upc.o fdc.o fdc37c665.o fdc37c93x.o fdd.o \ + fdi2raw.o gameport.o hdd.o hdd_esdi.o hdd_file.o headland.o i430hx.o i430lx.o i430fx.o i430vx.o i440fx.o i440bx.o ide.o \ + ide_atapi.o ide_sff8038i.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o \ + joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ + keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o laserxt.o lpt.o lpt_dac.o lpt_dss.o mca.o mcr.o \ + mem.o mem_bios.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_msystems.o mouse_ps2.o mouse_serial.o \ + mvp3.o neat.o nmi.o nvr.o nvr_tc8521.o olivetti_m24.o opti495.o paths.o pc.o pc87306.o pc87307.o pci.o pic.o \ + piix.o piix_pm.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o pzx.o rom.o rtc.o rtc_tc8521.o scamp.o scat.o scsi.o \ + scsi_53c400.o scsi_aha1540.o scsi_cd.o scsi_hd.o scsi_ibm.o scsi_zip.o serial.o sio.o sis496.o sl82c460.o \ + sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_audiopci.o sound_azt2316a.o sound_cms.o sound_dbopl.o \ + sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o \ + sound_resid.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \ + sound_ym7128.o soundopenal.o sst39sf010.o superxt.o t1000.o t3100e.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o \ + vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \ + vid_cl5429.o vid_colorplus.o vid_compaq_cga.o vid_ddc.o vid_ega.o vid_et4000.o vid_et4000w32.o \ + vid_et4000w32i.o vid_genius.o vid_hercules.o vid_ht216.o vid_icd2061.o vid_ics2595.o vid_im1024.o vid_incolor.o vid_mda.o \ + vid_mga.o vid_olivetti_m24.o vid_oti037.c vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ + vid_pcjr.o vid_pgc.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_sigma.o vid_stg_ramdac.o vid_svga.o \ + vid_svga_render.o vid_t1000.o vid_t3100e.o vid_tandy.o vid_tandysl.o vid_tgui9440.o \ + vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o vid_voodoo.o vid_voodoo_banshee.o vid_voodoo_banshee_blitter.o \ + vid_voodoo_blitter.o vid_voodoo_display.o vid_voodoo_fb.o vid_voodoo_fifo.o vid_voodoo_reg.o \ + vid_voodoo_render.o vid_voodoo_setup.o vid_voodoo_texture.o vid_wy700.o video.o vl82c480.o \ + vt82c586b.o w83877tf.o w83977tf.o wd76c10.o x86seg.o x87.o x87_timings.o xi8088.c xtide.o zenith.o win-midi.o wx-main.o \ + wx-config_sel.o wx-dialogbox.o wx-hostconfig.o wx-utils.o wx-app.o wx-sdl2-joystick.o wx-sdl2-mouse.o \ + wx-sdl2-keyboard.o wx-sdl2-video.o wx-sdl2.o wx-config.o wx-deviceconfig.o wx-status.o \ + wx-sdl2-status.o wx-resources.o wx-thread.o wx-common.o wx-sdl2-display-win.o \ + wx-sdl2-video-renderer.o wx-sdl2-video-gl3.o wx-glslp-parser.o wx-shader_man.o wx-shaderconfig.o \ + wx-joystickconfig.o wx-createdisc.o wx.res +DBOBJ = cdrom_image.o dbopl.o nukedopl.o vid_cga_comp.o +SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o +MVHDOBJ = cwalk.o libxml2_encoding.o minivhd_convert.o minivhd_create.o minivhd_io.o minivhd_manage.o minivhd_struct_rw.o minivhd_util.o +NETOBJ = ne2000.o nethandler.o + +LIBS = -Wl,--subsystem,windows -mthreads -mwindows -lwxmsw$(WXVERSION)u_xrc -lwxmsw$(WXVERSION)u_html -lwxmsw$(WXVERSION)u_adv -lwxbase$(WXVERSION)u_xml -lwxmsw$(WXVERSION)u_core -lwxbase$(WXVERSION)u -lwxtiff -lwxjpeg -lwxpng -lwxzlib -lwxregexu -lwxexpat -lkernel32 -lcomdlg32 -lwinspool -lcomctl32 -lole32 -loleaut32 -luuid -lrpcrt4 -ladvapi32 -lmingw32 -lopengl32 -lopenal32 -lstdc++ -lSDL2main -lSDL2 -lm -ldinput8 -ldxguid -ldxerr8 -luser32 -lgdi32 -lwinmm -limm32 -lole32 -loleaut32 -lshell32 -lversion -luuid -static-libgcc -lwsock32 -liphlpapi + +PCem-wx-SDL2.exe: $(OBJ) $(DBOBJ) $(SIDOBJ) $(MVHDOBJ) $(NETOBJ) libslirp.a + $(CC) $(OBJ) $(DBOBJ) $(SIDOBJ) $(MVHDOBJ) $(NETOBJ) slirp/libslirp.a -o "PCem-wx-SDL2.exe" $(LIBS) + strip -s PCem-wx-SDL2.exe + +libslirp.a: + $(MAKE) -C slirp + +all : libslirp.a PCem-wx-SDL2.exe + +clean : + rm *.o + rm PCem-wx-SDL2.exe + rm *.res + +wx-resources.o : pc.xrc + -wxrc -c pc.xrc -o wx-resources.cpp + $(CPP) $(CXXFLAGS) -c wx-resources.cpp + +%.o : %.c + $(CC) $(CFLAGS) -c $< + +%.o : %.cc + $(CPP) $(CXXFLAGS) -c $< + +%.o : %.cpp + $(CPP) $(CXXFLAGS) -c $< + +wx.res: wx.rc + $(WINDRES) -I$(WXINCLUDE)/../ -i wx.rc --input-format=rc -o wx.res -O coff diff --git a/src/Makefile.mingw64 b/src/Makefile.mingw64 deleted file mode 100644 index f55c6e1..0000000 --- a/src/Makefile.mingw64 +++ /dev/null @@ -1,47 +0,0 @@ -VPATH = . dosbox resid-fp -CPP = g++.exe -CC = gcc.exe -WINDRES = windres.exe -CFLAGS = -O3 -fomit-frame-pointer -msse2 -Wall -Werror -fno-strict-aliasing -OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o cdrom-iso.o \ - codegen.o codegen_ops.o codegen_timing_486.o codegen_timing_686.o codegen_timing_pentium.o codegen_timing_winchip.o codegen_x86-64.o compaq.o config.o cpu.o dac.o \ - device.o disc.o disc_fdi.o disc_img.o disc_sector.o dma.o fdc.o fdc37c665.o fdd.o fdi2raw.o gameport.o hdd.o hdd_esdi.o headland.o i430lx.o i430fx.o \ - i430vx.o ide.o intel.o intel_flash.o io.o jim.o joystick_ch_flightstick_pro.o joystick_standard.o joystick_sw_pad.o joystick_tm_fcs.o keyboard.o keyboard_amstrad.o keyboard_at.o \ - keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mca.o mcr.o mem.o mfm_at.o mfm_xebec.o model.o mouse.o mouse_ps2.o \ - mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti495.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o ps2.o ps2_mca.o ps2_nvr.o rom.o rtc.o \ - scat.o serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \ - sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \ - sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \ - soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ - vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_colorplus.o vid_ega.o vid_et4000.o \ - vid_et4000w32.o vid_et4000w32i.o vid_genius.o vid_hercules.o vid_icd2061.o vid_ics2595.o vid_incolor.o vid_mda.o \ - vid_olivetti_m24.o vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o \ - vid_pcjr.o vid_ps1_svga.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o \ - vid_svga_render.o vid_tandy.o vid_tandysl.o vid_tgui9440.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o \ - vid_vga.o vid_voodoo.o vid_wy700.o video.o wd76c10.o win.o win-config.o win-d3d.o win-d3d-fs.o win-ddraw.o \ - win-ddraw-fs.o win-deviceconfig.o win-hdconf.o win-joystick.o win-joystickconfig.o win-keyboard.o win-midi.o win-mouse.o \ - win-status.o win-video.o x86seg.o x87.o xtide.o pc.res -DBOBJ = dbopl.o vid_cga_comp.o -SIDOBJ = convolve.o convolve-sse.o envelope.o extfilt.o filter.o pot.o sid.o voice.o wave6581__ST.o wave6581_P_T.o wave6581_PS_.o wave6581_PST.o wave8580__ST.o wave8580_P_T.o wave8580_PS_.o wave8580_PST.o wave.o - - -LIBS = -mwindows -lwinmm -lopenal32 -lddraw -ldinput -ldxguid -ld3d9 -lstdc++ - -PCem64.exe: $(OBJ) $(DBOBJ) $(SIDOBJ) - $(CC) $(OBJ) $(DBOBJ) $(SIDOBJ) -o "PCem64.exe" $(LIBS) - -all : PCem64.exe - -clean : - rm *.o - rm *.exe - rm *.res - -%.o : %.c - $(CC) $(CFLAGS) -c $< - -%.o : %.cc - $(CPP) $(CFLAGS) -c $< - -pc.res: pc.rc - $(WINDRES) -i pc.rc --input-format=rc -o pc.res -O coff diff --git a/src/acc2036.c b/src/acc2036.c new file mode 100644 index 0000000..faacd9d --- /dev/null +++ b/src/acc2036.c @@ -0,0 +1,102 @@ +#include "ibm.h" +#include "acc2036.h" +#include "io.h" +#include "mem.h" + +static struct +{ + int reg_idx; + uint8_t regs[256]; +} acc2036; + +static void acc2036_shadow_recalc() +{ + if (acc2036.regs[0x2c] & 8) + { + switch (acc2036.regs[0x22] & 3) + { + case 0: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + } + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + if (acc2036.regs[0x2c] & 4) + { + switch (acc2036.regs[0x22] & 3) + { + case 0: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + } + else + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + +static void acc2036_write(uint16_t addr, uint8_t val, void *p) +{ + if (!(addr & 1)) + acc2036.reg_idx = val; + else + { + acc2036.regs[acc2036.reg_idx] = val; +// pclog("Write ACC2036 R%02x %02x %04x:%04x %i\n", acc2036.reg_idx, val, CS,cpu_state.pc, ins); + + switch (acc2036.reg_idx) + { + case 0x22: + case 0x2c: + acc2036_shadow_recalc(); + break; + + case 0x23: + mem_mapping_disable(&ram_remapped_mapping); + if (val & 0x10) + { + if (acc2036.regs[0x2c] & 0xc) + mem_remap_top_256k(); + else + mem_remap_top_384k(); + } + break; + } + } +} + +static uint8_t acc2036_read(uint16_t addr, void *p) +{ + if (!(addr & 1)) + return acc2036.reg_idx; + + if (acc2036.reg_idx >= 0xbc) + return 0xff; + + return acc2036.regs[acc2036.reg_idx]; +} + +void acc2036_init() +{ + memset(&acc2036, 0, sizeof(acc2036)); + io_sethandler(0x00f2, 0x0002, acc2036_read, NULL, NULL, acc2036_write, NULL, NULL, NULL); +} diff --git a/src/acc2036.h b/src/acc2036.h new file mode 100644 index 0000000..40561fa --- /dev/null +++ b/src/acc2036.h @@ -0,0 +1 @@ +void acc2036_init(); diff --git a/src/acc2168.c b/src/acc2168.c new file mode 100644 index 0000000..e6ab7dd --- /dev/null +++ b/src/acc2168.c @@ -0,0 +1,119 @@ +#include "ibm.h" +#include "acc2168.h" +#include "cpu.h" +#include "io.h" +#include "mem.h" +#include "x86.h" + +static struct +{ + int reg_idx; + uint8_t regs[256]; + uint8_t port_62; +} acc2168; + +static void acc2168_shadow_recalc() +{ + if (acc2168.regs[0x02] & 8) + { + switch (acc2168.regs[0x02] & 0x30) + { + case 0x00: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x10: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x30: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + if (acc2168.regs[0x02] & 4) + { + switch (acc2168.regs[0x02] & 0x30) + { + case 0x00: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x10: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x30: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } + else + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + +static void acc2168_write(uint16_t addr, uint8_t val, void *p) +{ +// pclog("acc2168_write: addr=%04x val=%02x\n", addr, val); + if (!(addr & 1)) + acc2168.reg_idx = val; + else + { + acc2168.regs[acc2168.reg_idx] = val; +// pclog("acc2168_write: idx=%02x val=%02x %04x:%04x\n", acc2168.reg_idx, val, CS,cpu_state.pc); + + switch (acc2168.reg_idx) + { + case 0x02: + acc2168_shadow_recalc(); + break; + } + } +} + +static uint8_t acc2168_read(uint16_t addr, void *p) +{ + if (!(addr & 1)) + return acc2168.reg_idx; + +// pclog("acc2168_read: idx=%02x val=%02x\n", acc2168.reg_idx, acc2168.regs[acc2168.reg_idx]); + return acc2168.regs[acc2168.reg_idx]; +} + +static uint8_t port78_read(uint16_t addr, void *p) +{ + return 0; +} + +static uint8_t port92_read(uint16_t addr, void *p) +{ + return acc2168.port_62 | 0xfc; +} + +static void port92_write(uint16_t addr, uint8_t val, void *p) +{ + if ((mem_a20_alt ^ val) & 2) + { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~acc2168.port_62 & val) & 1) + { + softresetx86(); + cpu_set_edx(); + } + acc2168.port_62 = val | 0xfC; +} + +void acc2168_init() +{ + memset(&acc2168, 0, sizeof(acc2168)); + io_sethandler(0x00f2, 0x0002, acc2168_read, NULL, NULL, acc2168_write, NULL, NULL, NULL); + io_sethandler(0x0078, 0x0001, port78_read, NULL, NULL, NULL, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, port92_read, NULL, NULL, port92_write, NULL, NULL, NULL); +} diff --git a/src/acc2168.h b/src/acc2168.h new file mode 100644 index 0000000..93515ee --- /dev/null +++ b/src/acc2168.h @@ -0,0 +1 @@ +void acc2168_init(); diff --git a/src/acc3221.c b/src/acc3221.c new file mode 100644 index 0000000..2b3fb8a --- /dev/null +++ b/src/acc3221.c @@ -0,0 +1,122 @@ +#include "ibm.h" +#include "acc3221.h" +#include "fdc.h" +#include "ide.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" + +static struct +{ + int reg_idx; + uint8_t regs[256]; +} acc3221; + +#define REG_BE_LPT1_DISABLE (1 << 4) + +#define REG_DB_SERIAL1_DISABLE (1 << 4) +#define REG_DB_SERIAL2_DISABLE (1 << 1) + +#define REG_DE_SIRQ3_SOURCE (3 << 6) +#define REG_DE_SIRQ3_SERIAL1 (1 << 6) +#define REG_DE_SIRQ3_SERIAL2 (3 << 6) + +#define REG_DE_SIRQ4_SOURCE (3 << 4) +#define REG_DE_SIRQ4_SERIAL1 (1 << 4) +#define REG_DE_SIRQ4_SERIAL2 (3 << 4) + +#define REG_FB_FDC_DISABLE (1 << 1) + +#define REG_FE_IDE_DISABLE (1 << 1) + +static void acc3221_write(uint16_t addr, uint8_t val, void *p) +{ + if (!(addr & 1)) + acc3221.reg_idx = val; + else + { + acc3221.regs[acc3221.reg_idx] = val; +// pclog("Write ACC2036 R%02x %02x %04x:%04x %i\n", acc2036.reg_idx, val, CS,cpu_state.pc, ins); + + if (acc3221.reg_idx >= 0xbc) + { +// pclog("Write ACC3221 R%02x %02x %04x:%04x %i\n", acc3221.reg_idx, val, CS,cpu_state.pc, ins); + fdc_remove(); + if (!(acc3221.regs[0xfb] & REG_FB_FDC_DISABLE)) + fdc_add(); + + serial1_remove(); + if (!(acc3221.regs[0xdb] & REG_DB_SERIAL1_DISABLE)) + { + uint16_t addr = (acc3221.regs[0xdc] & 0x7f) << 2; + + if ((acc3221.regs[0xde] & REG_DE_SIRQ3_SOURCE) == REG_DE_SIRQ3_SERIAL1) + { +// pclog("COM1 addr %03x IRQ 3\n", addr); + serial1_set(addr, 3); + } + else if ((acc3221.regs[0xde] & REG_DE_SIRQ4_SOURCE) == REG_DE_SIRQ4_SERIAL1) + { +// pclog("COM1 addr %03x IRQ 4\n", addr); + serial1_set(addr, 4); + } +// else +// pclog("COM1 addr %03x no IRQ\n", addr); + } +// else +// pclog("COM1 disabled\n"); + + serial2_remove(); + if (!(acc3221.regs[0xdb] & REG_DB_SERIAL2_DISABLE)) + { + uint16_t addr = (acc3221.regs[0xdd] & 0x7f) << 2; + + if ((acc3221.regs[0xde] & REG_DE_SIRQ3_SOURCE) == REG_DE_SIRQ3_SERIAL2) + { +// pclog("COM2 addr %03x IRQ 3\n", addr); + serial2_set(addr, 3); + } + else if ((acc3221.regs[0xde] & REG_DE_SIRQ4_SOURCE) == REG_DE_SIRQ4_SERIAL2) + { +// pclog("COM2 addr %03x IRQ 4\n", addr); + serial2_set(addr, 4); + } +// else +// pclog("COM2 addr %03x no IRQ\n", addr); + } +// else +// pclog("COM2 disabled\n"); + + lpt1_remove(); + lpt2_remove(); + if (!(acc3221.regs[0xbe] & REG_BE_LPT1_DISABLE)) + { +// pclog("LPT1 addr %03x\n", acc3221.regs[0xbf] << 2); + lpt1_init(acc3221.regs[0xbf] << 2); + } +// else +// pclog("LPT1 disabled\n"); + + ide_pri_disable(); + if (!(acc3221.regs[0xfe] & REG_FE_IDE_DISABLE)) + ide_pri_enable(); + } + } +} + +static uint8_t acc3221_read(uint16_t addr, void *p) +{ + if (!(addr & 1)) + return acc3221.reg_idx; + + if (acc3221.reg_idx < 0xbc) + return 0xff; + + return acc3221.regs[acc3221.reg_idx]; +} + +void acc3221_init() +{ + memset(&acc3221, 0, sizeof(acc3221)); + io_sethandler(0x00f2, 0x0002, acc3221_read, NULL, NULL, acc3221_write, NULL, NULL, NULL); +} diff --git a/src/acc3221.h b/src/acc3221.h new file mode 100644 index 0000000..95824ec --- /dev/null +++ b/src/acc3221.h @@ -0,0 +1 @@ +void acc3221_init(); diff --git a/src/acer386sx.c b/src/acer386sx.c index 77a7ef2..456ef35 100644 --- a/src/acer386sx.c +++ b/src/acer386sx.c @@ -1,22 +1,92 @@ #include "ibm.h" +#include "device.h" #include "io.h" #include "cpu.h" +#include "lpt.h" +#include "mem.h" +#include "serial.h" +#include "vid_oti067.h" #include "acer386sx.h" static int acer_index = 0; static uint8_t acer_regs[256]; +static uint8_t acer_last_write; +static int acer_locked; +static void *acer_oti067; + +void acer386sx_set_oti067(void *oti067) +{ + acer_oti067 = oti067; +} void acer386sx_write(uint16_t addr, uint8_t val, void *priv) { if (addr & 1) - acer_regs[acer_index] = val; + { + if (acer_locked) + { + if (acer_last_write == 0x14 && val == 0x09) + acer_locked = 0; + + acer_last_write = val; + return; + } + + if (acer_index == 0xff && val == 0xff) + acer_locked = 1; + else + { + pclog("Write ACER reg %02x %02x %08x\n", acer_index, val, cs); + acer_regs[acer_index] = val; + + switch (acer_index) + { + case 0xa: + switch ((val >> 4) & 3) + { + case 0: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(0xe0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + break; + case 0xb: + switch ((val >> 4) & 3) + { + case 0: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + break; + } + } + } else - acer_index = val; + acer_index = val; } uint8_t acer386sx_read(uint16_t addr, void *priv) { + if (acer_locked) + return 0xff; if (addr & 1) { if ((acer_index >= 0xc0 || acer_index == 0x20) && cpu_iscyrix) @@ -27,7 +97,60 @@ uint8_t acer386sx_read(uint16_t addr, void *priv) return acer_index; } +static uint8_t acer386sx_37f = 0, acer386sx_io = 0; +void acer386sx_io_write(uint16_t addr, uint8_t val, void *priv) +{ + switch (addr) + { + case 0x37f: + acer386sx_37f = val; + if (val & 4) + oti067_enable_disable(acer_oti067, 0); + else + oti067_enable_disable(acer_oti067, 1); + break; + + case 0x3f3: + acer386sx_io = val; + serial1_remove(); + serial2_remove(); + lpt1_remove(); + lpt2_remove(); + + switch (val & 3) + { + case 0: lpt1_init(0x378); break; + case 1: lpt1_init(0x3bc); break; + case 2: lpt1_init(0x278); break; + } + if (!(val & 0x04)) + serial1_set(0x3f8, 4); + if (!(val & 0x08)) + serial2_set(0x2f8, 3); + break; + } +} + +uint8_t acer386sx_io_read(uint16_t addr, void *priv) +{ + switch (addr) + { + case 0x37f: + return acer386sx_37f; + + case 0x3f3: + return acer386sx_io; + } + + return 0xff; +} + void acer386sx_init() { io_sethandler(0x0022, 0x0002, acer386sx_read, NULL, NULL, acer386sx_write, NULL, NULL, NULL); + io_sethandler(0x037f, 0x0001, acer386sx_io_read, NULL, NULL, acer386sx_io_write, NULL, NULL, NULL); + io_sethandler(0x03f3, 0x0001, acer386sx_io_read, NULL, NULL, acer386sx_io_write, NULL, NULL, NULL); + + acer386sx_io = 0; + acer386sx_37f = 0; } diff --git a/src/acer386sx.h b/src/acer386sx.h index 12d98f1..3d91d5c 100644 --- a/src/acer386sx.h +++ b/src/acer386sx.h @@ -1 +1,2 @@ void acer386sx_init(); +void acer386sx_set_oti067(void *oti067); diff --git a/src/ali1429.c b/src/ali1429.c index 388ab48..099a865 100644 --- a/src/ali1429.c +++ b/src/ali1429.c @@ -55,8 +55,6 @@ void ali1429_write(uint16_t port, uint8_t val, void *priv) ali1429_recalc(); break; case 0x14: - shadowbios = val & 1; - shadowbios_write = val & 2; ali1429_recalc(); break; } diff --git a/src/allegro-gui-config-sel.c b/src/allegro-gui-config-sel.c deleted file mode 100644 index 5f2b7ff..0000000 --- a/src/allegro-gui-config-sel.c +++ /dev/null @@ -1,265 +0,0 @@ -#include "ibm.h" -#include "device.h" -#include "allegro-main.h" -#include "allegro-gui.h" -#include "config.h" -#undef printf -typedef struct config_t -{ - char name[512]; - struct config_t *next; -} config_t; - -static config_t *config_head; - -static char *get_config(int nr); -static int get_config_nr(); -static void free_configs(); -static void populate_configs(); - -static char *list_proc_joystick(int index, int *list_size) -{ - int c = 0; - config_t *config = config_head; - - if (index < 0) - { - while (config) - { - c++; - config = config->next; - } - - *list_size = c; - return NULL; - } - - for (; c < index; c++) - { - if (!config) - return NULL; - config = config->next; - } - - if (!config) - return NULL; - - return config->name; -// return joystick_list[index].name; -} - -static char config_name[256]; - -static DIALOG new_config_dialog[] = -{ - {d_shadow_box_proc, 0, 0, 480,80,0,0xffffff,0,0, 0,0,0,0,0}, // 0 - - {d_button_proc, 240-148, 56, 144, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 - {d_button_proc, 240+4, 56, 144, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 - - {d_edit_proc, 8, 32, 464, 16, 0, 0xffffff, 0, 0, 255, 0, config_name, 0, 0}, // 3 - - {d_text_proc, 240-29*4, 16, 29*8, 16, 0, 0xffffff, 0, 0, 255, 0, "Please type new config name :", 0, 0}, - - {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} -}; - -static int new_proc(int msg, DIALOG *d, int c) -{ - int ret = d_button_proc(msg, d, c); - - if (ret == D_CLOSE) - { - int c; - - config_name[0] = 0; - new_config_dialog[3].d2 = 0; - - position_dialog(new_config_dialog, SCREEN_W/2 - new_config_dialog[0].w/2, SCREEN_H/2 - new_config_dialog[0].h/2); - - c = popup_dialog(new_config_dialog, 1); - - position_dialog(new_config_dialog, -(SCREEN_W/2 - new_config_dialog[0].w/2), -(SCREEN_H/2 - new_config_dialog[0].h/2)); - - if (c == 1) - { - sprintf(config_file_default, "%sconfigs/%s.cfg", pcempath, config_name); - c = settings_configure(); - free_configs(); - populate_configs(); - return c; - } - - return D_O_K; - } - - return ret; -} - -static int config_proc(int msg, DIALOG *d, int c) -{ - int ret = d_button_proc(msg, d, c); - - if (ret == D_CLOSE) - { - char *name = get_config(get_config_nr()); - - if (name) - { - sprintf(config_file_default, "%sconfigs/%s.cfg", pcempath, name); - loadconfig(NULL); - return settings_configure(); - } - - return D_O_K; - } - - return ret; -} - -static int hdd_proc(int msg, DIALOG *d, int c) -{ - int ret = d_button_proc(msg, d, c); - - if (ret == D_CLOSE) - { - char *name = get_config(get_config_nr()); - - if (name) - { - sprintf(config_file_default, "%sconfigs/%s.cfg", pcempath, name); - loadconfig(NULL); - return disc_hdconf(); - } - - return D_O_K; - } - - return ret; -} - -static DIALOG config_sel_dialog[] = -{ - {d_shadow_box_proc, 0, 0, 568,372,0,0xffffff,0,0, 0,0,0,0,0}, // 0 - - {d_button_proc, 416, 8, 144, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Load", 0, 0}, // 1 - {d_button_proc, 416, 348, 144, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Quit", 0, 0}, // 2 - - {new_proc, 416, 56, 144, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "New...", 0, 0}, // 3 - {config_proc, 416, 80, 144, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, // 4 - {hdd_proc, 416, 104, 144, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "HDD...", 0, 0}, // 5 - - {d_list_proc, 8, 8, 400, 356, 0, 0xffffff, 0, 0, 0, 0, list_proc_joystick, 0, 0}, // 6 - - {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} -}; - -static int get_config_nr() -{ - return config_sel_dialog[6].d1; -} - -static void populate_configs() -{ - struct al_ffblk info; - char cfg[512]; - config_t *config = NULL; - - strcpy(cfg, pcempath); - strcat(cfg, "/configs/*.cfg"); - printf("cfg %s\n", cfg); - if (al_findfirst(cfg, &info, FA_ALL)) - return; - - do - { - config_t *old_config = config; - char *ext; - - config = malloc(sizeof(config_t)); - if (old_config) - old_config->next = config; - else - config_head = config; - config->next = 0; - strcpy(config->name, info.name); - - ext = get_extension(config->name); - if (ext && ext[0]) - { - ext--; - *ext = 0; - } - - printf("Found %s\n", info.name); - } while (al_findnext(&info) == 0); - - al_findclose(&info); -} - -static char *get_config(int nr) -{ - config_t *config = config_head; - int c; - - for (c = 0; c < nr; c++) - { - if (!config) - return NULL; - config = config->next; - } - if (!config) - return NULL; - - return config->name; -} - -static void free_configs() -{ - config_t *config = config_head; - - while (config) - { - config_t *old_config = config; - - config = config->next; - free(old_config); - } -} - -int config_sel() -{ - populate_configs(); - set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); - while (1) - { - int c; - - position_dialog(config_sel_dialog, SCREEN_W/2 - config_sel_dialog[0].w/2, SCREEN_H/2 - config_sel_dialog[0].h/2); - - c = popup_dialog(config_sel_dialog, 1); - - position_dialog(config_sel_dialog, -(SCREEN_W/2 - config_sel_dialog[0].w/2), -(SCREEN_H/2 - config_sel_dialog[0].h/2)); - - if (c == 1) - { - char *name = get_config(config_sel_dialog[6].d1); - - if (name) - { - sprintf(config_file_default, "%sconfigs/%s.cfg", pcempath, name); - pclog("config_file_default=%s\n", config_file_default); - free_configs(); - return 0; - } - } - - if (c == 2) - return 1; - } - - free_configs(); - - return 1; -} - diff --git a/src/allegro-gui-configure.c b/src/allegro-gui-configure.c deleted file mode 100644 index cdd16a3..0000000 --- a/src/allegro-gui-configure.c +++ /dev/null @@ -1,837 +0,0 @@ -#include "ibm.h" -#include "device.h" -#include "allegro-main.h" -#include "allegro-gui.h" -#include "cpu.h" -#include "fdd.h" -#include "gameport.h" -#include "hdd.h" -#include "mem.h" -#include "model.h" -#include "mouse.h" -#include "sound.h" -#include "video.h" -#include "vid_voodoo.h" - -static int romstolist[ROM_MAX]; -static int settings_mouse_to_list[20], settings_list_to_mouse[20]; - -typedef struct allegro_list_t -{ - char name[256]; - int num; -} allegro_list_t; - -typedef struct allegro_list_str_t -{ - char name[256]; - char *internal_name; -} allegro_list_str_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 allegro_list_t mouse_list[32]; -static allegro_list_str_t hdd_list[32]; - -static char mem_size_str[10], mem_size_units[3]; - -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 allegro_list_t waitstate_list[] = -{ - {"System default", 0}, - {"0 W/S", 1}, - {"1 W/S", 2}, - {"2 W/S", 3}, - {"3 W/S", 4}, - {"4 W/S", 5}, - {"5 W/S", 6}, - {"6 W/S", 7}, - {"7 W/S", 8}, - {"", -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_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_hdd(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (hdd_list[c].internal_name) - c++; - - *list_size = c; - return NULL; - } - - return hdd_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 char *list_proc_mouse(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (mouse_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return mouse_list[index].name; -} - -static char *list_proc_ws(int index, int *list_size) -{ - if (index < 0) - { - int c = 0; - - while (waitstate_list[c].name[0]) - c++; - - *list_size = c; - return NULL; - } - - return waitstate_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 model_config_proc(int msg, DIALOG *d, int c); -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,372,0,0xffffff,0,0, 0,0,0,0,0}, // 0 - - {d_button_proc, 226, 348, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 - {d_button_proc, 296, 348, 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, 132, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_vidspeed, 0, 0}, //7 - {list_proc, 70*2, 152, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_sound, 0, 0}, //8 - - {d_edit_proc, 70*2, 276, 32, 14, 0, 0xffffff, 0, 0, 3, 0, mem_size_str, 0, 0}, - - {d_text_proc, 98*2, 276, 40, 10, 0, 0xffffff, 0, 0, 0, 0, mem_size_units, 0, 0}, - - {d_check_proc, 14*2, 292, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "CMS / Game Blaster", 0, 0}, - {d_check_proc, 14*2, 308, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Gravis Ultrasound", 0, 0}, - {d_check_proc, 14*2, 324, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Innovation SSI-2001", 0, 0}, - {d_check_proc, 14*2, 336, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Voodoo Graphics", 0, 0}, //14 - - {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, 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, 276, 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, 196, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Drive A: :", 0, 0}, - {d_text_proc, 16*2, 216, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Drive B: :", 0, 0}, - {d_list_proc, 70*2, 192, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_fdd, 0, 0}, //25 - {d_list_proc, 70*2, 212, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_fdd, 0, 0}, - - {video_config_proc, 452, 36, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, //27 - {sound_config_proc, 452, 156, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, - {voodoo_config_proc, 452, 336, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, - - {d_text_proc, 16*2, 236, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Joystick :", 0, 0}, - {d_list_proc, 70*2, 232, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_joystick, 0, 0}, //31 - - {d_text_proc, 16*2, 256, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Mouse :", 0, 0}, - {d_list_proc, 70*2, 252, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_mouse, 0, 0}, //33 - - {model_config_proc, 452, 12, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, - - {d_text_proc, 16*2, 116, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Waitstates :", 0, 0}, - {d_list_proc, 70*2, 112, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_ws, 0, 0}, //36 - - {d_text_proc, 16*2, 176, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "HDD :", 0, 0}, - {d_list_proc, 70*2, 172, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_hdd, 0, 0}, //38 - - {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} -}; - -static void update_hdd_list(int model, int use_selected_hdd) -{ - memset(hdd_list, 0, sizeof(hdd_list)); - - if (models[model].flags & MODEL_HAS_IDE) - { - strcpy(hdd_list[0].name, "Internal IDE"); - hdd_list[0].internal_name = "internal_ide"; - } - else - { - int c = 0, d = 0; - char old_name[16]; - - if (use_selected_hdd) - { - c = configure_dialog[38].d1; - - if (c != -1 && hdd_list[c].internal_name) - strncpy(old_name, hdd_list[c].internal_name, sizeof(old_name)-1); - else - strcpy(old_name, "none"); - } - else - strncpy(old_name, hdd_controller_name, sizeof(old_name)-1); - - configure_dialog[38].d1 = 0; - pclog("HDD list %i\n", model); - c = 0; - while (1) - { - char *s = hdd_controller_get_name(c); - - if (s[0] == 0) - break; - - if ((((hdd_controller_get_flags(c) & DEVICE_AT) && !(models[model].flags & MODEL_AT)) || - (hdd_controller_get_flags(c) & DEVICE_MCA) != (models[model].flags & MODEL_MCA)) && c) - { - pclog("Skip %i 1 %s\n", c, s); - c++; - continue; - } - if (!hdd_controller_available(c)) - { - pclog("Skip %i 2 %s\n", c, s); - c++; - continue; - } - - strcpy(hdd_list[d].name, s); - hdd_list[d].internal_name = hdd_controller_get_internal_name(c); - - if (!strcmp(old_name, hdd_list[d].internal_name)) - configure_dialog[38].d1 = d; - - c++; - d++; - } - } -} - -static int mouse_valid(int type, int model) -{ - if ((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_PS2 && !(models[model].flags & MODEL_PS2)) - return 0; - if ((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_AMSTRAD && !(models[model].flags & MODEL_AMSTRAD)) - return 0; - if ((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_OLIM24 && !(models[model].flags & MODEL_OLIM24)) - return 0; - return 1; -} - -static void update_mouse_list() -{ - int sel_model = model_list[configure_dialog[3].d1].num; - int c = 0, d = 0; - int new_mouse = settings_list_to_mouse[configure_dialog[33].d1]; - - while (mouse_get_name(c)) - { - int type = mouse_get_type(c); - - settings_mouse_to_list[c] = d; - - if (mouse_valid(type, sel_model)) - { - strcpy(mouse_list[d].name, mouse_get_name(c)); - settings_list_to_mouse[d] = c; - d++; - } - - c++; - } - mouse_list[d].name[0] = 0; - - if (mouse_valid(mouse_get_type(new_mouse), sel_model)) - configure_dialog[33].d1 = settings_mouse_to_list[new_mouse]; - else - configure_dialog[33].d1 = 0; -} - -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[22].flags & D_SELECTED; - int new_gfxcard = video_old_to_new(video_list[configure_dialog[4].d1].num); - int new_mem_size; - int cpu_flags, cpu_type; - - 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[22].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[22].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].flags & MODEL_AT) - sprintf(mem_size_units, "MB"); - else - sprintf(mem_size_units, "kB"); - - if (!video_card_has_config(new_gfxcard)) - configure_dialog[27].flags |= D_DISABLED; - else - configure_dialog[27].flags &= ~D_DISABLED; - - if (!sound_card_has_config(configure_dialog[9].d1)) - configure_dialog[28].flags |= D_DISABLED; - else - configure_dialog[28].flags &= ~D_DISABLED; - - update_mouse_list(); - - if (!model_getdevice(new_model)) - configure_dialog[34].flags |= D_DISABLED; - else - configure_dialog[34].flags &= ~D_DISABLED; - - cpu_type = models[new_model].cpu[new_cpu_m].cpus[new_cpu].cpu_type; - if (cpu_type < CPU_286 || cpu_type > CPU_386DX) - configure_dialog[36].flags |= D_DISABLED; - else - configure_dialog[36].flags &= ~D_DISABLED; - - update_hdd_list(new_model, 1); - - 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[8].d1].num; - - deviceconfig_open(sound_card_getdevice(new_sndcard)); - return D_O_K; - } - - return ret; -} -static int model_config_proc(int msg, DIALOG *d, int c) -{ - int ret = d_button_proc(msg, d, c); - - if (ret == D_CLOSE) - { - int model = model_list[configure_dialog[3].d1].num; - - deviceconfig_open(model_getdevice(model)); - 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[27].flags |= D_DISABLED; - else - configure_dialog[27].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[8].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[31].d1 = c; - - c++; - } - - configure_dialog[33].d1 = 0; - update_mouse_list(); - configure_dialog[33].d1 = settings_mouse_to_list[mouse_type]; - - update_hdd_list(model, 0); - - if (!sound_card_has_config(configure_dialog[8].d1)) - configure_dialog[28].flags |= D_DISABLED; - else - configure_dialog[28].flags &= ~D_DISABLED; - - configure_dialog[5].d1 = cpu_manufacturer; - configure_dialog[6].d1 = cpu; - configure_dialog[7].d1 = video_speed; - configure_dialog[36].d1 = cpu_waitstates; - 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[11].flags |= D_SELECTED; - else - configure_dialog[11].flags &= ~D_SELECTED; - - if (GUS) - configure_dialog[12].flags |= D_SELECTED; - else - configure_dialog[12].flags &= ~D_SELECTED; - - if (SSI2001) - configure_dialog[13].flags |= D_SELECTED; - else - configure_dialog[13].flags &= ~D_SELECTED; - - if (voodoo_enabled) - configure_dialog[14].flags |= D_SELECTED; - else - configure_dialog[14].flags &= ~D_SELECTED; - - if (models[model].flags & MODEL_AT) - sprintf(mem_size_str, "%i", mem_size / 1024); - else - sprintf(mem_size_str, "%i", mem_size); - - if (models[model].flags & MODEL_AT) - sprintf(mem_size_units, "MB"); - else - sprintf(mem_size_units, "kB"); - - if (!model_getdevice(model)) - configure_dialog[34].flags |= D_DISABLED; - else - configure_dialog[34].flags &= ~D_DISABLED; - - cpu_flags = models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; - configure_dialog[22].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[22].flags |= D_DISABLED; - - configure_dialog[25].d1 = fdd_get_type(0); - configure_dialog[26].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[8].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[11].flags & D_SELECTED) ? 1 : 0; - int new_GUS = (configure_dialog[12].flags & D_SELECTED) ? 1 : 0; - int new_SSI2001 = (configure_dialog[13].flags & D_SELECTED) ? 1 : 0; - int new_voodoo = (configure_dialog[14].flags & D_SELECTED) ? 1 : 0; - int new_dynarec = (configure_dialog[22].flags & D_SELECTED) ? 1 : 0; - int new_fda = configure_dialog[25].d1; - int new_fdb = configure_dialog[26].d1; - int new_mouse = settings_list_to_mouse[configure_dialog[33].d1]; - int new_hdd = configure_dialog[38].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].flags & MODEL_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) || - new_mouse != mouse_type || strncmp(hdd_list[new_hdd].internal_name, hdd_controller_name, sizeof(hdd_controller_name)-1)) - { - if (has_been_inited && 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; - mouse_type = new_mouse; - - if (hdd_list[new_hdd].internal_name) - strncpy(hdd_controller_name, hdd_list[new_hdd].internal_name, sizeof(hdd_controller_name)-1); - else - strcpy(hdd_controller_name, "none"); - - mem_resize(); - loadbios(); - resetpchard(); - - fdd_set_type(0, new_fda); - fdd_set_type(1, new_fdb); - } - - video_speed = configure_dialog[7].d1; - - cpu_manufacturer = new_cpu_m; - cpu = new_cpu; - cpu_set(); - - cpu_waitstates = configure_dialog[36].d1; - cpu_update_waitstates(); - - joystick_type = configure_dialog[31].d1; - gameport_update_joystick_type(); - - saveconfig(NULL); - - 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 deleted file mode 100644 index 3899ce9..0000000 --- a/src/allegro-gui-deviceconfig.c +++ /dev/null @@ -1,303 +0,0 @@ -#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(CFG_MACHINE, 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(CFG_MACHINE, 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(CFG_MACHINE, 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(CFG_MACHINE, 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(CFG_MACHINE, 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(CFG_MACHINE, config_device->name, config->name, val); - - dialog_pos += 2; - break; - - case CONFIG_MIDI: - break; - } - - config++; - - if (dialog_pos >= MAX_CONFIG_SIZE-3) - break; - } - - saveconfig(NULL); - - resetpchard(); - - return; - } - - if (c == id_cancel) - break; - } -} diff --git a/src/allegro-gui-hdconf.c b/src/allegro-gui-hdconf.c deleted file mode 100644 index 493c3ff..0000000 --- a/src/allegro-gui-hdconf.c +++ /dev/null @@ -1,536 +0,0 @@ -#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); - if ((sz % 17) == 0 && sz <= 133693440) - { - sprintf(hd_sectors_new, "17"); - if (sz <= 26738688) - { - sprintf(hd_heads_new, "4"); - sprintf(hd_cylinders_new, "%i", (int)((sz / 512) / 4) / 17); - } - else if (sz <= 53477376) - { - sprintf(hd_heads_new, "6"); - sprintf(hd_cylinders_new, "%i", (int)((sz / 512) / 6) / 17); - } - else if (sz <= 71303168) - { - sprintf(hd_heads_new, "8"); - sprintf(hd_cylinders_new, "%i", (int)((sz / 512) / 8) / 17); - } - else - { - sprintf(hd_heads_new, "15"); - sprintf(hd_cylinders_new, "%i", (int)((sz / 512) / 15) / 17); - } - } - else - { - 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; - uint8_t buf[512]; - FILE *f = fopen64(hd_path_new, "wb"); - 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); - - return 0; -} - -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; - - 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; - - 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 (!has_been_inited || 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(NULL); - - 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 deleted file mode 100644 index 43914e6..0000000 --- a/src/allegro-gui.c +++ /dev/null @@ -1,288 +0,0 @@ -#include "ibm.h" -#include "device.h" -#include "allegro-main.h" -#include "allegro-gui.h" -#include "disc.h" -#include "ide.h" -#include "cdrom-ioctl.h" -#include "cdrom-iso.h" -#include "cdrom-null.h" - -void warning(const char *format, ...) -{ - char buf[1024]; - va_list ap; - - va_start(ap, format); - vsprintf(buf, format, ap); - va_end(ap); - - alert("Warning:", buf, NULL, "OK", NULL, 0, 0); -} - - -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(NULL); - } - 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(NULL); - } - return D_O_K; -} - -static int disc_eject_a() -{ - disc_close(0); - saveconfig(NULL); - - return D_O_K; -} - -static int disc_eject_b() -{ - disc_close(1); - saveconfig(NULL); - - 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 switch (cdrom_drive) - { - case -1: - cdrom_menu[1].flags = D_SELECTED; - break; - case CDROM_ISO: - cdrom_menu[3].flags = D_SELECTED; - break; - default: - cdrom_menu[2].flags = D_SELECTED; - break; - } -} - -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(NULL); - 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(NULL); - resetpchard(); - cdrom_update(); - } - - return D_O_K; -} - -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(NULL); - resetpchard(); - cdrom_update(); - } - - return D_O_K; -} - -static int cdrom_iso() -{ - char fn[260]; - int ret; - int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; - - strcpy(fn, iso_path); - ret = file_select_ex("Please choose an ISO image", fn, "ISO", 260, xsize, ysize); - if (ret) - { - if (!cdrom_enabled) - { - if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) != 1) - return D_O_K; - } - else - { - atapi->exit(); - } - - cdrom_drive = CDROM_ISO; - iso_open(fn); - if (!cdrom_enabled) - { - cdrom_enabled = 1; - resetpchard(); - } - cdrom_update(); - saveconfig(NULL); - } - return D_O_K; -} - -static MENU cdrom_menu[] = -{ - {"&Disabled", cdrom_disabled, NULL, 0, NULL}, - {"&Empty", cdrom_empty, NULL, 0, NULL}, - {"/dev/cdrom", cdrom_dev, NULL, 0, NULL}, - {"&ISO image...", cdrom_iso, 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 deleted file mode 100644 index 2c98f82..0000000 --- a/src/allegro-gui.h +++ /dev/null @@ -1,15 +0,0 @@ -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); -int config_sel(); - -extern int has_been_inited; diff --git a/src/allegro-joystick.c b/src/allegro-joystick.c deleted file mode 100644 index 953399a..0000000 --- a/src/allegro-joystick.c +++ /dev/null @@ -1,49 +0,0 @@ -#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 deleted file mode 100644 index 335f842..0000000 --- a/src/allegro-keyboard.c +++ /dev/null @@ -1,49 +0,0 @@ -#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 deleted file mode 100644 index 47098f6..0000000 --- a/src/allegro-main.c +++ /dev/null @@ -1,204 +0,0 @@ -#include "ibm.h" -#include "device.h" -#include "allegro-gui.h" -#include "allegro-main.h" -#include "allegro-video.h" -#include "config.h" -#include "cpu.h" -#include "mem.h" -#include "model.h" -#include "nvr.h" -#include "plat-joystick.h" -#include "plat-keyboard.h" -#include "plat-midi.h" -#include "plat-mouse.h" -#include "sound.h" -#include "video.h" - - #undef printf - -int has_been_inited = 0; - -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; - 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(); - - getpath(); - - sound_init(); - - initpc(argc, argv); - - keyboard_init(); - mouse_init(); - joystick_init(); - - 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; - } - - for (c = 0; c < GFX_MAX; c++) - gfx_present[c] = video_card_available(video_old_to_new(c)); - - while (1) - { - has_been_inited = 0; - if (config_sel()) - return 0; - has_been_inited = 1; - - quited = 0; - - loadconfig(NULL); - - 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(NULL); - resetpchard(); - break; - } - } - } - - 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(NULL); - 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; - } - } - - savenvr(); - } - - closepc(); - - joystick_close(); - mouse_close(); - keyboard_close(); - midi_close(); - - return 0; -} - -END_OF_MAIN(); diff --git a/src/allegro-main.h b/src/allegro-main.h deleted file mode 100644 index ba96a4f..0000000 --- a/src/allegro-main.h +++ /dev/null @@ -1,19 +0,0 @@ -#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 deleted file mode 100644 index b491db1..0000000 --- a/src/allegro-midi.c +++ /dev/null @@ -1,45 +0,0 @@ -#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 deleted file mode 100644 index 9cceaa9..0000000 --- a/src/allegro-mouse.c +++ /dev/null @@ -1,32 +0,0 @@ -#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, int *z) -{ - if (mousecapture) - { - get_mouse_mickeys(x, y); - *z = 0; -// position_mouse(64, 64); - } - else - *x = *y = *z = 0; -} - diff --git a/src/allegro-video.c b/src/allegro-video.c deleted file mode 100644 index 5ca4da3..0000000 --- a/src/allegro-video.c +++ /dev/null @@ -1,131 +0,0 @@ -#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_func = allegro_blit_memtoscreen; - video_blit_memtoscreen_8_func = 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); - } - } - - video_blit_complete(); - 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); - video_blit_complete(); - } -} - -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]]; - } - } - } - video_blit_complete(); - 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 deleted file mode 100644 index e82419a..0000000 --- a/src/allegro-video.h +++ /dev/null @@ -1,3 +0,0 @@ -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 index 4c5cdf9..714380c 100644 --- a/src/amstrad.c +++ b/src/amstrad.c @@ -1,26 +1,73 @@ #include #include "ibm.h" -#include "dac.h" #include "io.h" #include "keyboard.h" #include "lpt.h" #include "mouse.h" +#include "video.h" +#include "fdc.h" +#include "x86.h" #include "amstrad.h" static uint8_t amstrad_dead; +int amstrad_latch = 0; +static uint8_t amstrad_language; uint8_t amstrad_read(uint16_t port, void *priv) { + uint8_t temp; + pclog("amstrad_read : %04X\n",port); switch (port) { + case 0x378: + return lpt1_read(port, NULL); case 0x379: - return 7 | readdacfifo(); + return lpt1_read(port, NULL) | (amstrad_language & 7); case 0x37a: - if (romset == ROM_PC1512) return 0x20; - if (romset == ROM_PC200) return 0x80; - return 0; + temp = lpt1_read(port, NULL) & 0x1f; + if (romset == ROM_PC1512) return temp | 0x20; + if (romset == ROM_PC200 || romset == ROM_PPC512) + { + if (fdc_discchange_read()) + temp |= 0x20; +/* DIP switches 4,5: Initial video mode */ + if (video_is_cga()) + temp |= 0x80; /* CGA 80 */ + else if (video_is_mda()) + temp |= 0xc0; /* MDA */ + return temp; + } + if (romset == ROM_PC1640) + { + if (video_is_cga()) + temp |= 0x80; + else if (video_is_mda()) + temp |= 0xc0; + + switch (amstrad_latch) + { + case AMSTRAD_NOLATCH: + temp &= ~0x20; + break; + case AMSTRAD_SW9: + temp &= ~0x20; + break; + case AMSTRAD_SW10: + temp |= 0x20; + break; + } + } + return temp; + case 0x3de: + if (romset == ROM_PC200 || romset == ROM_PPC512) + { +/* Read DIP switches / internal display adapter status. This code is only + * reached if the IDA is disabled; if it is enabled this read will be + * handled by the video card */ + } + return 0x20; /* Disable IDA */ case 0xdead: return amstrad_dead; } @@ -31,6 +78,16 @@ void amstrad_write(uint16_t port, uint8_t val, void *priv) { switch (port) { + case 0x66: + softresetx86(); + break; + + case 0x378: + case 0x379: + case 0x37a: + lpt1_write(port, val, NULL); + break; + case 0xdead: amstrad_dead = val; break; @@ -109,6 +166,170 @@ void amstrad_init() 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(0x0066, 0x0001, NULL, NULL, NULL, amstrad_write, NULL, NULL, NULL); + io_sethandler(0x0378, 0x0003, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL, NULL); io_sethandler(0xdead, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL, NULL); + if ((romset == ROM_PC200 || romset == ROM_PPC512) && gfxcard != GFX_BUILTIN) + io_sethandler(0x03de, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL, NULL); + + } + +static void *ams1512_init() +{ + amstrad_language = device_get_config_int("language"); + return &amstrad_language; +} + +device_config_t ams1512_config[] = +{ + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "English", + .value = 7 + }, + { + .description = "German", + .value = 6 + }, + { + .description = "French", + .value = 5 + }, + { + .description = "Spanish", + .value = 4 + }, + { + .description = "Danish", + .value = 3 + }, + { + .description = "Swedish", + .value = 2 + }, + { + .description = "Italian", + .value = 1 + }, + { + .description = "Diagnostic mode", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .type = -1 + } +}; + + +device_config_t ams2086_config[] = +{ + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "English", + .value = 7 + }, + { + .description = "Diagnostic mode", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .type = -1 + } +}; + + + +device_config_t ams3086_config[] = +{ + { + .name = "language", + .description = "BIOS language", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "English", + .value = 7 + }, + { + .description = "Diagnostic mode", + .value = 3 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .type = -1 + } +}; + + + + +device_t ams1512_device = +{ + "Amstrad PC1512 (BIOS)", + 0, + ams1512_init, + NULL, + NULL, + NULL, + NULL, + NULL, + ams1512_config +}; + + + +device_t ams2086_device = +{ + "Amstrad PC2086 (BIOS)", + 0, + ams1512_init, + NULL, + NULL, + NULL, + NULL, + NULL, + ams2086_config +}; + + +device_t ams3086_device = +{ + "Amstrad PC3086 (BIOS)", + 0, + ams1512_init, + NULL, + NULL, + NULL, + NULL, + NULL, + ams3086_config +}; diff --git a/src/amstrad.h b/src/amstrad.h index a4250d3..0c54fcb 100644 --- a/src/amstrad.h +++ b/src/amstrad.h @@ -1,3 +1,18 @@ +#include "mouse.h" +#include "device.h" + void amstrad_init(); extern mouse_t mouse_amstrad; +extern int amstrad_latch; + +extern device_t ams1512_device; +extern device_t ams2086_device; +extern device_t ams3086_device; + +enum +{ + AMSTRAD_NOLATCH, + AMSTRAD_SW9, + AMSTRAD_SW10 +}; diff --git a/src/bswap.h b/src/bswap.h new file mode 100644 index 0000000..c473c50 --- /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/cassette.c b/src/cassette.c new file mode 100644 index 0000000..68f495a --- /dev/null +++ b/src/cassette.c @@ -0,0 +1,187 @@ +/************************************************************************ + + PCem: IBM 5150 Cassette support + + Copyright (C) 2019 John Elliott + + 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. + +*************************************************************************/ + +#include +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "device.h" +#include "pzx.h" + +char cassettefn[256]; + +typedef struct cassette_t +{ + uint8_t motor; /* Motor status */ + pzxfile_t pzx; + int cycles_last; /* Cycle count at last cassette poll */ + +} cassette_t; + +extern device_t cassette_device; + + +static cassette_t *st_cas; + + + +#define CAS_LOG(x) pclog x +// #define CAS_LOG(x) + + +/* The PCem CPU uses IBM cycles (4.77MHz). PZX uses Spectrum cycles (3.5MHz) + * so scale accordingly. */ +static int32_t pzx_cycles(int32_t pc) +{ + double d = pc; + + return (int32_t)(((d * 3.5) / 4.772728) + 0.5); +} + +void cassette_eject(void) +{ + if (st_cas->pzx.input) + { + pzx_close(&st_cas->pzx); + } + cassettefn[0] = 0; +} + +void cassette_load(const char *filename) +{ + FILE *fp; + unsigned char magic[8]; + + if (!filename) return; + + fp = fopen(filename, "rb"); + if (!fp) + { + /* Warn user? */ + CAS_LOG(("Failed to open cassette input %s\n", filename)); + return; + } + memset(magic, 0, sizeof(magic)); + fread(magic, 1, sizeof(magic), fp); + + /* Check for PZX signature. In due course support could be added for + * other formats like TZX */ + if (!memcmp(magic, "PZXT", 4)) + { + const char *result; + + result = pzx_open(&st_cas->pzx, fp); + + if (result) + { + CAS_LOG(("Failed to open %s as PZX: %s\n", + filename, result)); + fclose(fp); + return; + } + strcpy(cassettefn, filename); + } +} + + +uint8_t cassette_input(void) +{ + int ticks; + + /* While motor is off, result is loopback */ + if (!st_cas->motor) + { + return ppispeakon; + } + /* If there is no tapefile open don't try to extract data */ + if (st_cas->pzx.input == NULL) return 0; + /* Otherwise see how many ticks there have been since the last input */ + if (st_cas->cycles_last == -1) + { + st_cas->cycles_last = cycles; + } + if (cycles <= st_cas->cycles_last) + { + ticks = (st_cas->cycles_last - cycles); + } + else + { + ticks = (st_cas->cycles_last + (cpu_get_speed() / 100) - cycles); + } + st_cas->cycles_last = cycles; + + return pzx_advance(&st_cas->pzx, pzx_cycles(ticks)); +} + + + +void cassette_set_motor(uint8_t on) +{ + if (on && !st_cas->motor) + { + CAS_LOG(("Start cassette motor\n")); + st_cas->cycles_last = -1; + } + if (st_cas->motor && !on) + { + CAS_LOG(("Stop cassette motor\n")); + st_cas->cycles_last = -1; + } + st_cas->motor = on; +} + + +static void *cassette_init(void) +{ + cassette_t *cas = malloc(sizeof(cassette_t)); + + memset(cas, 0, sizeof(cassette_t)); + pzx_init(&cas->pzx); + + st_cas = cas; + return cas; +} + + +static void cassette_close(void *p) +{ + cassette_t *cas = (cassette_t *)p; + + pzx_close(&cas->pzx); + + free(cas); +} + + +device_t cassette_device = +{ + "Cassette", + 0, + cassette_init, + cassette_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + diff --git a/src/cassette.h b/src/cassette.h new file mode 100644 index 0000000..de77354 --- /dev/null +++ b/src/cassette.h @@ -0,0 +1,30 @@ +/************************************************************************ + + PCem: IBM 5150 cassette support + + Copyright (C) 2019 John Elliott + + 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. + +*************************************************************************/ + +extern device_t cassette_device; + +uint8_t cassette_input(void); +void cassette_set_motor(uint8_t on); +void cassette_eject(void); +void cassette_load(const char *filename); + +extern char cassettefn[256]; diff --git a/src/cbm_io.c b/src/cbm_io.c new file mode 100644 index 0000000..ec73560 --- /dev/null +++ b/src/cbm_io.c @@ -0,0 +1,39 @@ +#include "ibm.h" + +#include "io.h" +#include "lpt.h" +#include "serial.h" + +static void cbm_io_write(uint16_t port, uint8_t val, void *p) +{ + serial1_remove(); + serial2_remove(); + lpt1_remove(); + lpt2_remove(); + switch (val & 3) + { + case 1: + lpt1_init(0x3bc); + break; + case 2: + lpt1_init(0x378); + break; + case 3: + lpt1_init(0x278); + break; + } + switch (val & 0xc) + { + case 0x4: + serial1_set(0x2f8, 3); + break; + case 0x8: + serial1_set(0x3f8, 4); + break; + } +} + +void cbm_io_init() +{ + io_sethandler(0x0230, 0x0001, NULL,NULL,NULL, cbm_io_write,NULL,NULL, NULL); +} diff --git a/src/cbm_io.h b/src/cbm_io.h new file mode 100644 index 0000000..1e3d5e6 --- /dev/null +++ b/src/cbm_io.h @@ -0,0 +1 @@ +void cbm_io_init(); diff --git a/src/cdrom-image.cc b/src/cdrom-image.cc new file mode 100644 index 0000000..99ce8ad --- /dev/null +++ b/src/cdrom-image.cc @@ -0,0 +1,548 @@ +#include +#include "cdrom-image.h" +#include "dosbox/cdrom.h" + +extern "C" +{ +#include "ibm.h" +#include "ide.h" +} + +char image_path[1024]; +static int image_changed = 0; + +extern ATAPI image_atapi; + +CDROM_Interface_Image *cdrom = NULL; + +#define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)) + +static uint32_t cdrom_capacity = 0; + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +static int image_cd_state = CD_STOPPED; +static uint32_t image_cd_pos = 0, image_cd_end = 0; + +#define BUF_SIZE 32768 +static int16_t cd_buffer[BUF_SIZE]; +static int cd_buflen = 0; + +void image_audio_callback(int16_t *output, int len) +{ + if (image_cd_state != CD_PLAYING) + return; + while (cd_buflen < len) + { + if (image_cd_pos < image_cd_end) + { +// pclog("Read to %i\n", cd_buflen); + if (!cdrom->ReadSector((unsigned char *)&cd_buffer[cd_buflen], true, image_cd_pos - 150)) + { +// pclog("DeviceIoControl returned false\n"); + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + image_cd_state = CD_STOPPED; + cd_buflen = len; + } + else + { +// pclog("DeviceIoControl returned true\n"); + image_cd_pos++; + cd_buflen += (RAW_SECTOR_SIZE / 2); + } + } + else + { + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + image_cd_state = CD_STOPPED; + cd_buflen = len; + } + } + memcpy(output, cd_buffer, len * 2); + memmove(cd_buffer, &cd_buffer[len], (BUF_SIZE - len) * 2); + cd_buflen -= len; +} + +void image_audio_stop() +{ + image_cd_state = CD_STOPPED; +} + +static int image_is_track_audio(uint32_t pos, int ismsf) +{ + if (!cdrom) return 0; + if (ismsf) + { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + pos = MSF_TO_FRAMES(m, s, f); + } + + unsigned char attr; + TMSF tmsf; + int number; + cdrom->GetAudioTrackInfo(cdrom->GetTrack(pos), number, tmsf, attr); + + return attr == AUDIO_TRACK; +} + +static void image_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ + if (!cdrom) return; + int number; + unsigned char attr; + TMSF tmsf; + cdrom->GetAudioTrackInfo(cdrom->GetTrack(pos), number, tmsf, attr); + if (attr == DATA_TRACK) + { + pclog("Can't play data track\n"); + image_cd_pos = 0; + image_cd_state = CD_STOPPED; + return; + } + pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf) + { + int m, s, f; + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + 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; + image_cd_pos = pos;// + 150; + image_cd_end = len;// + 150; + image_cd_state = CD_PLAYING; + if (image_cd_pos < 150) + image_cd_pos = 150; + cd_buflen = 0; + pclog("Audio start %08X %08X %i %i %i\n", image_cd_pos, image_cd_end, image_cd_state, cd_buflen, len); +} + +static void image_pause(void) +{ + if (!cdrom) return; + if (image_cd_state == CD_PLAYING) + image_cd_state = CD_PAUSED; +} + +static void image_resume(void) +{ + if (!cdrom) return; + if (image_cd_state == CD_PAUSED) + image_cd_state = CD_PLAYING; +} + +static void image_stop(void) +{ + if (!cdrom) return; + image_cd_state = CD_STOPPED; +} + +static void image_seek(uint32_t pos) +{ + if (!cdrom) return; + image_cd_pos = pos; + image_cd_state = CD_STOPPED; +} + +static int image_ready(void) +{ + if (!cdrom) + return 0; + + if (strlen(image_path) == 0) + return 0; + + if (image_changed) + image_changed = 0; + + return 1; +} + +static int image_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) +{ + int c; + uint32_t lb=0; + + if (!cdrom) return 0; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + cdrom->GetAudioTracks(first_track, last_track, tmsf); + + for (c = 0; c <= last_track; c++) + { + uint32_t address; + cdrom->GetAudioTrackInfo(c+1, number, tmsf, attr); + address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + if (address > lb) + lb = address; + } + return lb; +} + +static int image_medium_changed(void) +{ + if (!cdrom) + return 0; + + if (strlen(image_path) == 0) + return 0; + + if (old_cdrom_drive != cdrom_drive) + { + old_cdrom_drive = cdrom_drive; + return 1; + } + + if (image_changed) + { + image_changed = 0; + return 1; + } + return 0; +} + +static uint8_t image_getcurrentsubchannel(uint8_t *b, int msf) +{ + if (!cdrom) return 0; + uint8_t ret; + int pos=0; + + uint32_t cdpos = image_cd_pos; + if (cdpos >= 150) cdpos -= 150; + TMSF relPos, absPos; + unsigned char attr, track, index; + cdrom->GetAudioSub(cdpos, attr, track, index, relPos, absPos); + + if (image_cd_state == CD_PLAYING) + ret = 0x11; + else if (image_cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + + b[pos++] = attr; + b[pos++] = track; + b[pos++] = index; + + if (msf) + { + uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr); + 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 = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); + 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 + { + uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + dat = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + } + + return ret; +} + +static void image_eject(void) +{ +} + +static void image_load(void) +{ +} + +static int image_readsector(uint8_t *b, int sector, int count) +{ + if (!cdrom) return -1; + return !cdrom->ReadSectors((PhysPt)b, false, sector, count); +} + +static void image_readsector_raw(uint8_t *b, int sector) +{ + if (!cdrom) return; + cdrom->ReadSector(b, true, sector); +} + +static int image_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + if (!cdrom) return 0; + int len=4; + int c,d; + uint32_t temp; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + cdrom->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + d = 0; + for (c = 0; c <= last_track; c++) + { + cdrom->GetAudioTrackInfo(c+1, number, tmsf, attr); + if (number >= starttrack) + { + d=c; + break; + } + } + cdrom->GetAudioTrackInfo(c+1, number, tmsf, attr); + b[2] = number; + + for (c = d; c <= last_track; c++) + { + if ((len + 8) > maxlen) + break; + cdrom->GetAudioTrackInfo(c+1, number, tmsf, attr); + +// 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++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + + if (msf) + { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + else + { + temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + 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:\n"); + pclog("First track - %02X\n", first_track); + pclog("Last track - %02X\n", last_track); + for (c = 0; c <= last_track; c++) + { + cdrom->GetAudioTrackInfo(c+1, number, tmsf, attr); + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", c, number, attr, 0, 0, tmsf.min, tmsf.sec, tmsf.fr); + } + for (c = 0;c <= last_track; c++) { + cdrom->GetAudioTrackInfo(c+1, number, tmsf, attr); + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n", c, number, attr, 0, MSF_TO_FRAMES(tmsf.min, tmsf.sec, tmsf.fr)); + } + */ + return len; +} + +static int image_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + if (!cdrom) return 0; + int len = 4; + + int number; + TMSF tmsf; + unsigned char attr; + cdrom->GetAudioTrackInfo(1, number, tmsf, attr); + +// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",0, 0, 0,1,1,attr,0,number); + + b[2] = 1; + b[3] = 1; + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + if (msf) + { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + else + { + uint32_t temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + return len; +} + +static int image_readtoc_raw(unsigned char *b, int maxlen) +{ + if (!cdrom) return 0; + + int track; + int len = 4; + + int first_track; + int last_track; + int number; + unsigned char attr; + TMSF tmsf; + cdrom->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + for (track = first_track; track <= last_track; track++) + { + if ((len + 11) > maxlen) + { + pclog("image_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); + return len; + } + + cdrom->GetAudioTrackInfo(track, number, tmsf, attr); + +// 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++] = track; + b[len++]= attr; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + return len; +} + +static uint32_t image_size() +{ + return cdrom_capacity; +} + +static int image_status() +{ + if (!cdrom) return CD_STATUS_EMPTY; + if (cdrom->HasAudioTracks()) + { + switch(image_cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + default: + return CD_STATUS_STOPPED; + } + } + return CD_STATUS_DATA_ONLY; +} +void image_reset() +{ +} + +void image_close(void) +{ + image_cd_state = CD_STOPPED; + if (cdrom) + { + delete cdrom; + cdrom = NULL; + } +// memset(image_path, 0, 1024); +} + +int image_open(char *fn) +{ + if (strcmp(fn, image_path) != 0) + image_changed = 1; + + /* Make sure image_changed stays when changing from an image to another image. */ + if (cdrom_drive != CDROM_IMAGE) + image_changed = 1; + /* strcpy fails on OSX if both parameters are pointing to the same address */ + if (image_path != fn) + strcpy(image_path, fn); + + cdrom = new CDROM_Interface_Image(); + if (!cdrom->SetDevice(fn, false)) + { + image_close(); + return 1; + } + image_cd_state = CD_STOPPED; + image_cd_pos = 0; + cd_buflen = 0; + cdrom_capacity = image_get_last_block(0, 0, 4096, 0) + 1; + atapi = &image_atapi; + return 0; +} + +static void image_exit(void) +{ +} + +ATAPI image_atapi= +{ + image_ready, + image_medium_changed, + image_readtoc, + image_readtoc_session, + image_readtoc_raw, + image_getcurrentsubchannel, + image_readsector, + image_readsector_raw, + image_playaudio, + image_seek, + image_load, + image_eject, + image_pause, + image_resume, + image_size, + image_status, + image_is_track_audio, + image_stop, + image_exit +}; diff --git a/src/cdrom-image.h b/src/cdrom-image.h new file mode 100644 index 0000000..c0a7e44 --- /dev/null +++ b/src/cdrom-image.h @@ -0,0 +1,23 @@ +#ifndef CDROM_ISO_H +#define CDROM_ISO_H + +#include + +extern char image_path[1024]; + +#ifdef __cplusplus +extern "C" { +#endif + +int image_open(char *fn); +void image_reset(); +void image_close(); + +void image_audio_callback(int16_t *output, int len); +void image_audio_stop(); + +#ifdef __cplusplus +} +#endif + +#endif /* ! CDROM_ISO_H */ diff --git a/src/cdrom-ioctl-dummy.c b/src/cdrom-ioctl-dummy.c new file mode 100644 index 0000000..a4229ac --- /dev/null +++ b/src/cdrom-ioctl-dummy.c @@ -0,0 +1,20 @@ +/*Dummy CD-ROM support for other OSes*/ + +#include + +int old_cdrom_drive; + +void ioctl_audio_callback(int16_t *output, int len) { } + +void ioctl_audio_stop() { } + +void ioctl_reset() { } + +void ioctl_set_drive(char d) { } + +int ioctl_open(char d) +{ + return 0; +} + +void ioctl_close(void) { } diff --git a/src/cdrom-ioctl-linux.c b/src/cdrom-ioctl-linux.c index cd89b36..f5299ff 100644 --- a/src/cdrom-ioctl-linux.c +++ b/src/cdrom-ioctl-linux.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "ibm.h" #include "ide.h" #include "cdrom-ioctl.h" @@ -13,10 +14,11 @@ 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 struct cdrom_tocentry toc[256]; +static int toc_tracks; static int first_track, last_track; +static int ioctl_fd = 0; int old_cdrom_drive; @@ -36,7 +38,6 @@ 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()); @@ -45,9 +46,8 @@ void ioctl_audio_callback(int16_t *output, int len) memset(output, 0, len * 2); return; } - fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); - if (fd <= 0) + if (ioctl_fd <= 0) { memset(output, 0, len * 2); return; @@ -62,7 +62,7 @@ void ioctl_audio_callback(int16_t *output, int len) read_audio.nframes = 1; read_audio.buf = (__u8 *)&cd_buffer[cd_buflen]; - if (ioctl(fd, CDROMREADAUDIO, &read_audio) < 0) + if (ioctl(ioctl_fd, CDROMREADAUDIO, &read_audio) < 0) { // pclog("DeviceIoControl returned false\n"); memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); @@ -83,7 +83,7 @@ void ioctl_audio_callback(int16_t *output, int len) 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]; @@ -196,6 +196,7 @@ static int read_toc(int fd, struct cdrom_tocentry *btoc) { struct cdrom_tochdr toc_hdr; int track, err; + int c; //pclog("read_toc\n"); err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); if (err == -1) @@ -207,64 +208,66 @@ static int read_toc(int fd, struct cdrom_tocentry *btoc) 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)); + memset(btoc, 0, sizeof(struct cdrom_tocentry)); - for (track = toc_hdr.cdth_trk0; track <= toc_hdr.cdth_trk1; track++) + c = 0; + for (track = 0; track < 256; track++) { - btoc[track].cdte_track = track; - btoc[track].cdte_format = CDROM_MSF; - err = ioctl(fd, CDROMREADTOCENTRY, &btoc[track]); + btoc[c].cdte_track = track; + btoc[c].cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &btoc[c]); if (err == -1) { // pclog("read_toc: CDROMREADTOCENTRY failed on track %i\n", track); - return 0; + continue; } -// 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); + c++; +// pclog("read_toc: %i Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", c, track, btoc[c].cdte_track, btoc[c].cdte_ctrl, btoc[c].cdte_adr, 0, btoc[c].cdte_addr.msf.minute, btoc[c].cdte_addr.msf.second, btoc[c].cdte_addr.msf.frame); } + + toc_tracks = c; + 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) + if (ioctl_fd <= 0) return 0; - err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + err = ioctl(ioctl_fd, CDROM_MEDIA_CHANGED, 0); + if (err) + tocvalid = 0; + + if (tocvalid) + return 1; + + err = ioctl(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); + err = ioctl(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; + tocvalid = read_toc(ioctl_fd, toc); } - close(fd); + return 1; } @@ -274,16 +277,14 @@ static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, i int lb = 0; int tv = 0; struct cdrom_tocentry lbtoc[100]; - int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); - if (fd <= 0) + if (ioctl_fd <= 0) return 0; ioctl_cd_state = CD_STOPPED; - tv = read_toc(fd, lbtoc); - - close(fd); + if (!tocvalid) + tv = read_toc(ioctl_fd, lbtoc); if (!tv) return 0; @@ -301,30 +302,23 @@ static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, i 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) + if (ioctl_fd <= 0) return 0; - err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + err = ioctl(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); + err = ioctl(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) || @@ -338,15 +332,12 @@ static int ioctl_medium_changed(void) 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) @@ -393,38 +384,29 @@ static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) static void ioctl_eject(void) { - int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); - - if (fd <= 0) + if (ioctl_fd <= 0) return; - ioctl(fd, CDROMEJECT); - - close(fd); + ioctl(ioctl_fd, CDROMEJECT); } static void ioctl_load(void) { - int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); - - if (fd <= 0) + if (ioctl_fd <= 0) return; - ioctl(fd, CDROMEJECT); - - close(fd); + ioctl(ioctl_fd, CDROMEJECT); cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); } -static int ioctl_readsector(uint8_t *b, int sector) +static int ioctl_readsector(uint8_t *b, int sector, int count) { - int cdrom = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); - if (cdrom <= 0) + if (ioctl_fd <= 0) return -1; - lseek(cdrom, sector*2048, SEEK_SET); - read(cdrom, b, 2048); - close(cdrom); + + lseek(ioctl_fd, sector*2048, SEEK_SET); + read(ioctl_fd, b, count*2048); return 0; } @@ -444,9 +426,8 @@ 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) + if (ioctl_fd <= 0) return; raw_read_params.msf = malloc(sizeof(struct cdrom_msf)); @@ -455,7 +436,7 @@ static void ioctl_readsector_raw(uint8_t *b, int sector) 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); + err = ioctl(ioctl_fd, CDROMREADRAW, (void *) &raw_read_params); if (err == -1) { pclog("read_toc: CDROMREADTOCHDR failed\n"); @@ -464,27 +445,23 @@ static void ioctl_readsector_raw(uint8_t *b, int sector) 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); + uint32_t last_address = 0; - if (fd <= 0) + if (ioctl_fd <= 0) return 0; ioctl_cd_state = CD_STOPPED; - tocvalid = read_toc(fd, toc); - - close(fd); + if (!tocvalid) + tocvalid = read_toc(ioctl_fd, toc); if (!tocvalid) return 4; @@ -494,9 +471,9 @@ static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, in b[3] = last_track; d = 0; //pclog("Read TOC starttrack=%i\n", starttrack); - for (c = 1; c <= last_track; c++) + for (c = 0; c <= toc_tracks; c++) { - if (toc[c].cdte_track >= starttrack) + if (toc[c].cdte_track && toc[c].cdte_track >= starttrack) { d = c; break; @@ -504,17 +481,21 @@ static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, in } b[2] = toc[c].cdte_track; last_block = 0; - for (c = d; c <= last_track; c++) + + for (c = d; c <= toc_tracks; 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)); + address = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + if (address < last_address) + continue; + last_address = address; 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; @@ -536,6 +517,7 @@ static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, in 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); @@ -553,25 +535,21 @@ 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) + if (ioctl_fd <= 0) return 0; session.addr_format = CDROM_MSF; - err = ioctl(fd, CDROMMULTISESSION, &session); + err = ioctl(ioctl_fd, CDROMMULTISESSION, &session); if (err == -1) - { - close(fd); return 0; - } - b[2] = 0; - b[3] = 0; + b[2] = 1; + b[3] = 1; b[len++] = 0; /*Reserved*/ - b[len++] = (toc[0].cdte_adr << 4) | toc[0].cdte_ctrl; - b[len++] = toc[0].cdte_track; + b[len++] = (toc[first_track].cdte_adr << 4) | toc[first_track].cdte_ctrl; + b[len++] = toc[first_track].cdte_track; b[len++] = 0; /*Reserved*/ if (msf) { @@ -598,12 +576,13 @@ static int ioctl_readtoc_raw(unsigned char *b, int maxlen) 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) + if (ioctl_fd <= 0) return 0; - err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + err = ioctl(ioctl_fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) { pclog("read_toc: CDROMREADTOCHDR failed\n"); @@ -621,19 +600,15 @@ static int ioctl_readtoc_raw(unsigned char *b, int maxlen) 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]); + err = ioctl(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; @@ -648,7 +623,7 @@ static int ioctl_readtoc_raw(unsigned char *b, int maxlen) b[len++] = toc2[track].cdte_addr.msf.second; b[len++] = toc2[track].cdte_addr.msf.frame; } - close(fd); + return len; } @@ -659,7 +634,7 @@ static uint32_t ioctl_size() static int ioctl_status() { - if (!(ioctl_ready) && (cdrom_drive <= 0)) return CD_STATUS_EMPTY; + if (!ioctl_ready() && (cdrom_drive <= 0)) return CD_STATUS_EMPTY; switch(ioctl_cd_state) { @@ -668,36 +643,43 @@ static int ioctl_status() case CD_PAUSED: return CD_STATUS_PAUSED; case CD_STOPPED: + default: 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) + if (ioctl_fd <= 0) return; - tocvalid = read_toc(fd, toc); - - close(fd); + tocvalid = read_toc(ioctl_fd, toc); } void ioctl_set_drive(char d) { + ioctl_close(); atapi=&ioctl_atapi; + ioctl_open(d); } int ioctl_open(char d) { atapi=&ioctl_atapi; + ioctl_fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + return 0; } void ioctl_close(void) { + if (ioctl_fd) + { + close(ioctl_fd); + ioctl_fd = 0; + } } static void ioctl_exit(void) diff --git a/src/cdrom-ioctl-osx.c b/src/cdrom-ioctl-osx.c new file mode 100644 index 0000000..4d81bce --- /dev/null +++ b/src/cdrom-ioctl-osx.c @@ -0,0 +1,779 @@ +#include +#include +#include +#include "ibm.h" +#include "ide.h" +#include "cdrom-ioctl.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +static ATAPI ioctl_atapi; + +int old_cdrom_drive; + +static uint32_t cdrom_capacity = 0; +static int tocvalid = 0; +static int toc_tracks; +static int first_track, last_track; +static CDTOC *toc = NULL; +static CDDiscInfo disc_info; +static int track_addr[256]; + +static int msf_to_lba(CDMSF *msf) +{ + return msf->frame + (msf->second * 75) + (msf->minute * 60 * 75); +} + +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; +static int cd_drive = -1; + +static int cd_open() +{ + char s[80]; + + if (cd_drive < 0) + return 0; + + sprintf(s, "disk%i", cd_drive); + return opendev(s, O_RDONLY, 0, NULL); +} +static void cd_close(int fd) +{ + close(fd); +} + +void ioctl_audio_callback(int16_t *output, int len) +{ + int ioctl_fd; + +// 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; + } + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + { + memset(output, 0, len * 2); + return; + } + + while (cd_buflen < len) + { + if (ioctl_cd_pos < ioctl_cd_end) + { + dk_cd_read_t cd_read; + + bzero(&cd_read, sizeof(cd_read)); + + cd_read.offset = (ioctl_cd_pos-150)*kCDSectorSizeCDDA; + cd_read.buffer = &cd_buffer[cd_buflen]; + cd_read.bufferLength = kCDSectorSizeCDDA; + cd_read.sectorType = kCDSectorTypeCDDA; + cd_read.sectorArea = kCDSectorAreaUser; + //pclog("CDDA read %llx %d %d\n", cd_read.offset, cd_read.bufferLength, ioctl_cd_pos); + + if (ioctl(ioctl_fd, DKIOCCDREAD, &cd_read) < 0) + { + //pclog("DeviceIoControl returned false %d\n", errno); + 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; + } + } + + cd_close(ioctl_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->descriptors[c].p.frame + + (toc->descriptors[c].p.second * 75) + + (toc->descriptors[c].p.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; + //pclog("is_track_audio: %08x %i\n", pos, tocvalid); + if (!tocvalid) + return 0; + //pclog(" scan tracks %i-%i\n", first_track, last_track); + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc->descriptors[c].p.frame + + (toc->descriptors[c].p.second * 75) + + (toc->descriptors[c].p.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->descriptors[c].control; + } + return (control & 4) ? 0 : 1; +} + +static int ioctl_is_track_audio(uint32_t pos, int ismsf) +{ + if (ismsf) + { + CDMSF msf; + msf.minute = (pos >> 16) & 0xff; + msf.second = (pos >> 8) & 0xff; + msf.frame = pos & 0xff; + pos = msf_to_lba(&msf); + } + 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) +{ + dk_cd_read_toc_t cd_read_toc; + dk_cd_read_disc_info_t cd_read_disc_info; + int result; + int c; + + bzero(&cd_read_toc, sizeof(cd_read_toc)); + bzero(&cd_read_disc_info, sizeof(cd_read_disc_info)); + bzero(toc, sizeof(CDTOC) + sizeof(CDTOCDescriptor)*100); + + cd_read_toc.format = kCDTOCFormatTOC; + cd_read_toc.buffer = toc; + cd_read_toc.bufferLength = 2048;//sizeof(CDTOC) + sizeof(CDTOCDescriptor)*100; + //pclog("buffer=%p bufferLength=%u\n", cd_read_toc.buffer, cd_read_toc.bufferLength); + result = ioctl(fd, DKIOCCDREADTOC, &cd_read_toc); + + //pclog("Read_toc - fd=%d result=%d errno=%d toc=%p\n", fd, result, errno, toc); + if (result < 0) + { + //pclog("read_toc: DKIOCCDREADTOC failed\n"); + return 0; + } + + //pclog("toc length=%u first=%u last=%u\n", toc->length, toc->sessionFirst, toc->sessionFirst); + first_track = 1; + last_track = 0; + toc_tracks = CDTOCGetDescriptorCount(toc); + + for (c = 0; c < toc_tracks; c++) + { + if (toc->descriptors[c].session > 1) + continue; + track_addr[c] = msf_to_lba(&toc->descriptors[c].p); + //pclog("Track %i %02x addr %08x\n", c, toc->descriptors[c].point, track_addr[c]); + if (toc->descriptors[c].point <= 99 && toc->descriptors[c].adr == 1) + last_track++; + } + + //pclog("Tracks %i %i %i\n", first_track, last_track, toc_tracks); + + cd_read_disc_info.buffer = &disc_info; + cd_read_disc_info.bufferLength = sizeof(disc_info); + result = ioctl(fd, DKIOCCDREADDISCINFO, &cd_read_disc_info); + if (result < 0) + { + //pclog("read_toc: DKIOCCDREADDISCINFO failed\n"); + return 0; + } + + return 1; +} + +static int ioctl_ready(void) +{ + int ioctl_fd = cd_open(); + //pclog("ioctl_ready - %d %d\n", ioctl_fd, tocvalid); + if (ioctl_fd <= 0) + return 0; + cd_close(ioctl_fd); + + if (tocvalid) + return 1; + + return 0; +} + +static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) +{ + int c; + int lb = 0; + int tv = 0; + int ioctl_fd; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return 0; + + //ioctl_cd_state = CD_STOPPED; + + if (!tocvalid) + tv = read_toc(ioctl_fd); + + cd_close(ioctl_fd); + + if (!tv) + return 0; + + for (c = 0; c <= toc_tracks; c++) + { + if (track_addr[c] > lb) + lb = track_addr[c]; + } + return lb; +} + +static int ioctl_medium_changed(void) +{ + dk_cd_read_disc_info_t cd_read_disc_info; + CDDiscInfo new_disc_info; + int result; + int ioctl_fd; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return 1; + + bzero(&cd_read_disc_info, sizeof(cd_read_disc_info)); + cd_read_disc_info.buffer = &new_disc_info; + cd_read_disc_info.bufferLength = sizeof(new_disc_info); + result = ioctl(ioctl_fd, DKIOCCDREADDISCINFO, &cd_read_disc_info); + if (result < 0) + { + //pclog("medium_changed: DKIOCCDREADDISCINFO failed\n"); + ioctl_cd_state = CD_STOPPED; + tocvalid = 0; + cd_close(ioctl_fd); + return 1; + } + + if (memcmp(&disc_info, &new_disc_info, sizeof(CDDiscInfo))) + { + //pclog("medium_changed: disc changed\n"); + ioctl_cd_state = CD_STOPPED; + tocvalid = read_toc(ioctl_fd); + cd_close(ioctl_fd); + return 1; + } + + cd_close(ioctl_fd); + return 0; +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) +{ + uint32_t cdpos = ioctl_cd_pos; + int track = get_track_nr(cdpos); + uint32_t track_address = track_addr[track]; + long size; + int pos=0; + int err; + uint8_t ret; + + + if (ioctl_cd_state == CD_PLAYING) + ret = 0x11; + else if (ioctl_cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + + b[pos++] = (toc->descriptors[track].adr << 4) | toc->descriptors[track].control; + b[pos++] = toc->descriptors[track].point; + 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; + } + + //pclog("ioctl_getsubchannel: cdpos=%x track_address=%x track=%i state=%i ret=%02x\n", cdpos, track_address, track, ioctl_cd_state, ret); + + return ret; +} + +static void ioctl_eject(void) +{ +} + +static void ioctl_load(void) +{ +} + +static int ioctl_readsector(uint8_t *b, int sector, int count) +{ + dk_cd_read_t cd_read; + int res; + int ioctl_fd; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return -1; + //pclog("Read sector %x %i\n", sector, count); + + bzero(&cd_read, sizeof(cd_read)); + + cd_read.offset = sector*2048; + cd_read.buffer = b; + cd_read.bufferLength = count*2048; + cd_read.sectorType = kCDSectorTypeMode1; + cd_read.sectorArea = kCDSectorAreaUser; + + res = ioctl(ioctl_fd, DKIOCCDREAD, &cd_read); + //pclog("read res = %i %i %i\n", res, cd_read.bufferLength, errno); + + cd_close(ioctl_fd); + + return 0; +} + +static void ioctl_readsector_raw(uint8_t *b, int sector) +{ + dk_cd_read_t cd_read; + int res; + int ioctl_fd; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return; + //pclog("Read sector %x %i\n", sector, count); + + bzero(&cd_read, sizeof(cd_read)); + + cd_read.offset = sector*kCDSectorSizeWhole; + cd_read.buffer = b; + cd_read.bufferLength = kCDSectorSizeWhole; + cd_read.sectorType = kCDSectorTypeUnknown; + cd_read.sectorArea = kCDSectorAreaUser; + + res = ioctl(ioctl_fd, DKIOCCDREAD, &cd_read); + //pclog("read res = %i %i %i\n", res, cd_read.bufferLength, errno); + + cd_close(ioctl_fd); +} + +static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + int c,d; + uint32_t temp; + uint32_t last_address = 0; + int seenAA = 0; + + pclog("ioctl_readtoc\n"); + //ioctl_cd_state = CD_STOPPED; + + if (!tocvalid) + { + int ioctl_fd = cd_open(); + + if (ioctl_fd <= 0) + return 4; + + tocvalid = read_toc(ioctl_fd); + cd_close(ioctl_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 = 0; c <= toc_tracks; c++) + { + if (toc->descriptors[c].point && toc->descriptors[c].point >= starttrack && toc->descriptors[c].point <= 99) + { + d = c; + break; + } + } + //pclog("Start from track %i\n",d); + b[2] = toc->descriptors[c].point; + //last_block = 0; + + for (c = d; c <= toc_tracks; 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->descriptors[c].point,toc->descriptors[c].adr,toc->descriptors[c].control,toc->descriptors[c].p.minute, toc->descriptors[c].p.second, toc->descriptors[c].p.frame,track_addr[c]); + address = track_addr[c]; + if (address < last_address) + continue; + if (toc->descriptors[c].point == 0xaa) + seenAA = 1; + last_address = address; + b[len++] = 0; /*Reserved*/ + b[len++] = (toc->descriptors[c].adr << 4) | toc->descriptors[c].control; + b[len++] = toc->descriptors[c].point; + b[len++] = 0; /*Reserved*/ + //if (address > last_block) + // last_block = address; + + if (msf) + { + b[len++] = 0; + b[len++] = toc->descriptors[c].p.minute; + b[len++] = toc->descriptors[c].p.second; + b[len++] = toc->descriptors[c].p.frame; + } + else + { + temp = track_addr[c]; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + if (single) + break; + } + + if (!seenAA && !single) + { + uint32_t lb = 0; + + for (c = 0; c <= toc_tracks; c++) + { + if (track_addr[c] > lb) + lb = track_addr[c]; + } + //pclog("Track AA - %08x %i\n", lb, len); + b[len++] = 0; /*Reserved*/ + b[len++] = (1 << 4) | 1; + b[len++] = 0xaa; + b[len++] = 0; /*Reserved*/ + + if (msf) + { + b[len++] = 0; + b[len++] = (lb / 60) / 75; + b[len++] = (lb / 75) % 60; + b[len++] = lb % 75; + } + else + { + temp = track_addr[c]; + b[len++] = lb >> 24; + b[len++] = lb >> 16; + b[len++] = lb >> 8; + b[len++] = lb; + } + } + + 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) +{ + int len = 4; + int session = 0, first_track_nr = 0; + int c, d; + + if (!tocvalid) + { + int ioctl_fd = cd_open(); + + if (ioctl_fd <= 0) + return 4; + + tocvalid = read_toc(ioctl_fd); + cd_close(ioctl_fd); + } + + if (!tocvalid) + return 4; + + for (c = 0; c <= toc_tracks; c++) + { + if (toc->descriptors[c].point && toc->descriptors[c].point <= 99) + { + if (toc->descriptors[c].session > session || (toc->descriptors[c].session == session && toc->descriptors[c].point < first_track_nr)) + { + session = toc->descriptors[c].session; + first_track_nr = toc->descriptors[c].point; + d = c; + } + } + } + + b[2] = toc->sessionFirst; + b[3] = toc->sessionLast; + b[len++] = 0; /*Reserved*/ + b[len++] = (toc->descriptors[d].adr << 4) | toc->descriptors[d].control; + b[len++] = toc->descriptors[d].point; + b[len++] = 0; /*Reserved*/ + if (msf) + { + b[len++] = 0; + b[len++] = toc->descriptors[d].p.minute; + b[len++] = toc->descriptors[d].p.second; + b[len++] = toc->descriptors[d].p.frame; + } + else + { + uint32_t temp = track_addr[d]; + 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 ioctl_fd; + int track; + +//pclog("read_toc\n"); + if (!tocvalid) + return 0; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return 0; + cd_close(ioctl_fd); + + b[2] = toc->sessionFirst; + b[3] = toc->sessionLast; + + for (track = 0; track <= toc_tracks; track++) + { + if ((len + 11) > maxlen) + { + pclog("ioctl_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); + return len; + } + + +// 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++] = toc->descriptors[track].session; + b[len++] = (toc->descriptors[track].adr << 4) | toc->descriptors[track].control; + b[len++] = toc->descriptors[track].tno; + b[len++] = toc->descriptors[track].point; + b[len++] = toc->descriptors[track].address.minute; + b[len++] = toc->descriptors[track].address.second; + b[len++] = toc->descriptors[track].address.frame; + b[len++] = toc->descriptors[track].zero; + b[len++] = toc->descriptors[track].p.minute; + b[len++] = toc->descriptors[track].p.second; + b[len++] = toc->descriptors[track].p.frame; + } + + return len; +} + +static uint32_t ioctl_size() +{ + return cdrom_capacity; +} + +static int ioctl_status() +{ + if (!ioctl_ready) + return CD_STATUS_EMPTY; + return CD_STATUS_STOPPED; +} +void ioctl_reset() +{ + int ioctl_fd; + + tocvalid = 0; + + ioctl_fd = cd_open(); + if (ioctl_fd <= 0) + return; + + tocvalid = read_toc(ioctl_fd); + cd_close(ioctl_fd); +} + +void ioctl_set_drive(char d) +{ + ioctl_close(); + atapi=&ioctl_atapi; + ioctl_open(d); +} + +int ioctl_open(char d) +{ + atapi = &ioctl_atapi; + + toc = malloc(2048); + + cd_drive = d; + return 0; +} + +void ioctl_close(void) +{ + if (toc) + { + free(toc); + toc = NULL; + } +} + +static void ioctl_exit(void) +{ + +} + +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 index 2d4f176..8c8eb2b 100644 --- a/src/cdrom-ioctl.c +++ b/src/cdrom-ioctl.c @@ -2,7 +2,7 @@ #include #include -#ifdef __MINGW64__ +#ifdef __MINGW64_VERSION_MAJOR #include "ntddcdrm.h" #include "ntddscsi.h" #else @@ -16,7 +16,7 @@ int cdrom_drive; int old_cdrom_drive; -#ifndef __MINGW64__ +#ifndef __MINGW64_VERSION_MAJOR typedef struct _CDROM_TOC_SESSION_DATA { UCHAR Length[2]; UCHAR FirstCompleteSession; @@ -58,10 +58,7 @@ void ioctl_audio_callback(int16_t *output, int len) // 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) @@ -435,11 +432,11 @@ typedef struct _SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER { UCHAR SenseBuf[32]; } SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER; -static int ioctl_readsector(uint8_t *b, int sector) +static int ioctl_readsector(uint8_t *b, int sector, int count) { LARGE_INTEGER pos; BOOL status; - long size; + long size = 0; if (!cdrom_drive) return -1; @@ -451,16 +448,18 @@ static int ioctl_readsector(uint8_t *b, int sector) pos.QuadPart=sector*2048; ioctl_open(0); SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN); - status = ReadFile(hIOCTL,b,2048,(LPDWORD)&size,NULL); + status = ReadFile(hIOCTL, b, count*2048, (LPDWORD)&size, NULL); ioctl_close(); - /*If the read failed, try again using SPTI*/ - if (!status || size != 2048) + /*If the read 'succeeded' but didn't read all required data, try again using SPTI*/ + if (status && size != count*2048) { uint8_t cmd[12] = { 0xbe, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb; DWORD returned; - uint8_t data_buffer[IOCTL_DATA_BUFFER]; + uint8_t *data_buffer;//[IOCTL_DATA_BUFFER]; + + data_buffer = malloc(count * IOCTL_DATA_BUFFER); ioctl_open(0); @@ -469,6 +468,9 @@ static int ioctl_readsector(uint8_t *b, int sector) cmd[3] = (uint8_t)(sector >> 16); cmd[4] = (uint8_t)(sector >> 8); cmd[5] = (uint8_t)(sector >> 0); + cmd[6] = (uint8_t)(count >> 16); + cmd[7] = (uint8_t)(count >> 8); + cmd[8] = (uint8_t)(count >> 0); memset(&swb, 0, sizeof (swb)); memcpy(swb.spt.Cdb, cmd, 12); @@ -476,9 +478,9 @@ static int ioctl_readsector(uint8_t *b, int sector) swb.spt.Length = sizeof (SCSI_PASS_THROUGH); swb.spt.CdbLength = 12; swb.spt.DataIn = SCSI_IOCTL_DATA_IN; - swb.spt.DataTransferLength = IOCTL_DATA_BUFFER; + swb.spt.DataTransferLength = count*IOCTL_DATA_BUFFER; swb.spt.DataBuffer = data_buffer; - memset(data_buffer, 0, IOCTL_DATA_BUFFER); + memset(data_buffer, 0, count*IOCTL_DATA_BUFFER); swb.spt.TimeOutValue = 80 * 60; swb.spt.SenseInfoOffset = (uintptr_t)&swb.SenseBuf - (uintptr_t)&swb;//offsetof(swb, SenseBuf); swb.spt.SenseInfoLength = 32; @@ -487,9 +489,16 @@ static int ioctl_readsector(uint8_t *b, int sector) &swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), &swb, sizeof (SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), &returned, NULL)) - memcpy(b, data_buffer, 2048); + { + memcpy(b, data_buffer, count*2048); + status = 1; + } + else + status = 0; ioctl_close(); + + free(data_buffer); } return !status; @@ -503,14 +512,19 @@ static int is_track_audio(uint32_t pos) if (!tocvalid) return 0; - for (c = toc.FirstTrack; c < toc.LastTrack; c++) + for (c = 0; toc.TrackData[c].TrackNumber != 0xaa; 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) + if (toc.TrackData[c].TrackNumber >= toc.FirstTrack && + toc.TrackData[c].TrackNumber <= toc.LastTrack && + track_address >= pos) + { control = toc.TrackData[c].Control; + break; + } } return (control & 4) ? 0 : 1; } @@ -565,7 +579,6 @@ static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, in break; } } - b[2]=toc.TrackData[c].TrackNumber; last_block = 0; for (c=d;c<=toc.LastTrack;c++) { @@ -737,14 +750,20 @@ void ioctl_reset() void ioctl_set_drive(char d) { + ioctl_close(); + sprintf(ioctl_path, "\\\\.\\%c:", d); pclog("Path is %s\n", ioctl_path); tocvalid = 0; atapi = &ioctl_atapi; + + ioctl_open(d); } int ioctl_open(char d) { + if (hIOCTL) + ioctl_close(); hIOCTL = CreateFile(ioctl_path,GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL); if (!hIOCTL) diff --git a/src/cdrom-iso.c b/src/cdrom-iso.c deleted file mode 100644 index 220b073..0000000 --- a/src/cdrom-iso.c +++ /dev/null @@ -1,356 +0,0 @@ -/*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 = NULL; -static int iso_changed = 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 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) - return 1; - - iso_changed = 0; - 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) -{ - iso_changed = 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 int iso_readsector(uint8_t *b, int sector) -{ - if (!cdrom_drive) - return -1; - fseek(iso_image,sector*2048,SEEK_SET); - fread(b,2048,1,iso_image); - return 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; -} - -static void iso_readsector_raw(uint8_t *b, int sector) -{ - if (!cdrom_drive) return; - fseek(iso_image, sector*2048, SEEK_SET); - fread(b+16, 2048, 1, 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) -{ - struct stat st; - - if (iso_image) - fclose(iso_image); - - if (strcmp(fn, iso_path) != 0) - iso_changed = 1; - - /* Make sure iso_changed stays when changing from ISO to another ISO. */ - if (cdrom_drive != CDROM_ISO) - iso_changed = 1; - strcpy(iso_path, fn); - - iso_image = fopen(iso_path, "rb"); - atapi = &iso_atapi; - - stat(iso_path, &st); - image_size = st.st_size; - - return 0; -} - -void iso_close(void) -{ - if (iso_image) - { - fclose(iso_image); - iso_image = NULL; - } - memset(iso_path, 0, 1024); -} - -static void iso_exit(void) -{ - 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 deleted file mode 100644 index d4efd06..0000000 --- a/src/cdrom-iso.h +++ /dev/null @@ -1,13 +0,0 @@ -#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(); - -#endif /* ! CDROM_ISO_H */ diff --git a/src/cdrom-null.c b/src/cdrom-null.c index 5ba7320..d62f28b 100644 --- a/src/cdrom-null.c +++ b/src/cdrom-null.c @@ -59,7 +59,7 @@ static void null_load(void) { } -static int null_readsector(uint8_t *b, int sector) +static int null_readsector(uint8_t *b, int sector, int count) { return 0; } diff --git a/src/cmd640.c b/src/cmd640.c new file mode 100644 index 0000000..1e8b8f9 --- /dev/null +++ b/src/cmd640.c @@ -0,0 +1,71 @@ +/*CMD640 emulation + Currently only legacy mode emulated*/ +#include "ibm.h" +#include "cmd640.h" +#include "ide.h" +#include "pci.h" + +static uint8_t card_cmd640[256]; + +void cmd640_write(int func, int addr, uint8_t val, void *priv) +{ +// pclog("cmd640_write: func=%d addr=%02x val=%02x %04x:%08x\n", func, addr, val, CS, cpu_state.pc); + if (func > 0) + return; + + switch (addr) + { + case 0x04: + ide_pri_disable(); + ide_sec_disable(); + if (val & 0x01) + { + ide_pri_enable(); + ide_sec_enable(); + } + card_cmd640[0x04] = val & 0x41; + break; + case 0x07: + card_cmd640[0x07] = val & 0x86; + break; + case 0x3c: + card_cmd640[0x3c] = val; + break; + } +} + +static uint8_t cmd640_read(int func, int addr, void *p) +{ +// pclog("cmd640_read: func=%d addr=%02x val=%02x %04x:%08x\n", func, addr, card_cmd640[addr], CS, cpu_state.pc); + if (func > 0) + return 0xff; + + return card_cmd640[addr]; +} + +void cmd640b_init(int card) +{ + pci_add_specific(card, cmd640_read, cmd640_write, NULL); + + memset(card_cmd640, 0, 256); + card_cmd640[0x00] = 0x95; card_cmd640[0x01] = 0x10; /**/ + card_cmd640[0x02] = 0x40; card_cmd640[0x03] = 0x06; /*CMD640*/ + card_cmd640[0x04] = 0x01; card_cmd640[0x05] = 0x00; + card_cmd640[0x06] = 0x00; card_cmd640[0x07] = 0x02; + card_cmd640[0x08] = 0x00; /*Revision*/ + card_cmd640[0x09] = 0x00; /*Programming interface*/ + card_cmd640[0x0a] = 0x01; /*Sub class - IDE controller*/ + card_cmd640[0x0b] = 0x01; /*Base class - Mass storage controller*/ + + + card_cmd640[0x3c] = 0x0e; /*Interrupt line*/ + card_cmd640[0x3d] = 1; + + card_cmd640[0x50] = 0x02; /*Revision = 2*/ + card_cmd640[0x51] = 0x80; /*2nd port disabled, drive 1 read ahead disabled*/ + card_cmd640[0x57] = 0x0c; /*Drive 2/3 read ahead disabled*/ + card_cmd640[0x59] = 0x40; /*Burst length*/ + + ide_pri_disable(); + ide_sec_disable(); +} diff --git a/src/cmd640.h b/src/cmd640.h new file mode 100644 index 0000000..5371669 --- /dev/null +++ b/src/cmd640.h @@ -0,0 +1 @@ +void cmd640b_init(int card); diff --git a/src/codegen.c b/src/codegen.c index 8256ab2..373c15c 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -2,12 +2,65 @@ #include "x86_ops.h" #include "mem.h" #include "codegen.h" +#include "x86.h" + +#include "386_common.h" + +#include "codegen_accumulate.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" + +#define MAX_INSTRUCTION_COUNT 50 + +static struct +{ + uint32_t pc; + int op_ssegs; + x86seg *op_ea_seg; + uint32_t op_32; + int first_uop; + int TOP; +} codegen_instructions[MAX_INSTRUCTION_COUNT]; + +int codegen_get_instruction_uop(codeblock_t *block, uint32_t pc, int *first_instruction, int *TOP) +{ + int c; + + for (c = 0; c <= block->ins; c++) + { + if (codegen_instructions[c].pc == pc) + { + *first_instruction = c; + *TOP = codegen_instructions[c].TOP; + return codegen_instructions[c].first_uop; + } + } + + *first_instruction = block->ins; + return -1; +} + +void codegen_set_loop_start(ir_data_t *ir, int first_instruction) +{ + uop_MOV_IMM(ir, IREG_op32, codegen_instructions[first_instruction].op_32); + uop_MOV_PTR(ir, IREG_ea_seg, (void *)codegen_instructions[first_instruction].op_ea_seg); + uop_MOV_IMM(ir, IREG_ssegs, codegen_instructions[first_instruction].op_ssegs); +} + +int has_ea; + +codeblock_t *codeblock; +uint16_t *codeblock_hash; 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_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); void (*codegen_timing_block_start)(); void (*codegen_timing_block_end)(); +int (*codegen_timing_jump_cycles)(); void codegen_timing_set(codegen_timing_t *timing) { @@ -16,6 +69,706 @@ void codegen_timing_set(codegen_timing_t *timing) codegen_timing_opcode = timing->opcode; codegen_timing_block_start = timing->block_start; codegen_timing_block_end = timing->block_end; + codegen_timing_jump_cycles = timing->jump_cycles; } int codegen_in_recompile; + +static int last_op_ssegs; +static x86seg *last_op_ea_seg; +static uint32_t last_op_32; + +void codegen_generate_reset() +{ + last_op_ssegs = -1; + last_op_ea_seg = NULL; + last_op_32 = -1; + has_ea = 0; +} + +void codegen_check_seg_read(codeblock_t *block, ir_data_t *ir, x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) + return; + if (seg->checked) + return; + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + uop_CMP_IMM_JZ(ir, ireg_seg_base(seg), (uint32_t)-1, codegen_gpf_rout); + + seg->checked = 1; +} +void codegen_check_seg_write(codeblock_t *block, ir_data_t *ir, x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (cpu_state.eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &cpu_state.seg_cs || seg == &cpu_state.seg_ss) + return; + if (seg->checked) + return; + if (seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + uop_CMP_IMM_JZ(ir, ireg_seg_base(seg), (uint32_t)-1, codegen_gpf_rout); + + seg->checked = 1; +} + +static x86seg *codegen_generate_ea_16_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + uint32_t old_pc = (*op_pc) + 1; +// pclog("codegen - mod=%i rm=%i reg=%i fetchdat=%08x\n", cpu_mod, cpu_rm, cpu_reg, fetchdat); + if (!cpu_mod && cpu_rm == 6) + { + uint16_t addr = (fetchdat >> 8) & 0xffff; + uop_MOV_IMM(ir, IREG_eaaddr, addr); + (*op_pc) += 2; + } + else + { + int base_reg, index_reg, offset; + + switch (cpu_rm & 7) + { + case 0: case 1: case 7: + base_reg = IREG_EBX; + break; + case 2: case 3: case 6: + base_reg = IREG_EBP; + break; + case 4: + base_reg = IREG_ESI; + break; + case 5: + base_reg = IREG_EDI; + break; + } + uop_MOV(ir, IREG_eaaddr, base_reg); + + if (!(cpu_rm & 4)) + { + if (!(cpu_rm & 1)) + index_reg = IREG_ESI; + else + index_reg = IREG_EDI; + + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, index_reg); + } + + switch (cpu_mod) + { + case 1: + offset = (int)(int8_t)((fetchdat >> 8) & 0xff); + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, offset); + (*op_pc)++; + break; + case 2: + offset = (fetchdat >> 8) & 0xffff; + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, offset); + (*op_pc) += 2; + break; + } + + uop_AND_IMM(ir, IREG_eaaddr, IREG_eaaddr, 0xffff); + + if (mod1seg[cpu_rm] == &ss && !op_ssegs) + { + op_ea_seg = &cpu_state.seg_ss; + } + } + + codegen_mark_code_present(ir->block, cs+old_pc, ((*op_pc)+1)-old_pc); + return op_ea_seg; +} + +static x86seg *codegen_generate_ea_32_long(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + codeblock_t *block = ir->block; + uint32_t old_pc = (*op_pc) + 1; + uint32_t new_eaaddr; + int extra_bytes = 0; + + if (cpu_rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (cpu_mod) + { + case 0: + if ((sib & 7) == 5) + { + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_eaaddr, cs + (*op_pc) + 1); + extra_bytes = 1; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + extra_bytes = 5; + } + (*op_pc) += 4; + } + else + { + uop_MOV(ir, IREG_eaaddr, sib & 7); + extra_bytes = 1; + } + break; + case 1: + new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, sib & 7); + (*op_pc)++; + extra_bytes = 2; + break; + case 2: + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_eaaddr, cs + (*op_pc) + 1); + extra_bytes = 1; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + extra_bytes = 5; + } + (*op_pc) += 4; + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, sib & 7); + break; + } + if (stack_offset && (sib & 7) == 4 && (cpu_mod || (sib & 7) != 5)) /*ESP*/ + { + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, stack_offset); +// addbyte(0x05); +// addlong(stack_offset); + } + if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &cpu_state.seg_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7); + break; + case 1: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 1); + break; + case 2: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 2); + break; + case 3: + uop_ADD_LSHIFT(ir, IREG_eaaddr, IREG_eaaddr, (sib >> 3) & 7, 3); + break; + } + } + } + else + { + if (!cpu_mod && cpu_rm == 5) + { + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_eaaddr, cs + (*op_pc) + 1); + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_MOV_IMM(ir, IREG_eaaddr, new_eaaddr); + extra_bytes = 4; + } + + (*op_pc) += 4; + } + else + { + uop_MOV(ir, IREG_eaaddr, cpu_rm); + if (cpu_mod) + { + if (cpu_rm == 5 && !op_ssegs) + op_ea_seg = &cpu_state.seg_ss; + if (cpu_mod == 1) + { + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, (uint32_t)(int8_t)(fetchdat >> 8)); + (*op_pc)++; + extra_bytes = 1; + } + else + { + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + (*op_pc) + 1); + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, IREG_temp0); + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + uop_ADD_IMM(ir, IREG_eaaddr, IREG_eaaddr, new_eaaddr); + extra_bytes = 4; + } + (*op_pc) += 4; + } + } + } + } + + if (extra_bytes) + codegen_mark_code_present(ir->block, cs+old_pc, extra_bytes); + + return op_ea_seg; +} + +x86seg *codegen_generate_ea(ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32, int stack_offset) +{ + cpu_mod = (fetchdat >> 6) & 3; + cpu_reg = (fetchdat >> 3) & 7; + cpu_rm = fetchdat & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return NULL; + if (op_32 & 0x200) + return codegen_generate_ea_32_long(ir, op_ea_seg, fetchdat, op_ssegs, op_pc, stack_offset); + + return codegen_generate_ea_16_long(ir, op_ea_seg, fetchdat, op_ssegs, op_pc); +} + +static uint8_t 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*/ +}; +static uint8_t opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*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, 0, 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_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) +{ + codeblock_t *block = &codeblock[block_current]; + ir_data_t *ir = codegen_get_ir_data(); + 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; + uint32_t recomp_opcode_mask = 0x1ff; + uint32_t op_32 = use32; + int over = 0; + int test_modrm = 1; + int pc_off = 0; + uint32_t next_pc = 0; +#ifdef DEBUG_EXTRA + uint8_t last_prefix = 0; +#endif + op_ea_seg = &cpu_state.seg_ds; + op_ssegs = 0; + + codegen_timing_start(); + + while (!over) + { + switch (opcode) + { + case 0x0f: +#ifdef DEBUG_EXTRA + last_prefix = 0x0f; +#endif + op_table = x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &cpu_state.seg_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &cpu_state.seg_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &cpu_state.seg_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &cpu_state.seg_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &cpu_state.seg_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &cpu_state.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: +#ifdef DEBUG_EXTRA + last_prefix = 0xd8; +#endif + 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; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xd9: +#ifdef DEBUG_EXTRA + last_prefix = 0xd9; +#endif + 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; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xda: +#ifdef DEBUG_EXTRA + last_prefix = 0xda; +#endif + 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; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdb: +#ifdef DEBUG_EXTRA + last_prefix = 0xdb; +#endif + 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; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdc: +#ifdef DEBUG_EXTRA + last_prefix = 0xdc; +#endif + 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; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdd: +#ifdef DEBUG_EXTRA + last_prefix = 0xdd; +#endif + 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; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xde: +#ifdef DEBUG_EXTRA + last_prefix = 0xde; +#endif + 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; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdf: +#ifdef DEBUG_EXTRA + last_prefix = 0xdf; +#endif + 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; + block->flags |= CODEBLOCK_HAS_FPU; + break; + + case 0xf0: /*LOCK*/ + break; + + case 0xf2: /*REPNE*/ +#ifdef DEBUG_EXTRA + last_prefix = 0xf2; +#endif + op_table = x86_dynarec_opcodes_REPNE; + recomp_op_table = NULL;//recomp_opcodes_REPNE; + break; + case 0xf3: /*REPE*/ +#ifdef DEBUG_EXTRA + last_prefix = 0xf3; +#endif + op_table = x86_dynarec_opcodes_REPE; + recomp_op_table = NULL;//recomp_opcodes_REPE; + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); + codegen_timing_prefix(opcode, fetchdat); + if (cpu_state.abrt) + return; + opcode = fetchdat & 0xff; + if (!pc_off) + fetchdat >>= 8; + + op_pc++; + } + +generate_call: + codegen_instructions[block->ins].pc = cpu_state.oldpc; + codegen_instructions[block->ins].op_ssegs = last_op_ssegs; + codegen_instructions[block->ins].op_ea_seg = last_op_ea_seg; + codegen_instructions[block->ins].op_32 = last_op_32; + codegen_instructions[block->ins].TOP = cpu_state.TOP; + codegen_instructions[block->ins].first_uop = ir->wr_pos; + + codegen_timing_opcode(opcode, fetchdat, op_32, op_pc); + + codegen_accumulate(ACCREG_ins, 1); + codegen_accumulate(ACCREG_cycles, -codegen_block_cycles); + codegen_block_cycles = 0; + + 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))) + { + /*On some CPUs (eg K6), a jump/branch instruction may be able to pair with + subsequent instructions, so no cycles may have been deducted for it yet. + To prevent having zero cycle blocks (eg with a jump instruction pointing + to itself), apply the cycles that would be taken if this jump is taken, + then reverse it for subsequent instructions if the jump is not taken*/ + int jump_cycles = codegen_timing_jump_cycles(); + + if (jump_cycles) + codegen_accumulate(ACCREG_cycles, -jump_cycles); + codegen_accumulate_flush(ir); + if (jump_cycles) + codegen_accumulate(ACCREG_cycles, jump_cycles); + } + + if (op_table == x86_dynarec_opcodes_0f && opcode == 0x0f) + { + /*3DNow opcodes are stored after ModR/M, SIB and any offset*/ + uint8_t modrm = fetchdat & 0xff; + uint8_t sib = (fetchdat >> 8) & 0xff; + uint32_t opcode_pc = op_pc + 1; + uint8_t opcode_3dnow; + + if ((modrm & 0xc0) != 0xc0) + { + if (op_32 & 0x200) + { + if ((modrm & 7) == 4) + { + /* Has SIB*/ + opcode_pc++; + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 4; + else if ((sib & 0x07) == 0x05) + opcode_pc += 4; + } + else + { + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 4; + else if ((modrm & 0xc7) == 0x05) + opcode_pc += 4; + } + } + else + { + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 2; + else if ((modrm & 0xc7) == 0x06) + opcode_pc += 2; + } + } + + opcode_3dnow = fastreadb(cs + opcode_pc); +// pclog("recomp_opcodes_3DNOW[%02x]=%p\n", opcode, recomp_opcodes_3DNOW[opcode]); + if (recomp_opcodes_3DNOW[opcode_3dnow]) + { + next_pc = opcode_pc + 1; + + op_table = x86_dynarec_opcodes_3DNOW; + recomp_op_table = recomp_opcodes_3DNOW; + opcode = opcode_3dnow; + recomp_opcode_mask = 0xff; + opcode_mask = 0xff; + } + } + codegen_mark_code_present(block, cs+old_pc, (op_pc - old_pc) - pc_off); +// pclog("%04x:%08x : %02x\n", CS, new_pc, opcode); + if (recomp_op_table && recomp_op_table[(opcode | op_32) & recomp_opcode_mask]) + { + uint32_t new_pc = recomp_op_table[(opcode | op_32) & recomp_opcode_mask](block, ir, opcode, fetchdat, op_32, op_pc); + if (new_pc) + { + if (new_pc != -1) + uop_MOV_IMM(ir, IREG_pc, new_pc); + + codegen_endpc = (cs + cpu_state.pc) + 8; + + block->ins++; + + if (block->ins >= MAX_INSTRUCTION_COUNT) + CPU_BLOCK_END(); + + return; + } + } + + if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) + { + op_table = x86_dynarec_opcodes; + recomp_op_table = recomp_opcodes; + } + + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; + + if (!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_3DNOW)) + { + int stack_offset = 0; + + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ + stack_offset = (op_32 & 0x100) ? 4 : 2; + + cpu_mod = (fetchdat >> 6) & 3; + cpu_reg = (fetchdat >> 3) & 7; + cpu_rm = fetchdat & 7; + + uop_MOV_IMM(ir, IREG_rm_mod_reg, cpu_rm | (cpu_mod << 8) | (cpu_reg << 16)); + + op_pc += pc_off; + if (cpu_mod != 3 && !(op_32 & 0x200)) + { + op_ea_seg = codegen_generate_ea_16_long(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc); +// has_ea = 1; + } + if (cpu_mod != 3 && (op_32 & 0x200)) + { + op_ea_seg = codegen_generate_ea_32_long(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); +// has_ea = 1; + } +// op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); + op_pc -= pc_off; + } + +#ifdef DEBUG_EXTRA + uop_LOG_INSTR(ir, opcode | (last_prefix << 8)); +#endif + codegen_accumulate_flush(ir); + if (op_table == x86_dynarec_opcodes_3DNOW) + uop_MOV_IMM(ir, IREG_pc, next_pc); + else + uop_MOV_IMM(ir, IREG_pc, op_pc+pc_off); + uop_MOV_IMM(ir, IREG_oldpc, old_pc); + if (op_32 != last_op_32) + uop_MOV_IMM(ir, IREG_op32, op_32); + if (op_ea_seg != last_op_ea_seg) + uop_MOV_PTR(ir, IREG_ea_seg, (void *)op_ea_seg); + if (op_ssegs != last_op_ssegs) + uop_MOV_IMM(ir, IREG_ssegs, op_ssegs); + uop_LOAD_FUNC_ARG_IMM(ir, 0, fetchdat); + uop_CALL_INSTRUCTION_FUNC(ir, op); + codegen_mark_code_present(block, cs+cpu_state.pc, 8); + + last_op_32 = op_32; + last_op_ea_seg = op_ea_seg; + last_op_ssegs = op_ssegs; + //codegen_block_ins++; + + block->ins++; + + if (block->ins >= MAX_INSTRUCTION_COUNT) + CPU_BLOCK_END(); + + codegen_endpc = (cs + cpu_state.pc) + 8; + +// if (has_ea) +// fatal("Has EA\n"); +} diff --git a/src/codegen.h b/src/codegen.h index e715915..83f37ae 100644 --- a/src/codegen.h +++ b/src/codegen.h @@ -1,12 +1,8 @@ -#include "mem.h" +#ifndef _CODEGEN_H_ +#define _CODEGEN_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 +#include "mem.h" +#include "x86_ops.h" /*Handling self-modifying code (of which there is a lot on x86) : @@ -35,53 +31,88 @@ typedef struct codeblock_t { + uint32_t pc; + uint32_t _cs; + uint32_t phys, phys_2; + uint16_t status; + uint16_t flags; + uint8_t ins; + uint8_t TOP; + + /*Pointers for codeblock tree, used to search for blocks when hash lookup + fails.*/ + uint16_t parent, left, right; + + uint8_t *data; + + uint64_t page_mask, page_mask2; + uint64_t *dirty_mask, *dirty_mask2; + /*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; - - int was_recompiled; - uint32_t flags; - int TOP; - - uint64_t cmp; - - uint8_t data[2048]; + uint16_t prev, next; + uint16_t prev_2, next_2; + + /*First mem_block_t used by this block. Any subsequent mem_block_ts + will be in the list starting at head_mem_block->next.*/ + struct mem_block_t *head_mem_block; } codeblock_t; +extern codeblock_t *codeblock; + +extern uint16_t *codeblock_hash; + +extern uint8_t *block_write_data; + /*Code block uses FPU*/ #define CODEBLOCK_HAS_FPU 1 /*Code block is always entered with the same FPU top-of-stack*/ #define CODEBLOCK_STATIC_TOP 2 +/*Code block has been compiled*/ +#define CODEBLOCK_WAS_RECOMPILED 4 +/*Code block is in free list and is not valid*/ +#define CODEBLOCK_IN_FREE_LIST 8 +/*Code block spans two pages, page_mask2 and dirty_mask2 are valid*/ +#define CODEBLOCK_HAS_PAGE2 0x10 +/*Code block is using a byte mask for code present and dirty*/ +#define CODEBLOCK_BYTE_MASK 0x20 +/*Code block is in dirty list*/ +#define CODEBLOCK_IN_DIRTY_LIST 0x40 +/*Code block is not inlining immediate parameters, parameters must be fetched from memory*/ +#define CODEBLOCK_NO_IMMEDIATES 0x80 + +#define BLOCK_PC_INVALID 0xffffffff + +#define BLOCK_INVALID 0 + +static inline int get_block_nr(codeblock_t *block) +{ + return ((uintptr_t)block - (uintptr_t)codeblock) / sizeof(codeblock_t); +} static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) { - codeblock_t *block = pages[phys >> 12].head; + codeblock_t *block; uint64_t a = _cs | ((uint64_t)phys << 32); + if (!pages[phys >> 12].head) + return NULL; + + block = &codeblock[pages[phys >> 12].head]; while (block) { - if (a == block->cmp) - break; - else if (a < block->cmp) - block = block->left; + uint64_t block_cmp = block->_cs | ((uint64_t)block->phys << 32); + if (a == block_cmp) + { + if (!((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK))) + break; + } + if (a < block_cmp) + block = block->left ? &codeblock[block->left] : NULL; else - block = block->right; + block = block->right ? &codeblock[block->right] : NULL; } return block; @@ -89,75 +120,87 @@ static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) static inline void codeblock_tree_add(codeblock_t *new_block) { - codeblock_t *block = pages[new_block->phys >> 12].head; + codeblock_t *block = &codeblock[pages[new_block->phys >> 12].head]; uint64_t a = new_block->_cs | ((uint64_t)new_block->phys << 32); - new_block->cmp = a; - - if (!block) + + if (!pages[new_block->phys >> 12].head) { - pages[new_block->phys >> 12].head = new_block; - new_block->parent = new_block->left = new_block->right = NULL; + pages[new_block->phys >> 12].head = get_block_nr(new_block); + new_block->parent = new_block->left = new_block->right = BLOCK_INVALID; } else { codeblock_t *old_block = NULL; + uint64_t old_block_cmp = 0; while (block) { old_block = block; - if (a < old_block->cmp) - block = block->left; + old_block_cmp = old_block->_cs | ((uint64_t)old_block->phys << 32); + + if (a < old_block_cmp) + block = block->left ? &codeblock[block->left] : NULL; else - block = block->right; + block = block->right ? &codeblock[block->right] : NULL; } - if (a < old_block->cmp) - old_block->left = new_block; + if (a < old_block_cmp) + old_block->left = get_block_nr(new_block); else - old_block->right = new_block; + old_block->right = get_block_nr(new_block); - new_block->parent = old_block; - new_block->left = new_block->right = NULL; + new_block->parent = get_block_nr(old_block); + new_block->left = new_block->right = BLOCK_INVALID; } } static inline void codeblock_tree_delete(codeblock_t *block) { - codeblock_t *parent = block->parent; + uint16_t parent_nr = block->parent; + codeblock_t *parent; + + if (block->parent) + parent = &codeblock[block->parent]; + else + parent = NULL; if (!block->left && !block->right) { /*Easy case - remove from parent*/ if (!parent) - pages[block->phys >> 12].head = NULL; + pages[block->phys >> 12].head = BLOCK_INVALID; else { - if (parent->left == block) - parent->left = NULL; - if (parent->right == block) - parent->right = NULL; + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) + parent->left = BLOCK_INVALID; + if (parent->right == block_nr) + parent->right = BLOCK_INVALID; } return; } else if (!block->left) { /*Only right node*/ - if (!parent) + if (!parent_nr) { pages[block->phys >> 12].head = block->right; - pages[block->phys >> 12].head->parent = NULL; + codeblock[pages[block->phys >> 12].head].parent = BLOCK_INVALID; } else { - if (parent->left == block) + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) { parent->left = block->right; - parent->left->parent = parent; + codeblock[parent->left].parent = parent_nr; } - if (parent->right == block) + if (parent->right == block_nr) { parent->right = block->right; - parent->right->parent = parent; + codeblock[parent->right].parent = parent_nr; } } return; @@ -165,22 +208,24 @@ static inline void codeblock_tree_delete(codeblock_t *block) else if (!block->right) { /*Only left node*/ - if (!parent) + if (!parent_nr) { pages[block->phys >> 12].head = block->left; - pages[block->phys >> 12].head->parent = NULL; + codeblock[pages[block->phys >> 12].head].parent = BLOCK_INVALID; } else { - if (parent->left == block) + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) { parent->left = block->left; - parent->left->parent = parent; + codeblock[parent->left].parent = parent_nr; } - if (parent->right == block) + if (parent->right == block_nr) { parent->right = block->left; - parent->right->parent = parent; + codeblock[parent->right].parent = parent_nr; } } return; @@ -188,50 +233,54 @@ static inline void codeblock_tree_delete(codeblock_t *block) else { /*Difficult case - node has two children. Walk right child to find lowest node*/ - codeblock_t *lowest = block->right, *highest; + codeblock_t *lowest = &codeblock[block->right], *highest; codeblock_t *old_parent; + uint16_t lowest_nr; while (lowest->left) - lowest = lowest->left; - - old_parent = lowest->parent; + lowest = &codeblock[lowest->left]; + lowest_nr = get_block_nr(lowest); + + old_parent = &codeblock[lowest->parent]; /*Replace deleted node with lowest node*/ - if (!parent) - pages[block->phys >> 12].head = lowest; + if (!parent_nr) + pages[block->phys >> 12].head = lowest_nr; else { - if (parent->left == block) - parent->left = lowest; - if (parent->right == block) - parent->right = lowest; + uint16_t block_nr = get_block_nr(block); + + if (parent->left == block_nr) + parent->left = lowest_nr; + if (parent->right == block_nr) + parent->right = lowest_nr; } - lowest->parent = parent; + lowest->parent = parent_nr; lowest->left = block->left; if (lowest->left) - lowest->left->parent = lowest; + codeblock[lowest->left].parent = lowest_nr; - old_parent->left = NULL; + old_parent->left = BLOCK_INVALID; - highest = lowest->right; - if (!highest) + highest = &codeblock[lowest->right]; + if (!lowest->right) { - if (lowest != block->right) + if (lowest_nr != block->right) { lowest->right = block->right; - block->right->parent = lowest; + codeblock[block->right].parent = lowest_nr; } return; } while (highest->right) - highest = highest->right; + highest = &codeblock[highest->right]; - if (block->right && block->right != lowest) + if (block->right && block->right != lowest_nr) { highest->right = block->right; - block->right->parent = highest; + codeblock[block->right].parent = get_block_nr(highest); } } } @@ -239,22 +288,54 @@ static inline void codeblock_tree_delete(codeblock_t *block) #define PAGE_MASK_MASK 63 #define PAGE_MASK_SHIFT 6 -extern codeblock_t *codeblock; +void codegen_mark_code_present_multibyte(codeblock_t *block, uint32_t start_pc, int len); -extern codeblock_t **codeblock_hash; +static inline void codegen_mark_code_present(codeblock_t *block, uint32_t start_pc, int len) +{ + if (len == 1) + { + if (block->flags & CODEBLOCK_BYTE_MASK) + { + if (!((start_pc ^ block->pc) & ~0x3f)) /*Starts in second page*/ + block->page_mask |= ((uint64_t)1 << (start_pc & PAGE_MASK_MASK)); + else + block->page_mask2 |= ((uint64_t)1 << (start_pc & PAGE_MASK_MASK)); + } + else + { + if (!((start_pc ^ block->pc) & ~0xfff)) /*Starts in second page*/ + block->page_mask |= ((uint64_t)1 << ((start_pc >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK)); + else + block->page_mask2 |= ((uint64_t)1 << ((start_pc >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK)); + } + } + else + codegen_mark_code_present_multibyte(block, start_pc, len); +} void codegen_init(); +void codegen_close(); void codegen_reset(); void codegen_block_init(uint32_t phys_addr); void codegen_block_remove(); void codegen_block_start_recompile(codeblock_t *block); void codegen_block_end_recompile(codeblock_t *block); void codegen_block_end(); +void codegen_delete_block(codeblock_t *block); 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_set_op32(); void codegen_flush(); void codegen_check_flush(struct page_t *page, uint64_t mask, uint32_t phys_addr); +struct ir_data_t; +x86seg *codegen_generate_ea(struct ir_data_t *ir, x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32, int stack_offset); +void codegen_check_seg_read(codeblock_t *block, struct ir_data_t *ir, x86seg *seg); +void codegen_check_seg_write(codeblock_t *block, struct ir_data_t *ir, x86seg *seg); + +int codegen_purge_purgable_list(); +/*Delete a random code block to free memory. This is obviously quite expensive, and + will only be called when the allocator is out of memory*/ +void codegen_delete_random_block(int required_mem_block); extern int cpu_block_end; extern uint32_t codegen_endpc; @@ -273,23 +354,29 @@ 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_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); extern void (*codegen_timing_block_start)(); extern void (*codegen_timing_block_end)(); +extern int (*codegen_timing_jump_cycles)(); 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 (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc); void (*block_start)(); void (*block_end)(); + int (*jump_cycles)(); } 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; +extern codegen_timing_t codegen_timing_winchip2; +extern codegen_timing_t codegen_timing_cyrixiii; +extern codegen_timing_t codegen_timing_k6; +extern codegen_timing_t codegen_timing_p6; void codegen_timing_set(codegen_timing_t *timing); @@ -298,45 +385,6 @@ 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 >= BLOCK_MAX) - { - CPU_BLOCK_END(); - } -} - -static inline void addword(uint16_t val) -{ - *(uint16_t *)(void *)&codeblock[block_current].data[block_pos] = val; - block_pos += 2; - if (block_pos >= BLOCK_MAX) - { - 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 >= BLOCK_MAX) - { - 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 >= BLOCK_MAX) - { - CPU_BLOCK_END(); - } -} - /*Current physical page of block being recompiled. -1 if no recompilation taking place */ extern uint32_t recomp_page; @@ -355,3 +403,14 @@ extern int codegen_fpu_loaded_iq[8]; extern int codegen_reg_loaded[8]; extern int codegen_in_recompile; + +void codegen_generate_reset(); + +int codegen_get_instruction_uop(codeblock_t *block, uint32_t pc, int *first_instruction, int *TOP); +void codegen_set_loop_start(struct ir_data_t *ir, int first_instruction); + +#ifdef DEBUG_EXTRA +extern uint32_t instr_counts[256*256]; +#endif + +#endif diff --git a/src/codegen_accumulate.c b/src/codegen_accumulate.c new file mode 100644 index 0000000..968b7a5 --- /dev/null +++ b/src/codegen_accumulate.c @@ -0,0 +1,50 @@ +#include "ibm.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" + +static struct +{ + int count; + int dest_reg; +} acc_regs[] = +{ + [ACCREG_ins] = {0, IREG_ins}, + [ACCREG_cycles] = {0, IREG_cycles}, +}; + +void codegen_accumulate(int acc_reg, int delta) +{ + if (acc_reg == ACCREG_cycles) + { +// pclog("cycles %04x:%04x %i\n", CS, cpu_state.pc, delta); +// if (CS == 0x1000 && cpu_state.pc == 0x863) +// fatal("Here\n"); + } + acc_regs[acc_reg].count += delta; +} + +void codegen_accumulate_flush(ir_data_t *ir) +{ + int c; + + for (c = 0; c < ACCREG_COUNT; c++) + { + if (acc_regs[c].count) + { +// if (c == ACCREG_cycles) +// pclog("accumulate %i %i %i\n", c, acc_regs[c].dest_reg, acc_regs[c].count); + uop_ADD_IMM(ir, acc_regs[c].dest_reg, acc_regs[c].dest_reg, acc_regs[c].count); + } + + acc_regs[c].count = 0; + } +} + +void codegen_accumulate_reset() +{ + int c; + + for (c = 0; c < ACCREG_COUNT; c++) + acc_regs[c].count = 0; +} diff --git a/src/codegen_accumulate.h b/src/codegen_accumulate.h new file mode 100644 index 0000000..6c19499 --- /dev/null +++ b/src/codegen_accumulate.h @@ -0,0 +1,13 @@ +enum +{ + ACCREG_ins = 0, + ACCREG_cycles = 1, + + ACCREG_COUNT +}; + +struct ir_data_t; + +void codegen_accumulate(int acc_reg, int delta); +void codegen_accumulate_flush(struct ir_data_t *ir); +void codegen_accumulate_reset(); diff --git a/src/codegen_allocator.c b/src/codegen_allocator.c new file mode 100644 index 0000000..a5301d1 --- /dev/null +++ b/src/codegen_allocator.c @@ -0,0 +1,131 @@ +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" + +typedef struct mem_block_t +{ + uint32_t offset; /*Offset into mem_block_alloc*/ + uint32_t next; + uint16_t code_block; +} mem_block_t; + +static mem_block_t mem_blocks[MEM_BLOCK_NR]; +static uint32_t mem_block_free_list; +static uint8_t *mem_block_alloc = NULL; + +int codegen_allocator_usage = 0; + +void codegen_allocator_init() +{ + int c; + +#if defined WIN32 || defined _WIN32 || defined _WIN32 + mem_block_alloc = VirtualAlloc(NULL, MEM_BLOCK_NR * MEM_BLOCK_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); + /* TODO: check deployment target: older Intel-based versions of macOS don't play + nice with MAP_JIT. */ +#elif defined(__APPLE__) && defined(MAP_JIT) + mem_block_alloc = mmap(0, MEM_BLOCK_NR * MEM_BLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE|MAP_JIT, 0, 0); +#else + mem_block_alloc = mmap(0, MEM_BLOCK_NR * MEM_BLOCK_SIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0); +#endif + + for (c = 0; c < MEM_BLOCK_NR; c++) + { + mem_blocks[c].offset = c * MEM_BLOCK_SIZE; + mem_blocks[c].code_block = BLOCK_INVALID; + if (c < MEM_BLOCK_NR-1) + mem_blocks[c].next = c+2; + else + mem_blocks[c].next = 0; + } + mem_block_free_list = 1; +} + +mem_block_t *codegen_allocator_allocate(mem_block_t *parent, int code_block) +{ + mem_block_t *block; + uint32_t block_nr; + + while (!mem_block_free_list) + { + /*Pick a random memory block and free the owning code block*/ + block_nr = rand() & MEM_BLOCK_MASK; + block = &mem_blocks[block_nr]; + + if (block->code_block && block->code_block != code_block) + codegen_delete_block(&codeblock[block->code_block]); + } +// fatal("codegen_allocator_allocate: free list empty!\n"); + + /*Remove from free list*/ + block_nr = mem_block_free_list; + block = &mem_blocks[block_nr-1]; + mem_block_free_list = block->next; + + block->code_block = code_block; + if (parent) + { + /*Add to parent list*/ + block->next = parent->next; + parent->next = block_nr; + } + else + block->next = 0; + + codegen_allocator_usage++; +/* if (parent) + pclog("codegen_allocator_allocate with parent: %p %i %i %p\n", block, block_nr, codegen_allocator_usage, parent); + else + pclog("codegen_allocator_allocate: %p %i %i\n", block, block_nr, codegen_allocator_usage);*/ + return block; +} +void codegen_allocator_free(mem_block_t *block) +{ + int block_nr = (((uintptr_t)block - (uintptr_t)mem_blocks) / sizeof(mem_block_t)) + 1; + +// pclog("codegen_allocator_free: %p %i %i %i\n", block, block_nr, codegen_allocator_usage, block->next); + while (1) + { + int next_block_nr = block->next; +// pclog(" free next=%i\n", next_block_nr); + codegen_allocator_usage--; + + block->next = mem_block_free_list; + block->code_block = BLOCK_INVALID; + mem_block_free_list = block_nr; + block_nr = next_block_nr; + + if (block_nr) + block = &mem_blocks[block_nr - 1]; + else + break; + } +} + +uint8_t *codeblock_allocator_get_ptr(mem_block_t *block) +{ + return &mem_block_alloc[block->offset]; +} + +void codegen_allocator_clean_blocks(struct mem_block_t *block) +{ +#if defined __ARM_EABI__ || defined __aarch64__ + while (1) + { + __clear_cache(&mem_block_alloc[block->offset], &mem_block_alloc[block->offset + MEM_BLOCK_SIZE]); + if (block->next) + block = &mem_blocks[block->next - 1]; + else + break; + } +#endif +} diff --git a/src/codegen_allocator.h b/src/codegen_allocator.h new file mode 100644 index 0000000..1adb243 --- /dev/null +++ b/src/codegen_allocator.h @@ -0,0 +1,39 @@ +#ifndef _CODEGEN_ALLOCATOR_H_ +#define _CODEGEN_ALLOCATOR_H_ + +/*The allocator handles all allocation of executable memory. Since the two-pass + recompiler design makes applying hard limits to codeblock size difficult, the + allocator allows memory to be provided as and when required. + + The allocator provides a block size of a little under 1 kB (slightly lower to + limit cache aliasing). Each generated codeblock is allocated one block by default, + and will allocate additional block(s) once the existing memory is sorted. Blocks + are chained together by jump instructions. + + Due to the chaining, the total memory size is limited by the range of a jump + instruction. ARMv7 is restricted to +/- 32 MB, ARMv8 to +/- 128 MB, x86 to + +/- 2GB. As a result, total memory size is limited to 32 MB on ARMv7*/ +#ifdef __ARM_EABI__ +#define MEM_BLOCK_NR 32768 +#else +#define MEM_BLOCK_NR 131072 +#endif + +#define MEM_BLOCK_MASK (MEM_BLOCK_NR-1) +#define MEM_BLOCK_SIZE 0x3c0 + +void codegen_allocator_init(); +/*Allocate a mem_block_t, and the associated backing memory. + If parent is non-NULL, then the new block will be added to the list in + parent->next*/ +struct mem_block_t *codegen_allocator_allocate(struct mem_block_t *parent, int code_block); +/*Free a mem_block_t, and any subsequent blocks in the list at block->next*/ +void codegen_allocator_free(struct mem_block_t *block); +/*Get a pointer to the backing memory associated with block*/ +uint8_t *codeblock_allocator_get_ptr(struct mem_block_t *block); +/*Cache clean memory block list*/ +void codegen_allocator_clean_blocks(struct mem_block_t *block); + +extern int codegen_allocator_usage; + +#endif diff --git a/src/codegen_backend.h b/src/codegen_backend.h new file mode 100644 index 0000000..45668df --- /dev/null +++ b/src/codegen_backend.h @@ -0,0 +1,43 @@ +#ifndef _CODEGEN_BACKEND_H_ +#define _CODEGEN_BACKEND_H_ + +//#ifdef __amd64__ +//#include "codegen_x86-64.h" +#if defined __amd64__ +#include "codegen_backend_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 +#include "codegen_backend_x86.h" +#elif defined __ARM_EABI__ +#include "codegen_backend_arm.h" +#elif defined __aarch64__ +#include "codegen_backend_arm64.h" +#else +#error Dynamic recompiler not implemented on your platform +#endif + +void codegen_backend_init(); +void codegen_backend_prologue(codeblock_t *block); +void codegen_backend_epilogue(codeblock_t *block); + +struct ir_data_t; +struct uop_t; + +struct ir_data_t *codegen_get_ir_data(); + +typedef int (*uOpFn)(codeblock_t *codeblock, struct uop_t *uop); + +extern const uOpFn uop_handlers[]; + +/*Register will not be preserved across function calls*/ +#define HOST_REG_FLAG_VOLATILE (1 << 0) + +typedef struct host_reg_def_t +{ + int reg; + int flags; +} host_reg_def_t; + +extern host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS]; +extern host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS]; + +#endif diff --git a/src/codegen_backend_arm.c b/src/codegen_backend_arm.c new file mode 100644 index 0000000..aa9345c --- /dev/null +++ b/src/codegen_backend_arm.c @@ -0,0 +1,368 @@ +#ifdef __ARM_EABI__ + +#include +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" +#include "codegen_reg.h" +#include "x86.h" +#include "x87.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; +void *codegen_mem_load_quad; +void *codegen_mem_load_single; +void *codegen_mem_load_double; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; +void *codegen_mem_store_quad; +void *codegen_mem_store_single; +void *codegen_mem_store_double; + +void *codegen_fp_round; + +void *codegen_gpf_rout; +void *codegen_exit_rout; + +host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + {REG_R4, 0}, + {REG_R5, 0}, + {REG_R6, 0}, + {REG_R7, 0}, + {REG_R8, 0}, + {REG_R9, 0}, + {REG_R11, 0} +}; + +host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + {REG_D8, 0}, + {REG_D9, 0}, + {REG_D10, 0}, + {REG_D11, 0}, + {REG_D12, 0}, + {REG_D13, 0}, + {REG_D14, 0}, + {REG_D15, 0} +}; + +static void build_load_routine(codeblock_t *block, int size, int is_float) +{ + uint32_t *branch_offset; + uint32_t *misaligned_offset; + + /*In - R0 = address + Out - R0 = data, R1 = abrt*/ + /*MOV R1, R0, LSR #12 + MOV R2, #readlookup2 + LDR R1, [R2, R1, LSL #2] + CMP R1, #-1 + BNE + + LDRB R0, [R1, R0] + MOV R1, #0 + MOV PC, LR + * STR LR, [SP, -4]! + BL readmembl + LDRB R1, cpu_state.abrt + LDR PC, [SP], #4 + */ + codegen_alloc(block, 80); + host_arm_MOV_REG_LSR(block, REG_R1, REG_R0, 12); + host_arm_MOV_IMM(block, REG_R2, (uint32_t)readlookup2); + host_arm_LDR_REG_LSL(block, REG_R1, REG_R2, REG_R1, 2); + if (size != 1) + { + host_arm_TST_IMM(block, REG_R0, size-1); + misaligned_offset = host_arm_BNE_(block); + } + host_arm_CMP_IMM(block, REG_R1, -1); + branch_offset = host_arm_BEQ_(block); + if (size == 1 && !is_float) + host_arm_LDRB_REG(block, REG_R0, REG_R1, REG_R0); + else if (size == 2 && !is_float) + host_arm_LDRH_REG(block, REG_R0, REG_R1, REG_R0); + else if (size == 4 && !is_float) + host_arm_LDR_REG(block, REG_R0, REG_R1, REG_R0); + else if (size == 4 && is_float) + { + host_arm_ADD_REG(block, REG_R0, REG_R0, REG_R1); + host_arm_VLDR_S(block, REG_D_TEMP, REG_R0, 0); + } + else if (size == 8) + { + host_arm_ADD_REG(block, REG_R0, REG_R0, REG_R1); + host_arm_VLDR_D(block, REG_D_TEMP, REG_R0, 0); + } + host_arm_MOV_IMM(block, REG_R1, 0); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + *branch_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; + if (size != 1) + *misaligned_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 8) & 0x3fffffc) >> 2; + host_arm_STR_IMM_WB(block, REG_LR, REG_HOST_SP, -4); + if (size == 1) + host_arm_BL(block, (uintptr_t)readmembl); + else if (size == 2) + host_arm_BL(block, (uintptr_t)readmemwl); + else if (size == 4) + host_arm_BL(block, (uintptr_t)readmemll); + else if (size == 8) + host_arm_BL(block, (uintptr_t)readmemql); + else + fatal("build_load_routine - unknown size %i\n", size); + if (size == 4 && is_float) + host_arm_VMOV_S_32(block, REG_D_TEMP, REG_R0); + else if (size == 8) + host_arm_VMOV_D_64(block, REG_D_TEMP, REG_R0, REG_R1); + host_arm_LDRB_ABS(block, REG_R1, &cpu_state.abrt); + host_arm_LDR_IMM_POST(block, REG_PC, REG_HOST_SP, 4); +} + +static void build_store_routine(codeblock_t *block, int size, int is_float) +{ + uint32_t *branch_offset; + uint32_t *misaligned_offset; + + /*In - R0 = address + Out - R0 = data, R1 = abrt*/ + /*MOV R1, R0, LSR #12 + MOV R2, #readlookup2 + LDR R1, [R2, R1, LSL #2] + CMP R1, #-1 + BNE + + LDRB R0, [R1, R0] + MOV R1, #0 + MOV PC, LR + * STR LR, [SP, -4]! + BL readmembl + LDRB R1, cpu_state.abrt + LDR PC, [SP], #4 + */ + codegen_alloc(block, 80); + host_arm_MOV_REG_LSR(block, REG_R2, REG_R0, 12); + host_arm_MOV_IMM(block, REG_R3, (uint32_t)writelookup2); + host_arm_LDR_REG_LSL(block, REG_R2, REG_R3, REG_R2, 2); + if (size != 1) + { + host_arm_TST_IMM(block, REG_R0, size-1); + misaligned_offset = host_arm_BNE_(block); + } + host_arm_CMP_IMM(block, REG_R2, -1); + branch_offset = host_arm_BEQ_(block); + if (size == 1 && !is_float) + host_arm_STRB_REG(block, REG_R1, REG_R2, REG_R0); + else if (size == 2 && !is_float) + host_arm_STRH_REG(block, REG_R1, REG_R2, REG_R0); + else if (size == 4 && !is_float) + host_arm_STR_REG(block, REG_R1, REG_R2, REG_R0); + else if (size == 4 && is_float) + { + host_arm_ADD_REG(block, REG_R0, REG_R0, REG_R2); + host_arm_VSTR_S(block, REG_D_TEMP, REG_R0, 0); + } + else if (size == 8) + { + host_arm_ADD_REG(block, REG_R0, REG_R0, REG_R2); + host_arm_VSTR_D(block, REG_D_TEMP, REG_R0, 0); + } + host_arm_MOV_IMM(block, REG_R1, 0); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + *branch_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; + if (size != 1) + *misaligned_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 8) & 0x3fffffc) >> 2; + host_arm_STR_IMM_WB(block, REG_LR, REG_HOST_SP, -4); + if (size == 4 && is_float) + host_arm_VMOV_32_S(block, REG_R1, REG_D_TEMP); + else if (size == 8) + host_arm_VMOV_64_D(block, REG_R2, REG_R3, REG_D_TEMP); + if (size == 1) + host_arm_BL(block, (uintptr_t)writemembl); + else if (size == 2) + host_arm_BL(block, (uintptr_t)writememwl); + else if (size == 4) + host_arm_BL(block, (uintptr_t)writememll); + else if (size == 8) + host_arm_BL_r1(block, (uintptr_t)writememql); + else + fatal("build_store_routine - unknown size %i\n", size); + host_arm_LDRB_ABS(block, REG_R1, &cpu_state.abrt); + host_arm_LDR_IMM_POST(block, REG_PC, REG_HOST_SP, 4); +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &block_write_data[block_pos]; + build_load_routine(block, 1, 0); + codegen_mem_load_word = &block_write_data[block_pos]; + build_load_routine(block, 2, 0); + codegen_mem_load_long = &block_write_data[block_pos]; + build_load_routine(block, 4, 0); + codegen_mem_load_quad = &block_write_data[block_pos]; + build_load_routine(block, 8, 0); + codegen_mem_load_single = &block_write_data[block_pos]; + build_load_routine(block, 4, 1); + codegen_mem_load_double = &block_write_data[block_pos]; + build_load_routine(block, 8, 1); + + codegen_mem_store_byte = &block_write_data[block_pos]; + build_store_routine(block, 1, 0); + codegen_mem_store_word = &block_write_data[block_pos]; + build_store_routine(block, 2, 0); + codegen_mem_store_long = &block_write_data[block_pos]; + build_store_routine(block, 4, 0); + codegen_mem_store_quad = &block_write_data[block_pos]; + build_store_routine(block, 8, 0); + codegen_mem_store_single = &block_write_data[block_pos]; + build_store_routine(block, 4, 1); + codegen_mem_store_double = &block_write_data[block_pos]; + build_store_routine(block, 8, 1); +} + +/*VFP has a specific round-to-zero instruction, and the default rounding mode + is nearest. For round up/down, temporarily change the rounding mode in FPCSR*/ +#define FPCSR_ROUNDING_MASK (3 << 22) +#define FPCSR_ROUNDING_UP (1 << 22) +#define FPCSR_ROUNDING_DOWN (2 << 22) + +static void build_fp_round_routine(codeblock_t *block) +{ + uint32_t *jump_table; + + codegen_alloc(block, 80); + + host_arm_MOV_REG(block, REG_TEMP2, REG_LR); + host_arm_MOV_REG(block, REG_LR, REG_TEMP2); + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.new_fp_control - (uintptr_t)&cpu_state); + host_arm_LDR_REG(block, REG_PC, REG_PC, REG_TEMP); + host_arm_NOP(block); + + jump_table = (uint32_t *)&block_write_data[block_pos]; + host_arm_NOP(block); + host_arm_NOP(block); + host_arm_NOP(block); + host_arm_NOP(block); + + jump_table[X87_ROUNDING_NEAREST] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //tie even + host_arm_VCVTR_IS_D(block, REG_D_TEMP, REG_D_TEMP); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + jump_table[X87_ROUNDING_UP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //pos inf + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.old_fp_control - (uintptr_t)&cpu_state); + host_arm_BIC_IMM(block, REG_TEMP2, REG_TEMP, FPCSR_ROUNDING_MASK); + host_arm_ORR_IMM(block, REG_TEMP2, REG_TEMP2, FPCSR_ROUNDING_UP); + host_arm_VMSR_FPSCR(block, REG_TEMP2); + host_arm_VCVTR_IS_D(block, REG_D_TEMP, REG_D_TEMP); + host_arm_VMSR_FPSCR(block, REG_TEMP); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + jump_table[X87_ROUNDING_DOWN] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //neg inf + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.old_fp_control - (uintptr_t)&cpu_state); + host_arm_BIC_IMM(block, REG_TEMP2, REG_TEMP, FPCSR_ROUNDING_MASK); + host_arm_ORR_IMM(block, REG_TEMP2, REG_TEMP, FPCSR_ROUNDING_DOWN); + host_arm_VMSR_FPSCR(block, REG_TEMP2); + host_arm_VCVTR_IS_D(block, REG_D_TEMP, REG_D_TEMP); + host_arm_VMSR_FPSCR(block, REG_TEMP); + host_arm_MOV_REG(block, REG_PC, REG_LR); + + jump_table[X87_ROUNDING_CHOP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //zero + host_arm_VCVT_IS_D(block, REG_D_TEMP, REG_D_TEMP); + host_arm_MOV_REG(block, REG_PC, REG_LR); +} + +void codegen_backend_init() +{ + codeblock_t *block; + int c; + + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); + 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 *)); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].pc = BLOCK_PC_INVALID; + +// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); + + block_current = 0; + block_pos = 0; + block = &codeblock[block_current]; + block->head_mem_block = codegen_allocator_allocate(NULL, block_current); + block->data = codeblock_allocator_get_ptr(block->head_mem_block); + block_write_data = block->data; + build_loadstore_routines(&codeblock[block_current]); +printf("block_pos=%i\n", block_pos); + + codegen_fp_round = &block_write_data[block_pos]; + build_fp_round_routine(&codeblock[block_current]); + + codegen_alloc(block, 80); + codegen_gpf_rout = &block_write_data[block_pos]; + host_arm_MOV_IMM(block, REG_R0, 0); + host_arm_MOV_IMM(block, REG_R1, 0); + host_arm_call(block, x86gpf); + + codegen_exit_rout = &block_write_data[block_pos]; + host_arm_ADD_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); + host_arm_LDMIA_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_PC); + + block_write_data = NULL; +//fatal("block_pos=%i\n", block_pos); + asm("vmrs %0, fpscr\n" + : "=r" (cpu_state.old_fp_control) + ); + if ((cpu_state.old_fp_control >> 22) & 3) + fatal("VFP not in nearest rounding mode\n"); +} + +void codegen_set_rounding_mode(int mode) +{ + if (mode < 0 || mode > 3) + fatal("codegen_set_rounding_mode - invalid mode\n"); + cpu_state.new_fp_control = mode << 2; +} + +/*R10 - cpu_state*/ +void codegen_backend_prologue(codeblock_t *block) +{ + block_pos = BLOCK_START; + + /*Entry code*/ + + host_arm_STMDB_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_LR); + host_arm_SUB_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); + host_arm_MOV_IMM(block, REG_CPUSTATE, (uint32_t)&cpu_state); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm_SUB_IMM(block, REG_TEMP, REG_TEMP, block->TOP); + host_arm_STR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + } +} + +void codegen_backend_epilogue(codeblock_t *block) +{ + host_arm_ADD_IMM(block, REG_HOST_SP, REG_HOST_SP, 0x40); + host_arm_LDMIA_WB(block, REG_HOST_SP, REG_MASK_LOCAL | REG_MASK_PC); + + codegen_allocator_clean_blocks(block->head_mem_block); +} + +#endif diff --git a/src/codegen_backend_arm.h b/src/codegen_backend_arm.h new file mode 100644 index 0000000..bfd5206 --- /dev/null +++ b/src/codegen_backend_arm.h @@ -0,0 +1,24 @@ +#include "codegen_backend_arm_defs.h" + +#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_MAX 0x3c0 + +void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); +void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm); +void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); +void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); + +void host_arm_call(codeblock_t *block, void *dst_addr); +void host_arm_nop(codeblock_t *block); + +void codegen_alloc(codeblock_t *block, int size); \ No newline at end of file diff --git a/src/codegen_backend_arm64.c b/src/codegen_backend_arm64.c new file mode 100644 index 0000000..1885e61 --- /dev/null +++ b/src/codegen_backend_arm64.c @@ -0,0 +1,382 @@ +#ifdef __aarch64__ + +#include +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" +#include "codegen_reg.h" +#include "x86.h" +#include "x87.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; +void *codegen_mem_load_quad; +void *codegen_mem_load_single; +void *codegen_mem_load_double; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; +void *codegen_mem_store_quad; +void *codegen_mem_store_single; +void *codegen_mem_store_double; + +void *codegen_fp_round; +void *codegen_fp_round_quad; + +void *codegen_gpf_rout; +void *codegen_exit_rout; + +host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + {REG_X19, 0}, + {REG_X20, 0}, + {REG_X21, 0}, + {REG_X22, 0}, + {REG_X23, 0}, + {REG_X24, 0}, + {REG_X25, 0}, + {REG_X26, 0}, + {REG_X27, 0}, + {REG_X28, 0} +}; + +host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + {REG_V8, 0}, + {REG_V9, 0}, + {REG_V10, 0}, + {REG_V11, 0}, + {REG_V12, 0}, + {REG_V13, 0}, + {REG_V14, 0}, + {REG_V15, 0} +}; + +static void build_load_routine(codeblock_t *block, int size, int is_float) +{ + uint32_t *branch_offset; + uint32_t *misaligned_offset; + int offset; + + /*In - W0 = address + Out - W0 = data, W1 = abrt*/ + /*MOV W1, W0, LSR #12 + MOV X2, #readlookup2 + LDR X1, [X2, X1, LSL #3] + CMP X1, #-1 + BEQ + + LDRB W0, [X1, X0] + MOV W1, #0 + RET + * STP X29, X30, [SP, #-16] + BL readmembl + LDRB R1, cpu_state.abrt + LDP X29, X30, [SP, #-16] + RET + */ + codegen_alloc(block, 80); + host_arm64_MOV_REG_LSR(block, REG_W1, REG_W0, 12); + host_arm64_MOVX_IMM(block, REG_X2, (uint64_t)readlookup2); + host_arm64_LDRX_REG_LSL3(block, REG_X1, REG_X2, REG_X1); + if (size != 1) + { + host_arm64_TST_IMM(block, REG_W0, size-1); + misaligned_offset = host_arm64_BNE_(block); + } + host_arm64_CMPX_IMM(block, REG_X1, -1); + branch_offset = host_arm64_BEQ_(block); + if (size == 1 && !is_float) + host_arm64_LDRB_REG(block, REG_W0, REG_W1, REG_W0); + else if (size == 2 && !is_float) + host_arm64_LDRH_REG(block, REG_W0, REG_W1, REG_W0); + else if (size == 4 && !is_float) + host_arm64_LDR_REG(block, REG_W0, REG_W1, REG_W0); + else if (size == 4 && is_float) + host_arm64_LDR_REG_F32(block, REG_V_TEMP, REG_W1, REG_W0); + else if (size == 8) + host_arm64_LDR_REG_F64(block, REG_V_TEMP, REG_W1, REG_W0); + host_arm64_MOVZ_IMM(block, REG_W1, 0); + host_arm64_RET(block, REG_X30); + + host_arm64_branch_set_offset(branch_offset, &block_write_data[block_pos]); + if (size != 1) + host_arm64_branch_set_offset(misaligned_offset, &block_write_data[block_pos]); + host_arm64_STP_PREIDX_X(block, REG_X29, REG_X30, REG_XSP, -16); + if (size == 1) + host_arm64_call(block, (void *)readmembl); + else if (size == 2) + host_arm64_call(block, (void *)readmemwl); + else if (size == 4) + host_arm64_call(block, (void *)readmemll); + else if (size == 8) + host_arm64_call(block, (void *)readmemql); + else + fatal("build_load_routine - unknown size %i\n", size); + codegen_direct_read_8(block, REG_W1, &cpu_state.abrt); + if (size == 4 && is_float) + host_arm64_FMOV_S_W(block, REG_V_TEMP, REG_W0); + else if (size == 8) + host_arm64_FMOV_D_Q(block, REG_V_TEMP, REG_X0); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_XSP, 16); + host_arm64_RET(block, REG_X30); +} + +static void build_store_routine(codeblock_t *block, int size, int is_float) +{ + uint32_t *branch_offset; + uint32_t *misaligned_offset; + int offset; + + /*In - R0 = address, R1 = data + Out - R1 = abrt*/ + /*MOV W2, W0, LSR #12 + MOV X3, #writelookup2 + LDR X2, [X3, X2, LSL #3] + CMP X2, #-1 + BEQ + + STRB W1, [X2, X0] + MOV W1, #0 + RET + * STP X29, X30, [SP, #-16] + BL writemembl + LDRB R1, cpu_state.abrt + LDP X29, X30, [SP, #-16] + RET + */ + codegen_alloc(block, 80); + host_arm64_MOV_REG_LSR(block, REG_W2, REG_W0, 12); + host_arm64_MOVX_IMM(block, REG_X3, (uint64_t)writelookup2); + host_arm64_LDRX_REG_LSL3(block, REG_X2, REG_X3, REG_X2); + if (size != 1) + { + host_arm64_TST_IMM(block, REG_W0, size-1); + misaligned_offset = host_arm64_BNE_(block); + } + host_arm64_CMPX_IMM(block, REG_X2, -1); + branch_offset = host_arm64_BEQ_(block); + if (size == 1 && !is_float) + host_arm64_STRB_REG(block, REG_X1, REG_X2, REG_X0); + else if (size == 2 && !is_float) + host_arm64_STRH_REG(block, REG_X1, REG_X2, REG_X0); + else if (size == 4 && !is_float) + host_arm64_STR_REG(block, REG_X1, REG_X2, REG_X0); + else if (size == 4 && is_float) + host_arm64_STR_REG_F32(block, REG_V_TEMP, REG_X2, REG_X0); + else if (size == 8) + host_arm64_STR_REG_F64(block, REG_V_TEMP, REG_X2, REG_X0); + host_arm64_MOVZ_IMM(block, REG_X1, 0); + host_arm64_RET(block, REG_X30); + + host_arm64_branch_set_offset(branch_offset, &block_write_data[block_pos]); + if (size != 1) + host_arm64_branch_set_offset(misaligned_offset, &block_write_data[block_pos]); + host_arm64_STP_PREIDX_X(block, REG_X29, REG_X30, REG_XSP, -16); + if (size == 4 && is_float) + host_arm64_FMOV_W_S(block, REG_W1, REG_V_TEMP); + else if (size == 8) + host_arm64_FMOV_Q_D(block, REG_X1, REG_V_TEMP); + if (size == 1) + host_arm64_call(block, (void *)writemembl); + else if (size == 2) + host_arm64_call(block, (void *)writememwl); + else if (size == 4) + host_arm64_call(block, (void *)writememll); + else if (size == 8) + host_arm64_call(block, (void *)writememql); + else + fatal("build_store_routine - unknown size %i\n", size); + codegen_direct_read_8(block, REG_W1, &cpu_state.abrt); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_XSP, 16); + host_arm64_RET(block, REG_X30); +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &block_write_data[block_pos]; + build_load_routine(block, 1, 0); + codegen_mem_load_word = &block_write_data[block_pos]; + build_load_routine(block, 2, 0); + codegen_mem_load_long = &block_write_data[block_pos]; + build_load_routine(block, 4, 0); + codegen_mem_load_quad = &block_write_data[block_pos]; + build_load_routine(block, 8, 0); + codegen_mem_load_single = &block_write_data[block_pos]; + build_load_routine(block, 4, 1); + codegen_mem_load_double = &block_write_data[block_pos]; + build_load_routine(block, 8, 1); + + codegen_mem_store_byte = &block_write_data[block_pos]; + build_store_routine(block, 1, 0); + codegen_mem_store_word = &block_write_data[block_pos]; + build_store_routine(block, 2, 0); + codegen_mem_store_long = &block_write_data[block_pos]; + build_store_routine(block, 4, 0); + codegen_mem_store_quad = &block_write_data[block_pos]; + build_store_routine(block, 8, 0); + codegen_mem_store_single = &block_write_data[block_pos]; + build_store_routine(block, 4, 1); + codegen_mem_store_double = &block_write_data[block_pos]; + build_store_routine(block, 8, 1); +} + +static void build_fp_round_routine(codeblock_t *block, int is_quad) +{ + uint64_t *jump_table; + + codegen_alloc(block, 80); + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.new_fp_control - (uintptr_t)&cpu_state); + host_arm64_ADR(block, REG_TEMP2, 12); + host_arm64_LDR_REG_X(block, REG_TEMP2, REG_TEMP2, REG_TEMP); + host_arm64_BR(block, REG_TEMP2); + + jump_table = (uint64_t *)&block_write_data[block_pos]; + block_pos += 4*8; + + jump_table[X87_ROUNDING_NEAREST] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //tie even + if (is_quad) + host_arm64_FCVTNS_X_D(block, REG_TEMP, REG_V_TEMP); + else + host_arm64_FCVTNS_W_D(block, REG_TEMP, REG_V_TEMP); + host_arm64_RET(block, REG_X30); + + jump_table[X87_ROUNDING_UP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //pos inf + if (is_quad) + host_arm64_FCVTPS_X_D(block, REG_TEMP, REG_V_TEMP); + else + host_arm64_FCVTPS_W_D(block, REG_TEMP, REG_V_TEMP); + host_arm64_RET(block, REG_X30); + + jump_table[X87_ROUNDING_DOWN] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //neg inf + if (is_quad) + host_arm64_FCVTMS_X_D(block, REG_TEMP, REG_V_TEMP); + else + host_arm64_FCVTMS_W_D(block, REG_TEMP, REG_V_TEMP); + host_arm64_RET(block, REG_X30); + + jump_table[X87_ROUNDING_CHOP] = (uint64_t)(uintptr_t)&block_write_data[block_pos]; //zero + if (is_quad) + host_arm64_FCVTZS_X_D(block, REG_TEMP, REG_V_TEMP); + else + host_arm64_FCVTZS_W_D(block, REG_TEMP, REG_V_TEMP); + host_arm64_RET(block, REG_X30); +} + +void codegen_backend_init() +{ + codeblock_t *block; + int c; +#if defined(__linux__) || defined(__APPLE__) + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); + 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 *)); + + for (c = 0; c < BLOCK_SIZE; c++) + { + codeblock[c].pc = BLOCK_PC_INVALID; + } + +// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); + + block_current = 0; + block_pos = 0; + block = &codeblock[block_current]; + block->head_mem_block = codegen_allocator_allocate(NULL, block_current); + block->data = codeblock_allocator_get_ptr(block->head_mem_block); + block_write_data = block->data; + build_loadstore_routines(block); + + codegen_fp_round = &block_write_data[block_pos]; + build_fp_round_routine(block, 0); + codegen_fp_round_quad = &block_write_data[block_pos]; + build_fp_round_routine(block, 1); + + codegen_alloc(block, 80); + codegen_gpf_rout = &block_write_data[block_pos]; + host_arm64_mov_imm(block, REG_ARG0, 0); + host_arm64_mov_imm(block, REG_ARG1, 0); + host_arm64_call(block, (void *)x86gpf); + + codegen_exit_rout = &block_write_data[block_pos]; + host_arm64_LDP_POSTIDX_X(block, REG_X19, REG_X20, REG_XSP, 64); + host_arm64_LDP_POSTIDX_X(block, REG_X21, REG_X22, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X23, REG_X24, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X25, REG_X26, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X27, REG_X28, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_XSP, 16); + host_arm64_RET(block, REG_X30); + + block_write_data = NULL; + + codegen_allocator_clean_blocks(block->head_mem_block); + + asm("mrs %0, fpcr\n" + : "=r" (cpu_state.old_fp_control) + ); +} + +void codegen_set_rounding_mode(int mode) +{ + if (mode < 0 || mode > 3) + fatal("codegen_set_rounding_mode - invalid mode\n"); + cpu_state.new_fp_control = mode << 3; +} + +/*R10 - cpu_state*/ +void codegen_backend_prologue(codeblock_t *block) +{ + block_pos = BLOCK_START; + + /*Entry code*/ + + host_arm64_STP_PREIDX_X(block, REG_X29, REG_X30, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X27, REG_X28, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X25, REG_X26, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X23, REG_X24, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X21, REG_X22, REG_XSP, -16); + host_arm64_STP_PREIDX_X(block, REG_X19, REG_X20, REG_XSP, -64); + + host_arm64_MOVX_IMM(block, REG_CPUSTATE, (uint64_t)&cpu_state); + + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm64_SUB_IMM(block, REG_TEMP, REG_TEMP, block->TOP); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + } +} + +void codegen_backend_epilogue(codeblock_t *block) +{ + host_arm64_LDP_POSTIDX_X(block, REG_X19, REG_X20, REG_XSP, 64); + host_arm64_LDP_POSTIDX_X(block, REG_X21, REG_X22, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X23, REG_X24, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X25, REG_X26, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X27, REG_X28, REG_XSP, 16); + host_arm64_LDP_POSTIDX_X(block, REG_X29, REG_X30, REG_XSP, 16); + host_arm64_RET(block, REG_X30); + + codegen_allocator_clean_blocks(block->head_mem_block); +} + +#endif diff --git a/src/codegen_backend_arm64.h b/src/codegen_backend_arm64.h new file mode 100644 index 0000000..3263aa1 --- /dev/null +++ b/src/codegen_backend_arm64.h @@ -0,0 +1,31 @@ +#include "codegen_backend_arm64_defs.h" + +#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_MAX 0x3c0 + + +void host_arm64_BLR(codeblock_t *block, int addr_reg); +void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest); +void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data); +void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data); +void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); +void host_arm64_LDR_LITERAL_W(codeblock_t *block, int dest_reg, int literal_offset); +void host_arm64_LDR_LITERAL_X(codeblock_t *block, int dest_reg, int literal_offset); +void host_arm64_NOP(codeblock_t *block); +void host_arm64_RET(codeblock_t *block, int reg); +void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); +void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); + +void host_arm64_call(codeblock_t *block, void *dst_addr); +void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data); + +uint32_t host_arm64_find_imm(uint32_t data); \ No newline at end of file diff --git a/src/codegen_backend_arm64_defs.h b/src/codegen_backend_arm64_defs.h new file mode 100644 index 0000000..2df1e9f --- /dev/null +++ b/src/codegen_backend_arm64_defs.h @@ -0,0 +1,135 @@ +#define REG_W0 0 +#define REG_W1 1 +#define REG_W2 2 +#define REG_W3 3 +#define REG_W4 4 +#define REG_W5 5 +#define REG_W6 6 +#define REG_W7 7 +#define REG_W8 8 +#define REG_W9 9 +#define REG_W10 10 +#define REG_W11 11 +#define REG_W12 12 +#define REG_W13 13 +#define REG_W14 14 +#define REG_W15 15 +#define REG_W16 16 +#define REG_W17 17 +#define REG_W18 18 +#define REG_W19 19 +#define REG_W20 20 +#define REG_W21 21 +#define REG_W22 22 +#define REG_W23 23 +#define REG_W24 24 +#define REG_W25 25 +#define REG_W26 26 +#define REG_W27 27 +#define REG_W28 28 +#define REG_W29 29 +#define REG_W30 30 +#define REG_WZR 31 + +#define REG_X0 0 +#define REG_X1 1 +#define REG_X2 2 +#define REG_X3 3 +#define REG_X4 4 +#define REG_X5 5 +#define REG_X6 6 +#define REG_X7 7 +#define REG_X8 8 +#define REG_X9 9 +#define REG_X10 10 +#define REG_X11 11 +#define REG_X12 12 +#define REG_X13 13 +#define REG_X14 14 +#define REG_X15 15 +#define REG_X16 16 +#define REG_X17 17 +#define REG_X18 18 +#define REG_X19 19 +#define REG_X20 20 +#define REG_X21 21 +#define REG_X22 22 +#define REG_X23 23 +#define REG_X24 24 +#define REG_X25 25 +#define REG_X26 26 +#define REG_X27 27 +#define REG_X28 28 +#define REG_X29 29 +#define REG_X30 30 +#define REG_XZR 31 + +#define REG_V0 0 +#define REG_V1 1 +#define REG_V2 2 +#define REG_V3 3 +#define REG_V4 4 +#define REG_V5 5 +#define REG_V6 6 +#define REG_V7 7 +#define REG_V8 8 +#define REG_V9 9 +#define REG_V10 10 +#define REG_V11 11 +#define REG_V12 12 +#define REG_V13 13 +#define REG_V14 14 +#define REG_V15 15 +#define REG_V16 16 +#define REG_V17 17 +#define REG_V18 18 +#define REG_V19 19 +#define REG_V20 20 +#define REG_V21 21 +#define REG_V22 22 +#define REG_V23 23 +#define REG_V24 24 +#define REG_V25 25 +#define REG_V26 26 +#define REG_V27 27 +#define REG_V28 28 +#define REG_V29 29 +#define REG_V30 30 +#define REG_V31 31 + +#define REG_XSP 31 + +#define REG_ARG0 REG_X0 +#define REG_ARG1 REG_X1 +#define REG_ARG2 REG_X2 +#define REG_ARG3 REG_X3 + +#define REG_CPUSTATE REG_X29 + +#define REG_TEMP REG_X7 +#define REG_TEMP2 REG_X6 + +#define REG_V_TEMP REG_V0 + +#define CODEGEN_HOST_REGS 10 +#define CODEGEN_HOST_FP_REGS 8 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; +extern void *codegen_mem_load_quad; +extern void *codegen_mem_load_single; +extern void *codegen_mem_load_double; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; +extern void *codegen_mem_store_quad; +extern void *codegen_mem_store_single; +extern void *codegen_mem_store_double; + +extern void *codegen_fp_round; +extern void *codegen_fp_round_quad; + +extern void *codegen_gpf_rout; +extern void *codegen_exit_rout; \ No newline at end of file diff --git a/src/codegen_backend_arm64_imm.c b/src/codegen_backend_arm64_imm.c new file mode 100644 index 0000000..0362b71 --- /dev/null +++ b/src/codegen_backend_arm64_imm.c @@ -0,0 +1,1330 @@ +#include +#include + +/*ARM64 logical instructions have an 'interesting' immediate encoding. + All valid values are in the table below, which we perform a binary + search over*/ +#define IMM_NR 1302 +static uint32_t imm_table[][2] = +{ + {0x800, 0x00000001}, + {0xfc0, 0x00000002}, + {0x801, 0x00000003}, + {0xf80, 0x00000004}, + {0xfc1, 0x00000006}, + {0x802, 0x00000007}, + {0xf40, 0x00000008}, + {0xf81, 0x0000000c}, + {0xfc2, 0x0000000e}, + {0x803, 0x0000000f}, + {0xf00, 0x00000010}, + {0xf41, 0x00000018}, + {0xf82, 0x0000001c}, + {0xfc3, 0x0000001e}, + {0x804, 0x0000001f}, + {0xec0, 0x00000020}, + {0xf01, 0x00000030}, + {0xf42, 0x00000038}, + {0xf83, 0x0000003c}, + {0xfc4, 0x0000003e}, + {0x805, 0x0000003f}, + {0xe80, 0x00000040}, + {0xec1, 0x00000060}, + {0xf02, 0x00000070}, + {0xf43, 0x00000078}, + {0xf84, 0x0000007c}, + {0xfc5, 0x0000007e}, + {0x806, 0x0000007f}, + {0xe40, 0x00000080}, + {0xe81, 0x000000c0}, + {0xec2, 0x000000e0}, + {0xf03, 0x000000f0}, + {0xf44, 0x000000f8}, + {0xf85, 0x000000fc}, + {0xfc6, 0x000000fe}, + {0x807, 0x000000ff}, + {0xe00, 0x00000100}, + {0xe41, 0x00000180}, + {0xe82, 0x000001c0}, + {0xec3, 0x000001e0}, + {0xf04, 0x000001f0}, + {0xf45, 0x000001f8}, + {0xf86, 0x000001fc}, + {0xfc7, 0x000001fe}, + {0x808, 0x000001ff}, + {0xdc0, 0x00000200}, + {0xe01, 0x00000300}, + {0xe42, 0x00000380}, + {0xe83, 0x000003c0}, + {0xec4, 0x000003e0}, + {0xf05, 0x000003f0}, + {0xf46, 0x000003f8}, + {0xf87, 0x000003fc}, + {0xfc8, 0x000003fe}, + {0x809, 0x000003ff}, + {0xd80, 0x00000400}, + {0xdc1, 0x00000600}, + {0xe02, 0x00000700}, + {0xe43, 0x00000780}, + {0xe84, 0x000007c0}, + {0xec5, 0x000007e0}, + {0xf06, 0x000007f0}, + {0xf47, 0x000007f8}, + {0xf88, 0x000007fc}, + {0xfc9, 0x000007fe}, + {0x80a, 0x000007ff}, + {0xd40, 0x00000800}, + {0xd81, 0x00000c00}, + {0xdc2, 0x00000e00}, + {0xe03, 0x00000f00}, + {0xe44, 0x00000f80}, + {0xe85, 0x00000fc0}, + {0xec6, 0x00000fe0}, + {0xf07, 0x00000ff0}, + {0xf48, 0x00000ff8}, + {0xf89, 0x00000ffc}, + {0xfca, 0x00000ffe}, + {0x80b, 0x00000fff}, + {0xd00, 0x00001000}, + {0xd41, 0x00001800}, + {0xd82, 0x00001c00}, + {0xdc3, 0x00001e00}, + {0xe04, 0x00001f00}, + {0xe45, 0x00001f80}, + {0xe86, 0x00001fc0}, + {0xec7, 0x00001fe0}, + {0xf08, 0x00001ff0}, + {0xf49, 0x00001ff8}, + {0xf8a, 0x00001ffc}, + {0xfcb, 0x00001ffe}, + {0x80c, 0x00001fff}, + {0xcc0, 0x00002000}, + {0xd01, 0x00003000}, + {0xd42, 0x00003800}, + {0xd83, 0x00003c00}, + {0xdc4, 0x00003e00}, + {0xe05, 0x00003f00}, + {0xe46, 0x00003f80}, + {0xe87, 0x00003fc0}, + {0xec8, 0x00003fe0}, + {0xf09, 0x00003ff0}, + {0xf4a, 0x00003ff8}, + {0xf8b, 0x00003ffc}, + {0xfcc, 0x00003ffe}, + {0x80d, 0x00003fff}, + {0xc80, 0x00004000}, + {0xcc1, 0x00006000}, + {0xd02, 0x00007000}, + {0xd43, 0x00007800}, + {0xd84, 0x00007c00}, + {0xdc5, 0x00007e00}, + {0xe06, 0x00007f00}, + {0xe47, 0x00007f80}, + {0xe88, 0x00007fc0}, + {0xec9, 0x00007fe0}, + {0xf0a, 0x00007ff0}, + {0xf4b, 0x00007ff8}, + {0xf8c, 0x00007ffc}, + {0xfcd, 0x00007ffe}, + {0x80e, 0x00007fff}, + {0xc40, 0x00008000}, + {0xc81, 0x0000c000}, + {0xcc2, 0x0000e000}, + {0xd03, 0x0000f000}, + {0xd44, 0x0000f800}, + {0xd85, 0x0000fc00}, + {0xdc6, 0x0000fe00}, + {0xe07, 0x0000ff00}, + {0xe48, 0x0000ff80}, + {0xe89, 0x0000ffc0}, + {0xeca, 0x0000ffe0}, + {0xf0b, 0x0000fff0}, + {0xf4c, 0x0000fff8}, + {0xf8d, 0x0000fffc}, + {0xfce, 0x0000fffe}, + {0x80f, 0x0000ffff}, + {0xc00, 0x00010000}, + {0xc20, 0x00010001}, + {0xc41, 0x00018000}, + {0xc82, 0x0001c000}, + {0xcc3, 0x0001e000}, + {0xd04, 0x0001f000}, + {0xd45, 0x0001f800}, + {0xd86, 0x0001fc00}, + {0xdc7, 0x0001fe00}, + {0xe08, 0x0001ff00}, + {0xe49, 0x0001ff80}, + {0xe8a, 0x0001ffc0}, + {0xecb, 0x0001ffe0}, + {0xf0c, 0x0001fff0}, + {0xf4d, 0x0001fff8}, + {0xf8e, 0x0001fffc}, + {0xfcf, 0x0001fffe}, + {0x810, 0x0001ffff}, + {0xbc0, 0x00020000}, + {0xfe0, 0x00020002}, + {0xc01, 0x00030000}, + {0xc21, 0x00030003}, + {0xc42, 0x00038000}, + {0xc83, 0x0003c000}, + {0xcc4, 0x0003e000}, + {0xd05, 0x0003f000}, + {0xd46, 0x0003f800}, + {0xd87, 0x0003fc00}, + {0xdc8, 0x0003fe00}, + {0xe09, 0x0003ff00}, + {0xe4a, 0x0003ff80}, + {0xe8b, 0x0003ffc0}, + {0xecc, 0x0003ffe0}, + {0xf0d, 0x0003fff0}, + {0xf4e, 0x0003fff8}, + {0xf8f, 0x0003fffc}, + {0xfd0, 0x0003fffe}, + {0x811, 0x0003ffff}, + {0xb80, 0x00040000}, + {0xfa0, 0x00040004}, + {0xbc1, 0x00060000}, + {0xfe1, 0x00060006}, + {0xc02, 0x00070000}, + {0xc22, 0x00070007}, + {0xc43, 0x00078000}, + {0xc84, 0x0007c000}, + {0xcc5, 0x0007e000}, + {0xd06, 0x0007f000}, + {0xd47, 0x0007f800}, + {0xd88, 0x0007fc00}, + {0xdc9, 0x0007fe00}, + {0xe0a, 0x0007ff00}, + {0xe4b, 0x0007ff80}, + {0xe8c, 0x0007ffc0}, + {0xecd, 0x0007ffe0}, + {0xf0e, 0x0007fff0}, + {0xf4f, 0x0007fff8}, + {0xf90, 0x0007fffc}, + {0xfd1, 0x0007fffe}, + {0x812, 0x0007ffff}, + {0xb40, 0x00080000}, + {0xf60, 0x00080008}, + {0xb81, 0x000c0000}, + {0xfa1, 0x000c000c}, + {0xbc2, 0x000e0000}, + {0xfe2, 0x000e000e}, + {0xc03, 0x000f0000}, + {0xc23, 0x000f000f}, + {0xc44, 0x000f8000}, + {0xc85, 0x000fc000}, + {0xcc6, 0x000fe000}, + {0xd07, 0x000ff000}, + {0xd48, 0x000ff800}, + {0xd89, 0x000ffc00}, + {0xdca, 0x000ffe00}, + {0xe0b, 0x000fff00}, + {0xe4c, 0x000fff80}, + {0xe8d, 0x000fffc0}, + {0xece, 0x000fffe0}, + {0xf0f, 0x000ffff0}, + {0xf50, 0x000ffff8}, + {0xf91, 0x000ffffc}, + {0xfd2, 0x000ffffe}, + {0x813, 0x000fffff}, + {0xb00, 0x00100000}, + {0xf20, 0x00100010}, + {0xb41, 0x00180000}, + {0xf61, 0x00180018}, + {0xb82, 0x001c0000}, + {0xfa2, 0x001c001c}, + {0xbc3, 0x001e0000}, + {0xfe3, 0x001e001e}, + {0xc04, 0x001f0000}, + {0xc24, 0x001f001f}, + {0xc45, 0x001f8000}, + {0xc86, 0x001fc000}, + {0xcc7, 0x001fe000}, + {0xd08, 0x001ff000}, + {0xd49, 0x001ff800}, + {0xd8a, 0x001ffc00}, + {0xdcb, 0x001ffe00}, + {0xe0c, 0x001fff00}, + {0xe4d, 0x001fff80}, + {0xe8e, 0x001fffc0}, + {0xecf, 0x001fffe0}, + {0xf10, 0x001ffff0}, + {0xf51, 0x001ffff8}, + {0xf92, 0x001ffffc}, + {0xfd3, 0x001ffffe}, + {0x814, 0x001fffff}, + {0xac0, 0x00200000}, + {0xee0, 0x00200020}, + {0xb01, 0x00300000}, + {0xf21, 0x00300030}, + {0xb42, 0x00380000}, + {0xf62, 0x00380038}, + {0xb83, 0x003c0000}, + {0xfa3, 0x003c003c}, + {0xbc4, 0x003e0000}, + {0xfe4, 0x003e003e}, + {0xc05, 0x003f0000}, + {0xc25, 0x003f003f}, + {0xc46, 0x003f8000}, + {0xc87, 0x003fc000}, + {0xcc8, 0x003fe000}, + {0xd09, 0x003ff000}, + {0xd4a, 0x003ff800}, + {0xd8b, 0x003ffc00}, + {0xdcc, 0x003ffe00}, + {0xe0d, 0x003fff00}, + {0xe4e, 0x003fff80}, + {0xe8f, 0x003fffc0}, + {0xed0, 0x003fffe0}, + {0xf11, 0x003ffff0}, + {0xf52, 0x003ffff8}, + {0xf93, 0x003ffffc}, + {0xfd4, 0x003ffffe}, + {0x815, 0x003fffff}, + {0xa80, 0x00400000}, + {0xea0, 0x00400040}, + {0xac1, 0x00600000}, + {0xee1, 0x00600060}, + {0xb02, 0x00700000}, + {0xf22, 0x00700070}, + {0xb43, 0x00780000}, + {0xf63, 0x00780078}, + {0xb84, 0x007c0000}, + {0xfa4, 0x007c007c}, + {0xbc5, 0x007e0000}, + {0xfe5, 0x007e007e}, + {0xc06, 0x007f0000}, + {0xc26, 0x007f007f}, + {0xc47, 0x007f8000}, + {0xc88, 0x007fc000}, + {0xcc9, 0x007fe000}, + {0xd0a, 0x007ff000}, + {0xd4b, 0x007ff800}, + {0xd8c, 0x007ffc00}, + {0xdcd, 0x007ffe00}, + {0xe0e, 0x007fff00}, + {0xe4f, 0x007fff80}, + {0xe90, 0x007fffc0}, + {0xed1, 0x007fffe0}, + {0xf12, 0x007ffff0}, + {0xf53, 0x007ffff8}, + {0xf94, 0x007ffffc}, + {0xfd5, 0x007ffffe}, + {0x816, 0x007fffff}, + {0xa40, 0x00800000}, + {0xe60, 0x00800080}, + {0xa81, 0x00c00000}, + {0xea1, 0x00c000c0}, + {0xac2, 0x00e00000}, + {0xee2, 0x00e000e0}, + {0xb03, 0x00f00000}, + {0xf23, 0x00f000f0}, + {0xb44, 0x00f80000}, + {0xf64, 0x00f800f8}, + {0xb85, 0x00fc0000}, + {0xfa5, 0x00fc00fc}, + {0xbc6, 0x00fe0000}, + {0xfe6, 0x00fe00fe}, + {0xc07, 0x00ff0000}, + {0xc27, 0x00ff00ff}, + {0xc48, 0x00ff8000}, + {0xc89, 0x00ffc000}, + {0xcca, 0x00ffe000}, + {0xd0b, 0x00fff000}, + {0xd4c, 0x00fff800}, + {0xd8d, 0x00fffc00}, + {0xdce, 0x00fffe00}, + {0xe0f, 0x00ffff00}, + {0xe50, 0x00ffff80}, + {0xe91, 0x00ffffc0}, + {0xed2, 0x00ffffe0}, + {0xf13, 0x00fffff0}, + {0xf54, 0x00fffff8}, + {0xf95, 0x00fffffc}, + {0xfd6, 0x00fffffe}, + {0x817, 0x00ffffff}, + {0xa00, 0x01000000}, + {0xe20, 0x01000100}, + {0xe30, 0x01010101}, + {0xa41, 0x01800000}, + {0xe61, 0x01800180}, + {0xa82, 0x01c00000}, + {0xea2, 0x01c001c0}, + {0xac3, 0x01e00000}, + {0xee3, 0x01e001e0}, + {0xb04, 0x01f00000}, + {0xf24, 0x01f001f0}, + {0xb45, 0x01f80000}, + {0xf65, 0x01f801f8}, + {0xb86, 0x01fc0000}, + {0xfa6, 0x01fc01fc}, + {0xbc7, 0x01fe0000}, + {0xfe7, 0x01fe01fe}, + {0xc08, 0x01ff0000}, + {0xc28, 0x01ff01ff}, + {0xc49, 0x01ff8000}, + {0xc8a, 0x01ffc000}, + {0xccb, 0x01ffe000}, + {0xd0c, 0x01fff000}, + {0xd4d, 0x01fff800}, + {0xd8e, 0x01fffc00}, + {0xdcf, 0x01fffe00}, + {0xe10, 0x01ffff00}, + {0xe51, 0x01ffff80}, + {0xe92, 0x01ffffc0}, + {0xed3, 0x01ffffe0}, + {0xf14, 0x01fffff0}, + {0xf55, 0x01fffff8}, + {0xf96, 0x01fffffc}, + {0xfd7, 0x01fffffe}, + {0x818, 0x01ffffff}, + {0x9c0, 0x02000000}, + {0xde0, 0x02000200}, + {0xff0, 0x02020202}, + {0xa01, 0x03000000}, + {0xe21, 0x03000300}, + {0xe31, 0x03030303}, + {0xa42, 0x03800000}, + {0xe62, 0x03800380}, + {0xa83, 0x03c00000}, + {0xea3, 0x03c003c0}, + {0xac4, 0x03e00000}, + {0xee4, 0x03e003e0}, + {0xb05, 0x03f00000}, + {0xf25, 0x03f003f0}, + {0xb46, 0x03f80000}, + {0xf66, 0x03f803f8}, + {0xb87, 0x03fc0000}, + {0xfa7, 0x03fc03fc}, + {0xbc8, 0x03fe0000}, + {0xfe8, 0x03fe03fe}, + {0xc09, 0x03ff0000}, + {0xc29, 0x03ff03ff}, + {0xc4a, 0x03ff8000}, + {0xc8b, 0x03ffc000}, + {0xccc, 0x03ffe000}, + {0xd0d, 0x03fff000}, + {0xd4e, 0x03fff800}, + {0xd8f, 0x03fffc00}, + {0xdd0, 0x03fffe00}, + {0xe11, 0x03ffff00}, + {0xe52, 0x03ffff80}, + {0xe93, 0x03ffffc0}, + {0xed4, 0x03ffffe0}, + {0xf15, 0x03fffff0}, + {0xf56, 0x03fffff8}, + {0xf97, 0x03fffffc}, + {0xfd8, 0x03fffffe}, + {0x819, 0x03ffffff}, + {0x980, 0x04000000}, + {0xda0, 0x04000400}, + {0xfb0, 0x04040404}, + {0x9c1, 0x06000000}, + {0xde1, 0x06000600}, + {0xff1, 0x06060606}, + {0xa02, 0x07000000}, + {0xe22, 0x07000700}, + {0xe32, 0x07070707}, + {0xa43, 0x07800000}, + {0xe63, 0x07800780}, + {0xa84, 0x07c00000}, + {0xea4, 0x07c007c0}, + {0xac5, 0x07e00000}, + {0xee5, 0x07e007e0}, + {0xb06, 0x07f00000}, + {0xf26, 0x07f007f0}, + {0xb47, 0x07f80000}, + {0xf67, 0x07f807f8}, + {0xb88, 0x07fc0000}, + {0xfa8, 0x07fc07fc}, + {0xbc9, 0x07fe0000}, + {0xfe9, 0x07fe07fe}, + {0xc0a, 0x07ff0000}, + {0xc2a, 0x07ff07ff}, + {0xc4b, 0x07ff8000}, + {0xc8c, 0x07ffc000}, + {0xccd, 0x07ffe000}, + {0xd0e, 0x07fff000}, + {0xd4f, 0x07fff800}, + {0xd90, 0x07fffc00}, + {0xdd1, 0x07fffe00}, + {0xe12, 0x07ffff00}, + {0xe53, 0x07ffff80}, + {0xe94, 0x07ffffc0}, + {0xed5, 0x07ffffe0}, + {0xf16, 0x07fffff0}, + {0xf57, 0x07fffff8}, + {0xf98, 0x07fffffc}, + {0xfd9, 0x07fffffe}, + {0x81a, 0x07ffffff}, + {0x940, 0x08000000}, + {0xd60, 0x08000800}, + {0xf70, 0x08080808}, + {0x981, 0x0c000000}, + {0xda1, 0x0c000c00}, + {0xfb1, 0x0c0c0c0c}, + {0x9c2, 0x0e000000}, + {0xde2, 0x0e000e00}, + {0xff2, 0x0e0e0e0e}, + {0xa03, 0x0f000000}, + {0xe23, 0x0f000f00}, + {0xe33, 0x0f0f0f0f}, + {0xa44, 0x0f800000}, + {0xe64, 0x0f800f80}, + {0xa85, 0x0fc00000}, + {0xea5, 0x0fc00fc0}, + {0xac6, 0x0fe00000}, + {0xee6, 0x0fe00fe0}, + {0xb07, 0x0ff00000}, + {0xf27, 0x0ff00ff0}, + {0xb48, 0x0ff80000}, + {0xf68, 0x0ff80ff8}, + {0xb89, 0x0ffc0000}, + {0xfa9, 0x0ffc0ffc}, + {0xbca, 0x0ffe0000}, + {0xfea, 0x0ffe0ffe}, + {0xc0b, 0x0fff0000}, + {0xc2b, 0x0fff0fff}, + {0xc4c, 0x0fff8000}, + {0xc8d, 0x0fffc000}, + {0xcce, 0x0fffe000}, + {0xd0f, 0x0ffff000}, + {0xd50, 0x0ffff800}, + {0xd91, 0x0ffffc00}, + {0xdd2, 0x0ffffe00}, + {0xe13, 0x0fffff00}, + {0xe54, 0x0fffff80}, + {0xe95, 0x0fffffc0}, + {0xed6, 0x0fffffe0}, + {0xf17, 0x0ffffff0}, + {0xf58, 0x0ffffff8}, + {0xf99, 0x0ffffffc}, + {0xfda, 0x0ffffffe}, + {0x81b, 0x0fffffff}, + {0x900, 0x10000000}, + {0xd20, 0x10001000}, + {0xf30, 0x10101010}, + {0xf38, 0x11111111}, + {0x941, 0x18000000}, + {0xd61, 0x18001800}, + {0xf71, 0x18181818}, + {0x982, 0x1c000000}, + {0xda2, 0x1c001c00}, + {0xfb2, 0x1c1c1c1c}, + {0x9c3, 0x1e000000}, + {0xde3, 0x1e001e00}, + {0xff3, 0x1e1e1e1e}, + {0xa04, 0x1f000000}, + {0xe24, 0x1f001f00}, + {0xe34, 0x1f1f1f1f}, + {0xa45, 0x1f800000}, + {0xe65, 0x1f801f80}, + {0xa86, 0x1fc00000}, + {0xea6, 0x1fc01fc0}, + {0xac7, 0x1fe00000}, + {0xee7, 0x1fe01fe0}, + {0xb08, 0x1ff00000}, + {0xf28, 0x1ff01ff0}, + {0xb49, 0x1ff80000}, + {0xf69, 0x1ff81ff8}, + {0xb8a, 0x1ffc0000}, + {0xfaa, 0x1ffc1ffc}, + {0xbcb, 0x1ffe0000}, + {0xfeb, 0x1ffe1ffe}, + {0xc0c, 0x1fff0000}, + {0xc2c, 0x1fff1fff}, + {0xc4d, 0x1fff8000}, + {0xc8e, 0x1fffc000}, + {0xccf, 0x1fffe000}, + {0xd10, 0x1ffff000}, + {0xd51, 0x1ffff800}, + {0xd92, 0x1ffffc00}, + {0xdd3, 0x1ffffe00}, + {0xe14, 0x1fffff00}, + {0xe55, 0x1fffff80}, + {0xe96, 0x1fffffc0}, + {0xed7, 0x1fffffe0}, + {0xf18, 0x1ffffff0}, + {0xf59, 0x1ffffff8}, + {0xf9a, 0x1ffffffc}, + {0xfdb, 0x1ffffffe}, + {0x81c, 0x1fffffff}, + {0x8c0, 0x20000000}, + {0xce0, 0x20002000}, + {0xef0, 0x20202020}, + {0xff8, 0x22222222}, + {0x901, 0x30000000}, + {0xd21, 0x30003000}, + {0xf31, 0x30303030}, + {0xf39, 0x33333333}, + {0x942, 0x38000000}, + {0xd62, 0x38003800}, + {0xf72, 0x38383838}, + {0x983, 0x3c000000}, + {0xda3, 0x3c003c00}, + {0xfb3, 0x3c3c3c3c}, + {0x9c4, 0x3e000000}, + {0xde4, 0x3e003e00}, + {0xff4, 0x3e3e3e3e}, + {0xa05, 0x3f000000}, + {0xe25, 0x3f003f00}, + {0xe35, 0x3f3f3f3f}, + {0xa46, 0x3f800000}, + {0xe66, 0x3f803f80}, + {0xa87, 0x3fc00000}, + {0xea7, 0x3fc03fc0}, + {0xac8, 0x3fe00000}, + {0xee8, 0x3fe03fe0}, + {0xb09, 0x3ff00000}, + {0xf29, 0x3ff03ff0}, + {0xb4a, 0x3ff80000}, + {0xf6a, 0x3ff83ff8}, + {0xb8b, 0x3ffc0000}, + {0xfab, 0x3ffc3ffc}, + {0xbcc, 0x3ffe0000}, + {0xfec, 0x3ffe3ffe}, + {0xc0d, 0x3fff0000}, + {0xc2d, 0x3fff3fff}, + {0xc4e, 0x3fff8000}, + {0xc8f, 0x3fffc000}, + {0xcd0, 0x3fffe000}, + {0xd11, 0x3ffff000}, + {0xd52, 0x3ffff800}, + {0xd93, 0x3ffffc00}, + {0xdd4, 0x3ffffe00}, + {0xe15, 0x3fffff00}, + {0xe56, 0x3fffff80}, + {0xe97, 0x3fffffc0}, + {0xed8, 0x3fffffe0}, + {0xf19, 0x3ffffff0}, + {0xf5a, 0x3ffffff8}, + {0xf9b, 0x3ffffffc}, + {0xfdc, 0x3ffffffe}, + {0x81d, 0x3fffffff}, + {0x880, 0x40000000}, + {0xca0, 0x40004000}, + {0xeb0, 0x40404040}, + {0xfb8, 0x44444444}, + {0xfbc, 0x55555555}, + {0x8c1, 0x60000000}, + {0xce1, 0x60006000}, + {0xef1, 0x60606060}, + {0xff9, 0x66666666}, + {0x902, 0x70000000}, + {0xd22, 0x70007000}, + {0xf32, 0x70707070}, + {0xf3a, 0x77777777}, + {0x943, 0x78000000}, + {0xd63, 0x78007800}, + {0xf73, 0x78787878}, + {0x984, 0x7c000000}, + {0xda4, 0x7c007c00}, + {0xfb4, 0x7c7c7c7c}, + {0x9c5, 0x7e000000}, + {0xde5, 0x7e007e00}, + {0xff5, 0x7e7e7e7e}, + {0xa06, 0x7f000000}, + {0xe26, 0x7f007f00}, + {0xe36, 0x7f7f7f7f}, + {0xa47, 0x7f800000}, + {0xe67, 0x7f807f80}, + {0xa88, 0x7fc00000}, + {0xea8, 0x7fc07fc0}, + {0xac9, 0x7fe00000}, + {0xee9, 0x7fe07fe0}, + {0xb0a, 0x7ff00000}, + {0xf2a, 0x7ff07ff0}, + {0xb4b, 0x7ff80000}, + {0xf6b, 0x7ff87ff8}, + {0xb8c, 0x7ffc0000}, + {0xfac, 0x7ffc7ffc}, + {0xbcd, 0x7ffe0000}, + {0xfed, 0x7ffe7ffe}, + {0xc0e, 0x7fff0000}, + {0xc2e, 0x7fff7fff}, + {0xc4f, 0x7fff8000}, + {0xc90, 0x7fffc000}, + {0xcd1, 0x7fffe000}, + {0xd12, 0x7ffff000}, + {0xd53, 0x7ffff800}, + {0xd94, 0x7ffffc00}, + {0xdd5, 0x7ffffe00}, + {0xe16, 0x7fffff00}, + {0xe57, 0x7fffff80}, + {0xe98, 0x7fffffc0}, + {0xed9, 0x7fffffe0}, + {0xf1a, 0x7ffffff0}, + {0xf5b, 0x7ffffff8}, + {0xf9c, 0x7ffffffc}, + {0xfdd, 0x7ffffffe}, + {0x81e, 0x7fffffff}, + {0x840, 0x80000000}, + {0x841, 0x80000001}, + {0x842, 0x80000003}, + {0x843, 0x80000007}, + {0x844, 0x8000000f}, + {0x845, 0x8000001f}, + {0x846, 0x8000003f}, + {0x847, 0x8000007f}, + {0x848, 0x800000ff}, + {0x849, 0x800001ff}, + {0x84a, 0x800003ff}, + {0x84b, 0x800007ff}, + {0x84c, 0x80000fff}, + {0x84d, 0x80001fff}, + {0x84e, 0x80003fff}, + {0x84f, 0x80007fff}, + {0xc60, 0x80008000}, + {0x850, 0x8000ffff}, + {0xc61, 0x80018001}, + {0x851, 0x8001ffff}, + {0xc62, 0x80038003}, + {0x852, 0x8003ffff}, + {0xc63, 0x80078007}, + {0x853, 0x8007ffff}, + {0xc64, 0x800f800f}, + {0x854, 0x800fffff}, + {0xc65, 0x801f801f}, + {0x855, 0x801fffff}, + {0xc66, 0x803f803f}, + {0x856, 0x803fffff}, + {0xc67, 0x807f807f}, + {0x857, 0x807fffff}, + {0xe70, 0x80808080}, + {0xc68, 0x80ff80ff}, + {0x858, 0x80ffffff}, + {0xe71, 0x81818181}, + {0xc69, 0x81ff81ff}, + {0x859, 0x81ffffff}, + {0xe72, 0x83838383}, + {0xc6a, 0x83ff83ff}, + {0x85a, 0x83ffffff}, + {0xe73, 0x87878787}, + {0xc6b, 0x87ff87ff}, + {0x85b, 0x87ffffff}, + {0xf78, 0x88888888}, + {0xe74, 0x8f8f8f8f}, + {0xc6c, 0x8fff8fff}, + {0x85c, 0x8fffffff}, + {0xf79, 0x99999999}, + {0xe75, 0x9f9f9f9f}, + {0xc6d, 0x9fff9fff}, + {0x85d, 0x9fffffff}, + {0xffc, 0xaaaaaaaa}, + {0xf7a, 0xbbbbbbbb}, + {0xe76, 0xbfbfbfbf}, + {0xc6e, 0xbfffbfff}, + {0x85e, 0xbfffffff}, + {0x881, 0xc0000000}, + {0x882, 0xc0000001}, + {0x883, 0xc0000003}, + {0x884, 0xc0000007}, + {0x885, 0xc000000f}, + {0x886, 0xc000001f}, + {0x887, 0xc000003f}, + {0x888, 0xc000007f}, + {0x889, 0xc00000ff}, + {0x88a, 0xc00001ff}, + {0x88b, 0xc00003ff}, + {0x88c, 0xc00007ff}, + {0x88d, 0xc0000fff}, + {0x88e, 0xc0001fff}, + {0x88f, 0xc0003fff}, + {0x890, 0xc0007fff}, + {0xca1, 0xc000c000}, + {0x891, 0xc000ffff}, + {0xca2, 0xc001c001}, + {0x892, 0xc001ffff}, + {0xca3, 0xc003c003}, + {0x893, 0xc003ffff}, + {0xca4, 0xc007c007}, + {0x894, 0xc007ffff}, + {0xca5, 0xc00fc00f}, + {0x895, 0xc00fffff}, + {0xca6, 0xc01fc01f}, + {0x896, 0xc01fffff}, + {0xca7, 0xc03fc03f}, + {0x897, 0xc03fffff}, + {0xca8, 0xc07fc07f}, + {0x898, 0xc07fffff}, + {0xeb1, 0xc0c0c0c0}, + {0xca9, 0xc0ffc0ff}, + {0x899, 0xc0ffffff}, + {0xeb2, 0xc1c1c1c1}, + {0xcaa, 0xc1ffc1ff}, + {0x89a, 0xc1ffffff}, + {0xeb3, 0xc3c3c3c3}, + {0xcab, 0xc3ffc3ff}, + {0x89b, 0xc3ffffff}, + {0xeb4, 0xc7c7c7c7}, + {0xcac, 0xc7ffc7ff}, + {0x89c, 0xc7ffffff}, + {0xfb9, 0xcccccccc}, + {0xeb5, 0xcfcfcfcf}, + {0xcad, 0xcfffcfff}, + {0x89d, 0xcfffffff}, + {0xfba, 0xdddddddd}, + {0xeb6, 0xdfdfdfdf}, + {0xcae, 0xdfffdfff}, + {0x89e, 0xdfffffff}, + {0x8c2, 0xe0000000}, + {0x8c3, 0xe0000001}, + {0x8c4, 0xe0000003}, + {0x8c5, 0xe0000007}, + {0x8c6, 0xe000000f}, + {0x8c7, 0xe000001f}, + {0x8c8, 0xe000003f}, + {0x8c9, 0xe000007f}, + {0x8ca, 0xe00000ff}, + {0x8cb, 0xe00001ff}, + {0x8cc, 0xe00003ff}, + {0x8cd, 0xe00007ff}, + {0x8ce, 0xe0000fff}, + {0x8cf, 0xe0001fff}, + {0x8d0, 0xe0003fff}, + {0x8d1, 0xe0007fff}, + {0xce2, 0xe000e000}, + {0x8d2, 0xe000ffff}, + {0xce3, 0xe001e001}, + {0x8d3, 0xe001ffff}, + {0xce4, 0xe003e003}, + {0x8d4, 0xe003ffff}, + {0xce5, 0xe007e007}, + {0x8d5, 0xe007ffff}, + {0xce6, 0xe00fe00f}, + {0x8d6, 0xe00fffff}, + {0xce7, 0xe01fe01f}, + {0x8d7, 0xe01fffff}, + {0xce8, 0xe03fe03f}, + {0x8d8, 0xe03fffff}, + {0xce9, 0xe07fe07f}, + {0x8d9, 0xe07fffff}, + {0xef2, 0xe0e0e0e0}, + {0xcea, 0xe0ffe0ff}, + {0x8da, 0xe0ffffff}, + {0xef3, 0xe1e1e1e1}, + {0xceb, 0xe1ffe1ff}, + {0x8db, 0xe1ffffff}, + {0xef4, 0xe3e3e3e3}, + {0xcec, 0xe3ffe3ff}, + {0x8dc, 0xe3ffffff}, + {0xef5, 0xe7e7e7e7}, + {0xced, 0xe7ffe7ff}, + {0x8dd, 0xe7ffffff}, + {0xffa, 0xeeeeeeee}, + {0xef6, 0xefefefef}, + {0xcee, 0xefffefff}, + {0x8de, 0xefffffff}, + {0x903, 0xf0000000}, + {0x904, 0xf0000001}, + {0x905, 0xf0000003}, + {0x906, 0xf0000007}, + {0x907, 0xf000000f}, + {0x908, 0xf000001f}, + {0x909, 0xf000003f}, + {0x90a, 0xf000007f}, + {0x90b, 0xf00000ff}, + {0x90c, 0xf00001ff}, + {0x90d, 0xf00003ff}, + {0x90e, 0xf00007ff}, + {0x90f, 0xf0000fff}, + {0x910, 0xf0001fff}, + {0x911, 0xf0003fff}, + {0x912, 0xf0007fff}, + {0xd23, 0xf000f000}, + {0x913, 0xf000ffff}, + {0xd24, 0xf001f001}, + {0x914, 0xf001ffff}, + {0xd25, 0xf003f003}, + {0x915, 0xf003ffff}, + {0xd26, 0xf007f007}, + {0x916, 0xf007ffff}, + {0xd27, 0xf00ff00f}, + {0x917, 0xf00fffff}, + {0xd28, 0xf01ff01f}, + {0x918, 0xf01fffff}, + {0xd29, 0xf03ff03f}, + {0x919, 0xf03fffff}, + {0xd2a, 0xf07ff07f}, + {0x91a, 0xf07fffff}, + {0xf33, 0xf0f0f0f0}, + {0xd2b, 0xf0fff0ff}, + {0x91b, 0xf0ffffff}, + {0xf34, 0xf1f1f1f1}, + {0xd2c, 0xf1fff1ff}, + {0x91c, 0xf1ffffff}, + {0xf35, 0xf3f3f3f3}, + {0xd2d, 0xf3fff3ff}, + {0x91d, 0xf3ffffff}, + {0xf36, 0xf7f7f7f7}, + {0xd2e, 0xf7fff7ff}, + {0x91e, 0xf7ffffff}, + {0x944, 0xf8000000}, + {0x945, 0xf8000001}, + {0x946, 0xf8000003}, + {0x947, 0xf8000007}, + {0x948, 0xf800000f}, + {0x949, 0xf800001f}, + {0x94a, 0xf800003f}, + {0x94b, 0xf800007f}, + {0x94c, 0xf80000ff}, + {0x94d, 0xf80001ff}, + {0x94e, 0xf80003ff}, + {0x94f, 0xf80007ff}, + {0x950, 0xf8000fff}, + {0x951, 0xf8001fff}, + {0x952, 0xf8003fff}, + {0x953, 0xf8007fff}, + {0xd64, 0xf800f800}, + {0x954, 0xf800ffff}, + {0xd65, 0xf801f801}, + {0x955, 0xf801ffff}, + {0xd66, 0xf803f803}, + {0x956, 0xf803ffff}, + {0xd67, 0xf807f807}, + {0x957, 0xf807ffff}, + {0xd68, 0xf80ff80f}, + {0x958, 0xf80fffff}, + {0xd69, 0xf81ff81f}, + {0x959, 0xf81fffff}, + {0xd6a, 0xf83ff83f}, + {0x95a, 0xf83fffff}, + {0xd6b, 0xf87ff87f}, + {0x95b, 0xf87fffff}, + {0xf74, 0xf8f8f8f8}, + {0xd6c, 0xf8fff8ff}, + {0x95c, 0xf8ffffff}, + {0xf75, 0xf9f9f9f9}, + {0xd6d, 0xf9fff9ff}, + {0x95d, 0xf9ffffff}, + {0xf76, 0xfbfbfbfb}, + {0xd6e, 0xfbfffbff}, + {0x95e, 0xfbffffff}, + {0x985, 0xfc000000}, + {0x986, 0xfc000001}, + {0x987, 0xfc000003}, + {0x988, 0xfc000007}, + {0x989, 0xfc00000f}, + {0x98a, 0xfc00001f}, + {0x98b, 0xfc00003f}, + {0x98c, 0xfc00007f}, + {0x98d, 0xfc0000ff}, + {0x98e, 0xfc0001ff}, + {0x98f, 0xfc0003ff}, + {0x990, 0xfc0007ff}, + {0x991, 0xfc000fff}, + {0x992, 0xfc001fff}, + {0x993, 0xfc003fff}, + {0x994, 0xfc007fff}, + {0xda5, 0xfc00fc00}, + {0x995, 0xfc00ffff}, + {0xda6, 0xfc01fc01}, + {0x996, 0xfc01ffff}, + {0xda7, 0xfc03fc03}, + {0x997, 0xfc03ffff}, + {0xda8, 0xfc07fc07}, + {0x998, 0xfc07ffff}, + {0xda9, 0xfc0ffc0f}, + {0x999, 0xfc0fffff}, + {0xdaa, 0xfc1ffc1f}, + {0x99a, 0xfc1fffff}, + {0xdab, 0xfc3ffc3f}, + {0x99b, 0xfc3fffff}, + {0xdac, 0xfc7ffc7f}, + {0x99c, 0xfc7fffff}, + {0xfb5, 0xfcfcfcfc}, + {0xdad, 0xfcfffcff}, + {0x99d, 0xfcffffff}, + {0xfb6, 0xfdfdfdfd}, + {0xdae, 0xfdfffdff}, + {0x99e, 0xfdffffff}, + {0x9c6, 0xfe000000}, + {0x9c7, 0xfe000001}, + {0x9c8, 0xfe000003}, + {0x9c9, 0xfe000007}, + {0x9ca, 0xfe00000f}, + {0x9cb, 0xfe00001f}, + {0x9cc, 0xfe00003f}, + {0x9cd, 0xfe00007f}, + {0x9ce, 0xfe0000ff}, + {0x9cf, 0xfe0001ff}, + {0x9d0, 0xfe0003ff}, + {0x9d1, 0xfe0007ff}, + {0x9d2, 0xfe000fff}, + {0x9d3, 0xfe001fff}, + {0x9d4, 0xfe003fff}, + {0x9d5, 0xfe007fff}, + {0xde6, 0xfe00fe00}, + {0x9d6, 0xfe00ffff}, + {0xde7, 0xfe01fe01}, + {0x9d7, 0xfe01ffff}, + {0xde8, 0xfe03fe03}, + {0x9d8, 0xfe03ffff}, + {0xde9, 0xfe07fe07}, + {0x9d9, 0xfe07ffff}, + {0xdea, 0xfe0ffe0f}, + {0x9da, 0xfe0fffff}, + {0xdeb, 0xfe1ffe1f}, + {0x9db, 0xfe1fffff}, + {0xdec, 0xfe3ffe3f}, + {0x9dc, 0xfe3fffff}, + {0xded, 0xfe7ffe7f}, + {0x9dd, 0xfe7fffff}, + {0xff6, 0xfefefefe}, + {0xdee, 0xfefffeff}, + {0x9de, 0xfeffffff}, + {0xa07, 0xff000000}, + {0xa08, 0xff000001}, + {0xa09, 0xff000003}, + {0xa0a, 0xff000007}, + {0xa0b, 0xff00000f}, + {0xa0c, 0xff00001f}, + {0xa0d, 0xff00003f}, + {0xa0e, 0xff00007f}, + {0xa0f, 0xff0000ff}, + {0xa10, 0xff0001ff}, + {0xa11, 0xff0003ff}, + {0xa12, 0xff0007ff}, + {0xa13, 0xff000fff}, + {0xa14, 0xff001fff}, + {0xa15, 0xff003fff}, + {0xa16, 0xff007fff}, + {0xe27, 0xff00ff00}, + {0xa17, 0xff00ffff}, + {0xe28, 0xff01ff01}, + {0xa18, 0xff01ffff}, + {0xe29, 0xff03ff03}, + {0xa19, 0xff03ffff}, + {0xe2a, 0xff07ff07}, + {0xa1a, 0xff07ffff}, + {0xe2b, 0xff0fff0f}, + {0xa1b, 0xff0fffff}, + {0xe2c, 0xff1fff1f}, + {0xa1c, 0xff1fffff}, + {0xe2d, 0xff3fff3f}, + {0xa1d, 0xff3fffff}, + {0xe2e, 0xff7fff7f}, + {0xa1e, 0xff7fffff}, + {0xa48, 0xff800000}, + {0xa49, 0xff800001}, + {0xa4a, 0xff800003}, + {0xa4b, 0xff800007}, + {0xa4c, 0xff80000f}, + {0xa4d, 0xff80001f}, + {0xa4e, 0xff80003f}, + {0xa4f, 0xff80007f}, + {0xa50, 0xff8000ff}, + {0xa51, 0xff8001ff}, + {0xa52, 0xff8003ff}, + {0xa53, 0xff8007ff}, + {0xa54, 0xff800fff}, + {0xa55, 0xff801fff}, + {0xa56, 0xff803fff}, + {0xa57, 0xff807fff}, + {0xe68, 0xff80ff80}, + {0xa58, 0xff80ffff}, + {0xe69, 0xff81ff81}, + {0xa59, 0xff81ffff}, + {0xe6a, 0xff83ff83}, + {0xa5a, 0xff83ffff}, + {0xe6b, 0xff87ff87}, + {0xa5b, 0xff87ffff}, + {0xe6c, 0xff8fff8f}, + {0xa5c, 0xff8fffff}, + {0xe6d, 0xff9fff9f}, + {0xa5d, 0xff9fffff}, + {0xe6e, 0xffbfffbf}, + {0xa5e, 0xffbfffff}, + {0xa89, 0xffc00000}, + {0xa8a, 0xffc00001}, + {0xa8b, 0xffc00003}, + {0xa8c, 0xffc00007}, + {0xa8d, 0xffc0000f}, + {0xa8e, 0xffc0001f}, + {0xa8f, 0xffc0003f}, + {0xa90, 0xffc0007f}, + {0xa91, 0xffc000ff}, + {0xa92, 0xffc001ff}, + {0xa93, 0xffc003ff}, + {0xa94, 0xffc007ff}, + {0xa95, 0xffc00fff}, + {0xa96, 0xffc01fff}, + {0xa97, 0xffc03fff}, + {0xa98, 0xffc07fff}, + {0xea9, 0xffc0ffc0}, + {0xa99, 0xffc0ffff}, + {0xeaa, 0xffc1ffc1}, + {0xa9a, 0xffc1ffff}, + {0xeab, 0xffc3ffc3}, + {0xa9b, 0xffc3ffff}, + {0xeac, 0xffc7ffc7}, + {0xa9c, 0xffc7ffff}, + {0xead, 0xffcfffcf}, + {0xa9d, 0xffcfffff}, + {0xeae, 0xffdfffdf}, + {0xa9e, 0xffdfffff}, + {0xaca, 0xffe00000}, + {0xacb, 0xffe00001}, + {0xacc, 0xffe00003}, + {0xacd, 0xffe00007}, + {0xace, 0xffe0000f}, + {0xacf, 0xffe0001f}, + {0xad0, 0xffe0003f}, + {0xad1, 0xffe0007f}, + {0xad2, 0xffe000ff}, + {0xad3, 0xffe001ff}, + {0xad4, 0xffe003ff}, + {0xad5, 0xffe007ff}, + {0xad6, 0xffe00fff}, + {0xad7, 0xffe01fff}, + {0xad8, 0xffe03fff}, + {0xad9, 0xffe07fff}, + {0xeea, 0xffe0ffe0}, + {0xada, 0xffe0ffff}, + {0xeeb, 0xffe1ffe1}, + {0xadb, 0xffe1ffff}, + {0xeec, 0xffe3ffe3}, + {0xadc, 0xffe3ffff}, + {0xeed, 0xffe7ffe7}, + {0xadd, 0xffe7ffff}, + {0xeee, 0xffefffef}, + {0xade, 0xffefffff}, + {0xb0b, 0xfff00000}, + {0xb0c, 0xfff00001}, + {0xb0d, 0xfff00003}, + {0xb0e, 0xfff00007}, + {0xb0f, 0xfff0000f}, + {0xb10, 0xfff0001f}, + {0xb11, 0xfff0003f}, + {0xb12, 0xfff0007f}, + {0xb13, 0xfff000ff}, + {0xb14, 0xfff001ff}, + {0xb15, 0xfff003ff}, + {0xb16, 0xfff007ff}, + {0xb17, 0xfff00fff}, + {0xb18, 0xfff01fff}, + {0xb19, 0xfff03fff}, + {0xb1a, 0xfff07fff}, + {0xf2b, 0xfff0fff0}, + {0xb1b, 0xfff0ffff}, + {0xf2c, 0xfff1fff1}, + {0xb1c, 0xfff1ffff}, + {0xf2d, 0xfff3fff3}, + {0xb1d, 0xfff3ffff}, + {0xf2e, 0xfff7fff7}, + {0xb1e, 0xfff7ffff}, + {0xb4c, 0xfff80000}, + {0xb4d, 0xfff80001}, + {0xb4e, 0xfff80003}, + {0xb4f, 0xfff80007}, + {0xb50, 0xfff8000f}, + {0xb51, 0xfff8001f}, + {0xb52, 0xfff8003f}, + {0xb53, 0xfff8007f}, + {0xb54, 0xfff800ff}, + {0xb55, 0xfff801ff}, + {0xb56, 0xfff803ff}, + {0xb57, 0xfff807ff}, + {0xb58, 0xfff80fff}, + {0xb59, 0xfff81fff}, + {0xb5a, 0xfff83fff}, + {0xb5b, 0xfff87fff}, + {0xf6c, 0xfff8fff8}, + {0xb5c, 0xfff8ffff}, + {0xf6d, 0xfff9fff9}, + {0xb5d, 0xfff9ffff}, + {0xf6e, 0xfffbfffb}, + {0xb5e, 0xfffbffff}, + {0xb8d, 0xfffc0000}, + {0xb8e, 0xfffc0001}, + {0xb8f, 0xfffc0003}, + {0xb90, 0xfffc0007}, + {0xb91, 0xfffc000f}, + {0xb92, 0xfffc001f}, + {0xb93, 0xfffc003f}, + {0xb94, 0xfffc007f}, + {0xb95, 0xfffc00ff}, + {0xb96, 0xfffc01ff}, + {0xb97, 0xfffc03ff}, + {0xb98, 0xfffc07ff}, + {0xb99, 0xfffc0fff}, + {0xb9a, 0xfffc1fff}, + {0xb9b, 0xfffc3fff}, + {0xb9c, 0xfffc7fff}, + {0xfad, 0xfffcfffc}, + {0xb9d, 0xfffcffff}, + {0xfae, 0xfffdfffd}, + {0xb9e, 0xfffdffff}, + {0xbce, 0xfffe0000}, + {0xbcf, 0xfffe0001}, + {0xbd0, 0xfffe0003}, + {0xbd1, 0xfffe0007}, + {0xbd2, 0xfffe000f}, + {0xbd3, 0xfffe001f}, + {0xbd4, 0xfffe003f}, + {0xbd5, 0xfffe007f}, + {0xbd6, 0xfffe00ff}, + {0xbd7, 0xfffe01ff}, + {0xbd8, 0xfffe03ff}, + {0xbd9, 0xfffe07ff}, + {0xbda, 0xfffe0fff}, + {0xbdb, 0xfffe1fff}, + {0xbdc, 0xfffe3fff}, + {0xbdd, 0xfffe7fff}, + {0xfee, 0xfffefffe}, + {0xbde, 0xfffeffff}, + {0xc0f, 0xffff0000}, + {0xc10, 0xffff0001}, + {0xc11, 0xffff0003}, + {0xc12, 0xffff0007}, + {0xc13, 0xffff000f}, + {0xc14, 0xffff001f}, + {0xc15, 0xffff003f}, + {0xc16, 0xffff007f}, + {0xc17, 0xffff00ff}, + {0xc18, 0xffff01ff}, + {0xc19, 0xffff03ff}, + {0xc1a, 0xffff07ff}, + {0xc1b, 0xffff0fff}, + {0xc1c, 0xffff1fff}, + {0xc1d, 0xffff3fff}, + {0xc1e, 0xffff7fff}, + {0xc50, 0xffff8000}, + {0xc51, 0xffff8001}, + {0xc52, 0xffff8003}, + {0xc53, 0xffff8007}, + {0xc54, 0xffff800f}, + {0xc55, 0xffff801f}, + {0xc56, 0xffff803f}, + {0xc57, 0xffff807f}, + {0xc58, 0xffff80ff}, + {0xc59, 0xffff81ff}, + {0xc5a, 0xffff83ff}, + {0xc5b, 0xffff87ff}, + {0xc5c, 0xffff8fff}, + {0xc5d, 0xffff9fff}, + {0xc5e, 0xffffbfff}, + {0xc91, 0xffffc000}, + {0xc92, 0xffffc001}, + {0xc93, 0xffffc003}, + {0xc94, 0xffffc007}, + {0xc95, 0xffffc00f}, + {0xc96, 0xffffc01f}, + {0xc97, 0xffffc03f}, + {0xc98, 0xffffc07f}, + {0xc99, 0xffffc0ff}, + {0xc9a, 0xffffc1ff}, + {0xc9b, 0xffffc3ff}, + {0xc9c, 0xffffc7ff}, + {0xc9d, 0xffffcfff}, + {0xc9e, 0xffffdfff}, + {0xcd2, 0xffffe000}, + {0xcd3, 0xffffe001}, + {0xcd4, 0xffffe003}, + {0xcd5, 0xffffe007}, + {0xcd6, 0xffffe00f}, + {0xcd7, 0xffffe01f}, + {0xcd8, 0xffffe03f}, + {0xcd9, 0xffffe07f}, + {0xcda, 0xffffe0ff}, + {0xcdb, 0xffffe1ff}, + {0xcdc, 0xffffe3ff}, + {0xcdd, 0xffffe7ff}, + {0xcde, 0xffffefff}, + {0xd13, 0xfffff000}, + {0xd14, 0xfffff001}, + {0xd15, 0xfffff003}, + {0xd16, 0xfffff007}, + {0xd17, 0xfffff00f}, + {0xd18, 0xfffff01f}, + {0xd19, 0xfffff03f}, + {0xd1a, 0xfffff07f}, + {0xd1b, 0xfffff0ff}, + {0xd1c, 0xfffff1ff}, + {0xd1d, 0xfffff3ff}, + {0xd1e, 0xfffff7ff}, + {0xd54, 0xfffff800}, + {0xd55, 0xfffff801}, + {0xd56, 0xfffff803}, + {0xd57, 0xfffff807}, + {0xd58, 0xfffff80f}, + {0xd59, 0xfffff81f}, + {0xd5a, 0xfffff83f}, + {0xd5b, 0xfffff87f}, + {0xd5c, 0xfffff8ff}, + {0xd5d, 0xfffff9ff}, + {0xd5e, 0xfffffbff}, + {0xd95, 0xfffffc00}, + {0xd96, 0xfffffc01}, + {0xd97, 0xfffffc03}, + {0xd98, 0xfffffc07}, + {0xd99, 0xfffffc0f}, + {0xd9a, 0xfffffc1f}, + {0xd9b, 0xfffffc3f}, + {0xd9c, 0xfffffc7f}, + {0xd9d, 0xfffffcff}, + {0xd9e, 0xfffffdff}, + {0xdd6, 0xfffffe00}, + {0xdd7, 0xfffffe01}, + {0xdd8, 0xfffffe03}, + {0xdd9, 0xfffffe07}, + {0xdda, 0xfffffe0f}, + {0xddb, 0xfffffe1f}, + {0xddc, 0xfffffe3f}, + {0xddd, 0xfffffe7f}, + {0xdde, 0xfffffeff}, + {0xe17, 0xffffff00}, + {0xe18, 0xffffff01}, + {0xe19, 0xffffff03}, + {0xe1a, 0xffffff07}, + {0xe1b, 0xffffff0f}, + {0xe1c, 0xffffff1f}, + {0xe1d, 0xffffff3f}, + {0xe1e, 0xffffff7f}, + {0xe58, 0xffffff80}, + {0xe59, 0xffffff81}, + {0xe5a, 0xffffff83}, + {0xe5b, 0xffffff87}, + {0xe5c, 0xffffff8f}, + {0xe5d, 0xffffff9f}, + {0xe5e, 0xffffffbf}, + {0xe99, 0xffffffc0}, + {0xe9a, 0xffffffc1}, + {0xe9b, 0xffffffc3}, + {0xe9c, 0xffffffc7}, + {0xe9d, 0xffffffcf}, + {0xe9e, 0xffffffdf}, + {0xeda, 0xffffffe0}, + {0xedb, 0xffffffe1}, + {0xedc, 0xffffffe3}, + {0xedd, 0xffffffe7}, + {0xede, 0xffffffef}, + {0xf1b, 0xfffffff0}, + {0xf1c, 0xfffffff1}, + {0xf1d, 0xfffffff3}, + {0xf1e, 0xfffffff7}, + {0xf5c, 0xfffffff8}, + {0xf5d, 0xfffffff9}, + {0xf5e, 0xfffffffb}, + {0xf9d, 0xfffffffc}, + {0xf9e, 0xfffffffd}, + {0xfde, 0xfffffffe}, +}; + +uint32_t host_arm64_find_imm(uint32_t data) +{ + int l = 0, r = IMM_NR - 1; + + while (l <= r) + { + int m = (l + r) >> 1; + + if (imm_table[m][1] < data) + l = m+1; + else if (imm_table[m][1] > data) + r = m-1; + else + return imm_table[m][0]; + } + return 0; +} diff --git a/src/codegen_backend_arm64_ops.c b/src/codegen_backend_arm64_ops.c new file mode 100644 index 0000000..552665a --- /dev/null +++ b/src/codegen_backend_arm64_ops.c @@ -0,0 +1,1382 @@ +#ifdef __aarch64__ + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" + + +#define Rt(x) (x) +#define Rd(x) (x) +#define Rn(x) ((x) << 5) +#define Rt2(x) ((x) << 10) +#define Rm(x) ((x) << 16) + +#define shift_imm6(x) ((x) << 10) + +#define DATA_OFFSET_UP (1 << 23) +#define DATA_OFFSET_DOWN (0 << 23) + +#define COND_EQ (0x0) +#define COND_NE (0x1) +#define COND_CS (0x2) +#define COND_CC (0x3) +#define COND_MI (0x4) +#define COND_PL (0x5) +#define COND_VS (0x6) +#define COND_VC (0x7) +#define COND_HI (0x8) +#define COND_LS (0x9) +#define COND_GE (0xa) +#define COND_LT (0xb) +#define COND_GT (0xc) +#define COND_LE (0xd) + +#define CSEL_COND(cond) ((cond) << 12) + +#define OPCODE_SHIFT 24 +#define OPCODE_ADD_IMM (0x11 << OPCODE_SHIFT) +#define OPCODE_ADDX_IMM (0x91 << OPCODE_SHIFT) +#define OPCODE_ADR (0x10 << OPCODE_SHIFT) +#define OPCODE_B (0x14 << OPCODE_SHIFT) +#define OPCODE_BCOND (0x54 << OPCODE_SHIFT) +#define OPCODE_CBNZ (0xb5 << OPCODE_SHIFT) +#define OPCODE_CBZ (0xb4 << OPCODE_SHIFT) +#define OPCODE_CMN_IMM (0x31 << OPCODE_SHIFT) +#define OPCODE_CMNX_IMM (0xb1 << OPCODE_SHIFT) +#define OPCODE_CMP_IMM (0x71 << OPCODE_SHIFT) +#define OPCODE_CMPX_IMM (0xf1 << OPCODE_SHIFT) +#define OPCODE_SUB_IMM (0x51 << OPCODE_SHIFT) +#define OPCODE_SUBX_IMM (0xd1 << OPCODE_SHIFT) +#define OPCODE_TBNZ (0x37 << OPCODE_SHIFT) +#define OPCODE_TBZ (0x36 << OPCODE_SHIFT) + +#define OPCODE_AND_IMM (0x024 << 23) +#define OPCODE_ANDS_IMM (0x0e4 << 23) +#define OPCODE_EOR_IMM (0x0a4 << 23) +#define OPCODE_MOVK_W (0x0e5 << 23) +#define OPCODE_MOVK_X (0x1e5 << 23) +#define OPCODE_MOVZ_W (0x0a5 << 23) +#define OPCODE_MOVZ_X (0x1a5 << 23) +#define OPCODE_ORR_IMM (0x064 << 23) + +#define OPCODE_BFI (0x0cc << 22) +#define OPCODE_LDR_IMM_W (0x2e5 << 22) +#define OPCODE_LDR_IMM_X (0x3e5 << 22) +#define OPCODE_LDR_IMM_F64 (0x3f5 << 22) +#define OPCODE_LDRB_IMM_W (0x0e5 << 22) +#define OPCODE_LDRH_IMM (0x1e5 << 22) +#define OPCODE_LDP_POSTIDX_X (0x2a3 << 22) +#define OPCODE_SBFX (0x04c << 22) +#define OPCODE_STP_PREIDX_X (0x2a6 << 22) +#define OPCODE_STR_IMM_W (0x2e4 << 22) +#define OPCODE_STR_IMM_Q (0x3e4 << 22) +#define OPCODE_STR_IMM_F64 (0x3f4 << 22) +#define OPCODE_STRB_IMM (0x0e4 << 22) +#define OPCODE_STRH_IMM (0x1e4 << 22) +#define OPCODE_UBFX (0x14c << 22) + +#define OPCODE_ADD_LSL (0x058 << 21) +#define OPCODE_ADD_LSR (0x05a << 21) +#define OPCODE_ADDX_LSL (0x458 << 21) +#define OPCODE_AND_ASR (0x054 << 21) +#define OPCODE_AND_LSL (0x050 << 21) +#define OPCODE_AND_ROR (0x056 << 21) +#define OPCODE_ANDS_LSL (0x350 << 21) +#define OPCODE_CMP_LSL (0x358 << 21) +#define OPCODE_CSEL (0x0d4 << 21) +#define OPCODE_EOR_LSL (0x250 << 21) +#define OPCODE_ORR_ASR (0x154 << 21) +#define OPCODE_ORR_LSL (0x150 << 21) +#define OPCODE_ORR_LSR (0x152 << 21) +#define OPCODE_ORR_ROR (0x156 << 21) +#define OPCODE_ORRX_LSL (0x550 << 21) +#define OPCODE_SUB_LSL (0x258 << 21) +#define OPCODE_SUB_LSR (0x25a << 21) +#define OPCODE_SUBX_LSL (0x658 << 21) + +#define OPCODE_ADD_V8B (0x0e208400) +#define OPCODE_ADD_V4H (0x0e608400) +#define OPCODE_ADD_V2S (0x0ea08400) +#define OPCODE_ADDP_V4S (0x4ea0bc00) +#define OPCODE_AND_V (0x0e201c00) +#define OPCODE_ASR (0x1ac02800) +#define OPCODE_BIC_V (0x0e601c00) +#define OPCODE_BLR (0xd63f0000) +#define OPCODE_BR (0xd61f0000) +#define OPCODE_CMEQ_V8B (0x2e208c00) +#define OPCODE_CMEQ_V4H (0x2e608c00) +#define OPCODE_CMEQ_V2S (0x2ea08c00) +#define OPCODE_CMGT_V8B (0x0e203400) +#define OPCODE_CMGT_V4H (0x0e603400) +#define OPCODE_CMGT_V2S (0x0ea03400) +#define OPCODE_DUP_V2S (0x0e040400) +#define OPCODE_EOR_V (0x2e201c00) +#define OPCODE_FABS_D (0x1e60c000) +#define OPCODE_FADD_D (0x1e602800) +#define OPCODE_FADD_V2S (0x0e20d400) +#define OPCODE_FCMEQ_V2S (0x0e20e400) +#define OPCODE_FCMGE_V2S (0x2e20e400) +#define OPCODE_FCMGT_V2S (0x2ea0e400) +#define OPCODE_FCMP_D (0x1e602000) +#define OPCODE_FCVT_D_S (0x1e22c000) +#define OPCODE_FCVT_S_D (0x1e624000) +#define OPCODE_FCVTMS_W_D (0x1e700000) +#define OPCODE_FCVTMS_X_D (0x9e700000) +#define OPCODE_FCVTNS_W_D (0x1e600000) +#define OPCODE_FCVTNS_X_D (0x9e600000) +#define OPCODE_FCVTPS_W_D (0x1e680000) +#define OPCODE_FCVTPS_X_D (0x9e680000) +#define OPCODE_FCVTZS_W_D (0x1e780000) +#define OPCODE_FCVTZS_X_D (0x9e780000) +#define OPCODE_FCVTZS_V2S (0x0ea1b800) +#define OPCODE_FDIV_D (0x1e601800) +#define OPCODE_FDIV_S (0x1e201800) +#define OPCODE_FMAX_V2S (0x0e20f400) +#define OPCODE_FMIN_V2S (0x0ea0f400) +#define OPCODE_FMOV_D_D (0x1e604000) +#define OPCODE_FMOV_D_Q (0x9e670000) +#define OPCODE_FMOV_Q_D (0x9e660000) +#define OPCODE_FMOV_S_W (0x1e270000) +#define OPCODE_FMOV_W_S (0x1e260000) +#define OPCODE_FMOV_S_ONE (0x1e2e1000) +#define OPCODE_FMUL_D (0x1e600800) +#define OPCODE_FMUL_V2S (0x2e20dc00) +#define OPCODE_FNEG_D (0x1e614000) +#define OPCODE_FRINTX_D (0x1e674000) +#define OPCODE_FSQRT_D (0x1e61c000) +#define OPCODE_FSQRT_S (0x1e21c000) +#define OPCODE_FSUB_D (0x1e603800) +#define OPCODE_FSUB_V2S (0x0ea0d400) +#define OPCODE_LDR_REG (0xb8606800) +#define OPCODE_LDRX_REG (0xf8606800) +#define OPCODE_LDRB_REG (0x38606800) +#define OPCODE_LDRH_REG (0x78606800) +#define OPCODE_LDRX_REG_LSL3 (0xf8607800) +#define OPCODE_LDR_REG_F32 (0xbc606800) +#define OPCODE_LDR_REG_F64 (0xfc606800) +#define OPCODE_LDR_REG_F64_S (0xfc607800) +#define OPCODE_LSL (0x1ac02000) +#define OPCODE_LSR (0x1ac02400) +#define OPCODE_MSR_FPCR (0xd51b4400) +#define OPCODE_MUL_V4H (0x0e609c00) +#define OPCODE_NOP (0xd503201f) +#define OPCODE_ORR_V (0x0ea01c00) +#define OPCODE_RET (0xd65f0000) +#define OPCODE_ROR (0x1ac02c00) +#define OPCODE_SADDLP_V2S_4H (0x0e602800) +#define OPCODE_SCVTF_D_Q (0x9e620000) +#define OPCODE_SCVTF_D_W (0x1e620000) +#define OPCODE_SCVTF_V2S (0x0e21d800) +#define OPCODE_SQADD_V8B (0x0e200c00) +#define OPCODE_SQADD_V4H (0x0e600c00) +#define OPCODE_SQSUB_V8B (0x0e202c00) +#define OPCODE_SQSUB_V4H (0x0e602c00) +#define OPCODE_SQXTN_V8B_8H (0x0e214800) +#define OPCODE_SQXTN_V4H_4S (0x0e614800) +#define OPCODE_SHL_VD (0x0f005400) +#define OPCODE_SHL_VQ (0x4f005400) +#define OPCODE_SHRN (0x0f008400) +#define OPCODE_SMULL_V4S_4H (0x0e60c000) +#define OPCODE_SSHR_VD (0x0f000400) +#define OPCODE_SSHR_VQ (0x4f000400) +#define OPCODE_STR_REG (0xb8206800) +#define OPCODE_STRB_REG (0x38206800) +#define OPCODE_STRH_REG (0x78206800) +#define OPCODE_STR_REG_F32 (0xbc206800) +#define OPCODE_STR_REG_F64 (0xfc206800) +#define OPCODE_STR_REG_F64_S (0xfc207800) +#define OPCODE_SUB_V8B (0x2e208400) +#define OPCODE_SUB_V4H (0x2e608400) +#define OPCODE_SUB_V2S (0x2ea08400) +#define OPCODE_UQADD_V8B (0x2e200c00) +#define OPCODE_UQADD_V4H (0x2e600c00) +#define OPCODE_UQSUB_V8B (0x2e202c00) +#define OPCODE_UQSUB_V4H (0x2e602c00) +#define OPCODE_UQXTN_V8B_8H (0x2e214800) +#define OPCODE_UQXTN_V4H_4S (0x2e614800) +#define OPCODE_USHR_VD (0x2f000400) +#define OPCODE_USHR_VQ (0x6f000400) +#define OPCODE_ZIP1_V8B (0x0e003800) +#define OPCODE_ZIP1_V4H (0x0e403800) +#define OPCODE_ZIP1_V2S (0x0e803800) +#define OPCODE_ZIP2_V8B (0x0e007800) +#define OPCODE_ZIP2_V4H (0x0e407800) +#define OPCODE_ZIP2_V2S (0x0e807800) + +#define DATPROC_SHIFT(sh) (sh << 10) +#define DATPROC_IMM_SHIFT(sh) (sh << 22) +#define MOV_WIDE_HW(hw) (hw << 21) + +#define IMM7_X(imm_data) (((imm_data >> 3) & 0x7f) << 15) +#define IMM12(imm_data) ((imm_data) << 10) +#define IMM16(imm_data) ((imm_data) << 5) + +#define IMMN(immn) ((immn) << 22) +#define IMMR(immr) ((immr) << 16) +#define IMMS(imms) ((imms) << 10) + +#define IMM_LOGICAL(imm) ((imm) << 10) + +#define BIT_TBxZ(bit) ((((bit) & 0x1f) << 19) | (((bit) & 0x20) ? (1 << 31) : 0)) + +#define OFFSET14(offset) (((offset >> 2) << 5) & 0x0007ffe0) +#define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0) +#define OFFSET20(offset) (((offset & 3) << 29) | ((((offset) & 0x1fffff) >> 2) << 5)) +#define OFFSET26(offset) ((offset >> 2) & 0x03ffffff) + +#define OFFSET12_B(offset) (offset << 10) +#define OFFSET12_H(offset) ((offset >> 1) << 10) +#define OFFSET12_W(offset) ((offset >> 2) << 10) +#define OFFSET12_Q(offset) ((offset >> 3) << 10) + +#define SHIFT_IMM_V4H(shift) (((shift) | 0x10) << 16) +#define SHIFT_IMM_V2S(shift) (((shift) | 0x20) << 16) +#define SHIFT_IMM_V2D(shift) (((shift) | 0x40) << 16) + +#define SHRN_SHIFT_IMM_V4S(shift) (((shift) | 0x10) << 16) + +#define DUP_ELEMENT(element) ((element) << 19) + +/*Returns true if offset fits into 19 bits*/ +static int offset_is_19bit(int offset) +{ + if (offset >= (1 << (18+2))) + return 0; + if (offset < -(1 << (18+2))) + return 0; + return 1; +} + +/*Returns true if offset fits into 26 bits*/ +static int offset_is_26bit(int offset) +{ + if (offset >= (1 << (25+2))) + return 0; + if (offset < -(1 << (25+2))) + return 0; + return 1; +} + +static inline int imm_is_imm16(uint32_t imm_data) +{ + if (!(imm_data & 0xffff0000) || !(imm_data & 0x0000ffff)) + return 1; + return 0; +} +static inline int imm_is_imm12(uint32_t imm_data) +{ + if (!(imm_data & 0xfffff000) || !(imm_data & 0xff000fff)) + return 1; + return 0; +} + +static void codegen_allocate_new_block(codeblock_t *block); + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + if (block_pos >= (BLOCK_MAX-4)) + codegen_allocate_new_block(block); + *(uint32_t *)&block_write_data[block_pos] = val; + block_pos += 4; +} + +static void codegen_allocate_new_block(codeblock_t *block) +{ + /*Current block is full. Allocate a new block*/ + struct mem_block_t *new_block = codegen_allocator_allocate(block->head_mem_block, get_block_nr(block)); + uint8_t *new_ptr = codeblock_allocator_get_ptr(new_block); + uint32_t offset = (uintptr_t)new_ptr - (uintptr_t)&block_write_data[block_pos]; + + if (!offset_is_26bit(offset)) + fatal("codegen_allocate_new_block - offset out of range %x\n", offset); + /*Add a jump instruction to the new block*/ + *(uint32_t *)&block_write_data[block_pos] = OPCODE_B | OFFSET26(offset); + + /*Set write address to start of new block*/ + block_pos = 0; + block_write_data = new_ptr; +} + +void codegen_alloc(codeblock_t *block, int size) +{ + if (block_pos >= (BLOCK_MAX-size)) + codegen_allocate_new_block(block); +} + +void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (!imm_data) + host_arm64_MOV_REG(block, dst_reg, src_n_reg, 0); + else if ((int32_t)imm_data < 0 && imm_data != 0x80000000) + { + host_arm64_SUB_IMM(block, dst_reg, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xff000000)) + { + if (imm_data & 0xfff) + { + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + { + host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); + codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_ADDX_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint64_t imm_data) +{ + if (!(imm_data & ~0xffffffull)) + { + if (imm_data & 0xfff) + { + codegen_addlong(block, OPCODE_ADDX_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADDX_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_ADDX_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + fatal("ADD_IMM_X %016llx\n", imm_data); +} +void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ADD_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ADD_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_ADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ADD_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ADD_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ADD_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ADD_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_ADDP_V4S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ADDP_V4S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_ADR(codeblock_t *block, int dst_reg, int offset) +{ + codegen_addlong(block, OPCODE_ADR | Rd(dst_reg) | OFFSET20(offset)); +} + +void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + uint32_t imm_encoding = host_arm64_find_imm(imm_data); + + if (imm_encoding) + { + codegen_addlong(block, OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM_LOGICAL(imm_encoding)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_AND_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_AND_REG_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_ASR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_AND_REG_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_AND_ROR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_AND_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_AND_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_ANDS_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + uint32_t imm_encoding = host_arm64_find_imm(imm_data); + + if (imm_encoding) + { + codegen_addlong(block, OPCODE_ANDS_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM_LOGICAL(imm_encoding)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_ANDS_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} + +void host_arm64_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg) +{ + codegen_addlong(block, OPCODE_ASR | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); +} + +void host_arm64_B(codeblock_t *block, void *dest) +{ + int offset; + + codegen_alloc(block, 4); + offset = (uintptr_t)dest - (uintptr_t)&block_write_data[block_pos]; + + if (!offset_is_26bit(offset)) + fatal("host_arm64_B - offset out of range %x\n", offset); + codegen_addlong(block, OPCODE_B | OFFSET26(offset)); +} + +void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR((32 - lsb) & 31) | IMMS((width-1) & 31)); +} + +void host_arm64_BLR(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BLR | Rn(addr_reg)); +} + +uint32_t *host_arm64_BCC_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_CS | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BCS_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_CC | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BEQ_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_NE | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BGE_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_LT | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BGT_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_LE | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BHI_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_LS | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BLE_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_GT | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BLS_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_HI | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BLT_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_GE | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BMI_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_PL | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BNE_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_EQ | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BPL_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_MI | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BVC_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_VS | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_arm64_BVS_(codeblock_t *block) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_BCOND | COND_VC | OFFSET19(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_arm64_branch_set_offset(uint32_t *opcode, void *dest) +{ + int offset = (uintptr_t)dest - (uintptr_t)opcode; + *opcode |= OFFSET26(offset); +} + +void host_arm64_BR(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BR | Rn(addr_reg)); +} + +void host_arm64_BEQ(codeblock_t *block, void *dest) +{ + uint32_t *opcode = host_arm64_BEQ_(block); + host_arm64_branch_set_offset(opcode, dest); +} + +void host_arm64_BIC_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_BIC_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest) +{ + int offset; + + codegen_alloc(block, 4); + offset = dest - (uintptr_t)&block_write_data[block_pos]; + if (offset_is_19bit(offset)) + { + codegen_addlong(block, OPCODE_CBNZ | OFFSET19(offset) | Rt(reg)); + } + else + { + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_CBZ | OFFSET19(8) | Rt(reg)); + offset = (uintptr_t)dest - (uintptr_t)&block_write_data[block_pos]; + codegen_addlong(block, OPCODE_B | OFFSET26(offset)); + } +} + +void host_arm64_CMEQ_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMEQ_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMEQ_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMEQ_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMEQ_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMEQ_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMGT_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMGT_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMGT_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMGT_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CMGT_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CMGT_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_CMN_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data) +{ + if ((int32_t)imm_data < 0 && imm_data != (1ull << 31)) + { + host_arm64_CMP_IMM(block, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xfffff000)) + { + codegen_addlong(block, OPCODE_CMN_IMM | Rd(REG_WZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMN_IMM %08x\n", imm_data); +} +void host_arm64_CMNX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data) +{ + if ((int64_t)imm_data < 0 && imm_data != (1ull << 63)) + { + host_arm64_CMPX_IMM(block, src_n_reg, -(int64_t)imm_data); + } + else if (!(imm_data & 0xfffffffffffff000ull)) + { + codegen_addlong(block, OPCODE_CMNX_IMM | Rd(REG_XZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMNX_IMM %08x\n", imm_data); +} + +void host_arm64_CMP_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data) +{ + if ((int32_t)imm_data < 0 && imm_data != (1ull << 31)) + { + host_arm64_CMN_IMM(block, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xfffff000)) + { + codegen_addlong(block, OPCODE_CMP_IMM | Rd(REG_WZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMP_IMM %08x\n", imm_data); +} +void host_arm64_CMPX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data) +{ + if ((int64_t)imm_data < 0 && imm_data != (1ull << 63)) + { + host_arm64_CMNX_IMM(block, src_n_reg, -(int64_t)imm_data); + } + else if (!(imm_data & 0xfffffffffffff000ull)) + { + codegen_addlong(block, OPCODE_CMPX_IMM | Rd(REG_XZR) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + } + else + fatal("CMPX_IMM %08x\n", imm_data); +} + +void host_arm64_CMP_REG_LSL(codeblock_t *block, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_CMP_LSL | Rd(0x1f) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_CSEL_CC(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CSEL | CSEL_COND(COND_CC) | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CSEL_EQ(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CSEL | CSEL_COND(COND_EQ) | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_CSEL_VS(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_CSEL | CSEL_COND(COND_VS) | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_DUP_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int element) +{ + codegen_addlong(block, OPCODE_DUP_V2S | Rd(dst_reg) | Rn(src_n_reg) | DUP_ELEMENT(element)); +} + +void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + uint32_t imm_encoding = host_arm64_find_imm(imm_data); + + if (imm_encoding) + { + codegen_addlong(block, OPCODE_EOR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM_LOGICAL(imm_encoding)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_EOR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_EOR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_EOR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_EOR_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FABS_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FABS_D | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FADD_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FADD_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FADD_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FADD_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FCMEQ_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FCMEQ_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FCMGE_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FCMGE_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FCMGT_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FCMGT_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FCMP_D(codeblock_t *block, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FCMP_D | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FCVT_D_S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVT_D_S | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVT_S_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVT_S_D | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FCVTMS_W_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTMS_W_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTMS_X_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTMS_X_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTNS_W_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTNS_W_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTNS_X_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTNS_X_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTPS_W_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTPS_W_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTPS_X_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTPS_X_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTZS_W_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTZS_W_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTZS_X_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTZS_X_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FCVTZS_V2S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FCVTZS_V2S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FDIV_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FDIV_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FDIV_S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FDIV_S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FMAX_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMAX_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FMIN_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMIN_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FMUL_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMUL_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FMUL_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FMUL_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FSUB_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FSUB_D | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_FSUB_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_FSUB_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_FMOV_D_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_D_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_D_Q(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_D_Q | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_Q_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_Q_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_S_W(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_S_W | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_W_S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FMOV_W_S | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FMOV_S_ONE(codeblock_t *block, int dst_reg) +{ + codegen_addlong(block, OPCODE_FMOV_S_ONE | Rd(dst_reg)); +} + +void host_arm64_FNEG_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FNEG_D | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FRINTX_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FRINTX_D | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_FSQRT_D(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FSQRT_D | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_FSQRT_S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_FSQRT_S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) +{ + if (!in_range7_x(offset)) + fatal("host_arm64_LDP_POSTIDX out of range7 %i\n", offset); + codegen_addlong(block, OPCODE_LDP_POSTIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); +} + +void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_w(offset)) + fatal("host_arm64_LDR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_IMM_X(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_q(offset)) + fatal("host_arm64_LDR_IMM_X out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDR_IMM_X | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} + +void host_arm64_LDR_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_REG_X(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRX_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDR_REG_F32(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG_F32 | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_IMM_F64(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + codegen_addlong(block, OPCODE_LDR_IMM_F64 | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_REG_F64(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG_F64 | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} +void host_arm64_LDR_REG_F64_S(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDR_REG_F64_S | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_b(offset)) + fatal("host_arm64_LDRB_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDRB_IMM_W | OFFSET12_B(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDRB_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRB_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRH_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_h(offset)) + fatal("host_arm64_LDRH_IMM out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_LDRH_IMM | OFFSET12_H(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_LDRH_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRH_REG | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LDRX_REG_LSL3(codeblock_t *block, int dest_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_LDRX_REG_LSL3 | Rn(base_reg) | Rm(offset_reg) | Rt(dest_reg)); +} + +void host_arm64_LSL(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg) +{ + codegen_addlong(block, OPCODE_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); +} + +void host_arm64_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg) +{ + codegen_addlong(block, OPCODE_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); +} + +void host_arm64_MOV_REG_ASR(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_ASR | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + if (dst_reg != src_m_reg || shift) + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_LSR | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_MOV_REG_ROR(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_ROR | Rd(dst_reg) | Rn(REG_WZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOVX_IMM(codeblock_t *block, int reg, uint64_t imm_data) +{ + codegen_addlong(block, OPCODE_MOVZ_X | MOV_WIDE_HW(0) | IMM16(imm_data & 0xffff) | Rd(reg)); + if ((imm_data >> 16) & 0xffff) + codegen_addlong(block, OPCODE_MOVK_X | MOV_WIDE_HW(1) | IMM16((imm_data >> 16) & 0xffff) | Rd(reg)); + if ((imm_data >> 32) & 0xffff) + codegen_addlong(block, OPCODE_MOVK_X | MOV_WIDE_HW(2) | IMM16((imm_data >> 32) & 0xffff) | Rd(reg)); + if ((imm_data >> 48) & 0xffff) + codegen_addlong(block, OPCODE_MOVK_X | MOV_WIDE_HW(3) | IMM16((imm_data >> 48) & 0xffff) | Rd(reg)); +} +void host_arm64_MOVX_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift) +{ + if (dst_reg != src_m_reg) + codegen_addlong(block, OPCODE_ORRX_LSL | Rd(dst_reg) | Rn(REG_XZR) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} + +void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + int hw; + + if (!imm_is_imm16(imm_data)) + fatal("MOVZ_IMM - imm not representable %08x\n", imm_data); + + hw = (imm_data & 0xffff0000) ? 1 : 0; + if (hw) + imm_data >>= 16; + + codegen_addlong(block, OPCODE_MOVZ_W | MOV_WIDE_HW(hw) | IMM16(imm_data) | Rd(reg)); +} + +void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + int hw; + + if (!imm_is_imm16(imm_data)) + fatal("MOVK_IMM - imm not representable %08x\n", imm_data); + + hw = (imm_data & 0xffff0000) ? 1 : 0; + if (hw) + imm_data >>= 16; + + codegen_addlong(block, OPCODE_MOVK_W | MOV_WIDE_HW(hw) | IMM16(imm_data) | Rd(reg)); +} + +void host_arm64_MSR_FPCR(codeblock_t *block, int src_reg) +{ + codegen_addlong(block, OPCODE_MSR_FPCR | Rd(src_reg)); +} + +void host_arm64_MUL_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_MUL_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_NOP(codeblock_t *block) +{ + codegen_addlong(block, OPCODE_NOP); +} + +void host_arm64_ORR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + uint32_t imm_encoding = host_arm64_find_imm(imm_data); + + if (imm_encoding) + { + codegen_addlong(block, OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM_LOGICAL(imm_encoding)); + } + else + { + host_arm64_mov_imm(block, REG_W16, imm_data); + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_ORR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_ORR_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_ORR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ORR_V | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_RET(codeblock_t *block, int reg) +{ + codegen_addlong(block, OPCODE_RET | Rn(reg)); +} + +void host_arm64_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg) +{ + codegen_addlong(block, OPCODE_ROR | Rd(dst_reg) | Rn(src_n_reg) | Rm(shift_reg)); +} + +void host_arm64_SADDLP_V2S_4H(codeblock_t *block, int dst_reg, int src_n_reg) +{ + codegen_addlong(block, OPCODE_SADDLP_V2S_4H | Rd(dst_reg) | Rn(src_n_reg)); +} + +void host_arm64_SBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_SBFX | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR(lsb) | IMMS((lsb+width-1) & 31)); +} + +void host_arm64_SCVTF_D_Q(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SCVTF_D_Q | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_SCVTF_D_W(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SCVTF_D_W | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_SCVTF_V2S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SCVTF_V2S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_SHRN_V4H_4S(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 16) + fatal("host_arm64_SHRN_V4H_4S : shift > 16\n"); + codegen_addlong(block, OPCODE_SHRN | Rd(dst_reg) | Rn(src_n_reg) | SHRN_SHIFT_IMM_V4S(16-shift)); +} + +void host_arm64_SMULL_V4S_4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SMULL_V4S_4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_SQADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SQADD_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SQADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SQADD_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SQSUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SQSUB_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SQSUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SQSUB_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_SQXTN_V8B_8H(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SQXTN_V8B_8H | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_SQXTN_V4H_4S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_SQXTN_V4H_4S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_SHL_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + codegen_addlong(block, OPCODE_SHL_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V4H(shift)); +} +void host_arm64_SHL_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + codegen_addlong(block, OPCODE_SHL_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2S(shift)); +} +void host_arm64_SHL_V2D(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + codegen_addlong(block, OPCODE_SHL_VQ | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2D(shift)); +} + +void host_arm64_SSHR_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 16) + fatal("host_arm_USHR_V4H : shift > 16\n"); + codegen_addlong(block, OPCODE_SSHR_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V4H(16-shift)); +} +void host_arm64_SSHR_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 32) + fatal("host_arm_SSHR_V2S : shift > 32\n"); + codegen_addlong(block, OPCODE_SSHR_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2S(32-shift)); +} +void host_arm64_SSHR_V2D(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 64) + fatal("host_arm_SSHR_V2D : shift > 64\n"); + codegen_addlong(block, OPCODE_SSHR_VQ | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2D(64-shift)); +} + +void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset) +{ + if (!in_range7_x(offset)) + fatal("host_arm64_STP_PREIDX out of range7 %i\n", offset); + codegen_addlong(block, OPCODE_STP_PREIDX_X | IMM7_X(offset) | Rn(base_reg) | Rt(src_reg1) | Rt2(src_reg2)); +} + +void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_w(offset)) + fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STR_IMM_W | OFFSET12_W(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_q(offset)) + fatal("host_arm64_STR_IMM_W out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STR_IMM_Q | OFFSET12_Q(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STR_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_STR_REG_F32(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG_F32 | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} +void host_arm64_STR_IMM_F64(codeblock_t *block, int src_reg, int base_reg, int offset) +{ + codegen_addlong(block, OPCODE_STR_IMM_F64 | OFFSET12_Q(offset) | Rn(base_reg) | Rt(src_reg)); +} +void host_arm64_STR_REG_F64(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG_F64 | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} +void host_arm64_STR_REG_F64_S(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STR_REG_F64_S | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_b(offset)) + fatal("host_arm64_STRB_IMM out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STRB_IMM | OFFSET12_B(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STRB_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STRB_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_STRH_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if (!in_range12_h(offset)) + fatal("host_arm64_STRH_IMM out of range12 %i\n", offset); + codegen_addlong(block, OPCODE_STRH_IMM | OFFSET12_H(offset) | Rn(base_reg) | Rt(dest_reg)); +} +void host_arm64_STRH_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg) +{ + codegen_addlong(block, OPCODE_STRH_REG | Rn(base_reg) | Rm(offset_reg) | Rt(src_reg)); +} + +void host_arm64_SUB_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data) +{ + if (!imm_data) + host_arm64_MOV_REG(block, dst_reg, src_n_reg, 0); + else if ((int32_t)imm_data < 0 && imm_data != 0x80000000) + { + host_arm64_ADD_IMM(block, dst_reg, src_n_reg, -(int32_t)imm_data); + } + else if (!(imm_data & 0xff000000)) + { + if (imm_data & 0xfff) + { + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12(imm_data & 0xfff) | DATPROC_IMM_SHIFT(0)); + if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(dst_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else if (imm_data & 0xfff000) + codegen_addlong(block, OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_n_reg) | IMM12((imm_data >> 12) & 0xfff) | DATPROC_IMM_SHIFT(1)); + } + else + { + host_arm64_MOVZ_IMM(block, REG_W16, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, REG_W16, imm_data & 0xffff0000); + codegen_addlong(block, OPCODE_SUB_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(REG_W16) | DATPROC_SHIFT(0)); + } +} +void host_arm64_SUB_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_SUB_LSL | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift) +{ + codegen_addlong(block, OPCODE_SUB_LSR | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg) | DATPROC_SHIFT(shift)); +} +void host_arm64_SUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SUB_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SUB_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_SUB_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_SUB_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +uint32_t *host_arm64_TBNZ(codeblock_t *block, int reg, int bit) +{ + codegen_alloc(block, 12); + codegen_addlong(block, OPCODE_TBZ | Rt(reg) | BIT_TBxZ(bit) | OFFSET14(8)); + codegen_addlong(block, OPCODE_B); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_arm64_UBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_UBFX | Rd(dst_reg) | Rn(src_reg) | IMMN(0) | IMMR(lsb) | IMMS((lsb+width-1) & 31)); +} + +void host_arm64_UQADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_UQADD_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_UQADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_UQADD_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_UQSUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_UQSUB_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_UQSUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_UQSUB_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_UQXTN_V8B_8H(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_UQXTN_V8B_8H | Rd(dst_reg) | Rn(src_reg)); +} +void host_arm64_UQXTN_V4H_4S(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_UQXTN_V4H_4S | Rd(dst_reg) | Rn(src_reg)); +} + +void host_arm64_USHR_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 16) + fatal("host_arm_USHR_V4H : shift > 16\n"); + codegen_addlong(block, OPCODE_USHR_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V4H(16-shift)); +} +void host_arm64_USHR_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 32) + fatal("host_arm_USHR_V4S : shift > 32\n"); + codegen_addlong(block, OPCODE_USHR_VD | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2S(32-shift)); +} +void host_arm64_USHR_V2D(codeblock_t *block, int dst_reg, int src_n_reg, int shift) +{ + if (shift > 64) + fatal("host_arm_USHR_V2D : shift > 64\n"); + codegen_addlong(block, OPCODE_USHR_VQ | Rd(dst_reg) | Rn(src_n_reg) | SHIFT_IMM_V2D(64-shift)); +} + +void host_arm64_ZIP1_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP1_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP1_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP1_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP1_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP1_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP2_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP2_V8B | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP2_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP2_V4H | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} +void host_arm64_ZIP2_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg) +{ + codegen_addlong(block, OPCODE_ZIP2_V2S | Rd(dst_reg) | Rn(src_n_reg) | Rm(src_m_reg)); +} + +void host_arm64_call(codeblock_t *block, void *dst_addr) +{ + host_arm64_MOVX_IMM(block, REG_X16, (uint64_t)dst_addr); + host_arm64_BLR(block, REG_X16); +} + +void host_arm64_jump(codeblock_t *block, uintptr_t dst_addr) +{ + host_arm64_MOVX_IMM(block, REG_X16, (uint64_t)dst_addr); + host_arm64_BR(block, REG_X16); +} + +void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data) +{ + if (imm_is_imm16(imm_data)) + host_arm64_MOVZ_IMM(block, reg, imm_data); + else + { + host_arm64_MOVZ_IMM(block, reg, imm_data & 0xffff); + host_arm64_MOVK_IMM(block, reg, imm_data & 0xffff0000); + } +} + +#endif diff --git a/src/codegen_backend_arm64_ops.h b/src/codegen_backend_arm64_ops.h new file mode 100644 index 0000000..2a514ed --- /dev/null +++ b/src/codegen_backend_arm64_ops.h @@ -0,0 +1,264 @@ +void host_arm64_ADD_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_ADD_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_ADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ADD_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ADDX_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint64_t imm_data); + +void host_arm64_ADDP_V4S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_ADR(codeblock_t *block, int dst_reg, int offset); + +void host_arm64_AND_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_AND_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_AND_REG_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_AND_REG_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_AND_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_ANDS_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); + +void host_arm64_ASR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); + +void host_arm64_B(codeblock_t *block, void *dest); + +void host_arm64_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm64_BLR(codeblock_t *block, int addr_reg); + +void host_arm64_BEQ(codeblock_t *block, void *dest); + +uint32_t *host_arm64_BCC_(codeblock_t *block); +uint32_t *host_arm64_BCS_(codeblock_t *block); +uint32_t *host_arm64_BEQ_(codeblock_t *block); +uint32_t *host_arm64_BGE_(codeblock_t *block); +uint32_t *host_arm64_BGT_(codeblock_t *block); +uint32_t *host_arm64_BHI_(codeblock_t *block); +uint32_t *host_arm64_BLE_(codeblock_t *block); +uint32_t *host_arm64_BLS_(codeblock_t *block); +uint32_t *host_arm64_BLT_(codeblock_t *block); +uint32_t *host_arm64_BMI_(codeblock_t *block); +uint32_t *host_arm64_BNE_(codeblock_t *block); +uint32_t *host_arm64_BPL_(codeblock_t *block); +uint32_t *host_arm64_BVC_(codeblock_t *block); +uint32_t *host_arm64_BVS_(codeblock_t *block); + +void host_arm64_branch_set_offset(uint32_t *opcode, void *dest); + +void host_arm64_BR(codeblock_t *block, int addr_reg); + +void host_arm64_BIC_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_CBNZ(codeblock_t *block, int reg, uintptr_t dest); + +void host_arm64_CMEQ_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMEQ_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMEQ_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMGT_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMGT_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CMGT_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_CMN_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data); +void host_arm64_CMNX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data); + +void host_arm64_CMP_IMM(codeblock_t *block, int src_n_reg, uint32_t imm_data); +void host_arm64_CMPX_IMM(codeblock_t *block, int src_n_reg, uint64_t imm_data); + +#define host_arm64_CMP_REG(block, src_n_reg, src_m_reg) host_arm64_CMP_REG_LSL(block, src_n_reg, src_m_reg, 0) +void host_arm64_CMP_REG_LSL(codeblock_t *block, int src_n_reg, int src_m_reg, int shift); + +void host_arm64_CSEL_CC(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CSEL_EQ(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_CSEL_VS(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_DUP_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int element); + +void host_arm64_EOR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_EOR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_EOR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_FABS_D(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FADD_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FADD_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FCMEQ_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FCMGE_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FCMGT_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FCMP_D(codeblock_t *block, int src_n_reg, int src_m_reg); +void host_arm64_FDIV_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FDIV_S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMAX_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMIN_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMUL_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FMUL_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FSUB_D(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_FSUB_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_FCVT_D_S(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVT_S_D(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FCVTMS_W_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTMS_X_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTNS_W_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTNS_X_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTPS_W_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTPS_X_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTZS_W_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTZS_X_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FCVTZS_V2S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FMOV_D_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_D_Q(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_Q_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_S_W(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_W_S(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FMOV_S_ONE(codeblock_t *block, int dst_reg); + +void host_arm64_FNEG_D(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FRINTX_D(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_FSQRT_D(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_FSQRT_S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_LDP_POSTIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); + +void host_arm64_LDR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDR_IMM_X(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDR_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); +void host_arm64_LDR_REG_X(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDR_REG_F32(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); +void host_arm64_LDR_IMM_F64(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDR_REG_F64(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); +void host_arm64_LDR_REG_F64_S(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRB_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDRB_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRH_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_LDRH_REG(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LDRX_REG_LSL3(codeblock_t *block, int dest_reg, int base_reg, int offset_reg); + +void host_arm64_LSL(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); +void host_arm64_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); + +void host_arm64_MOV_REG_ASR(codeblock_t *block, int dst_reg, int src_m_reg, int shift); +void host_arm64_MOV_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift); +void host_arm64_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_m_reg, int shift); +void host_arm64_MOV_REG_ROR(codeblock_t *block, int dst_reg, int src_m_reg, int shift); + +void host_arm64_MOVX_IMM(codeblock_t *block, int reg, uint64_t imm_data); +void host_arm64_MOVX_REG(codeblock_t *block, int dst_reg, int src_m_reg, int shift); + +void host_arm64_MOVZ_IMM(codeblock_t *block, int reg, uint32_t imm_data); +void host_arm64_MOVK_IMM(codeblock_t *block, int reg, uint32_t imm_data); + +void host_arm64_MSR_FPCR(codeblock_t *block, int src_reg); + +void host_arm64_MUL_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_NOP(codeblock_t *block); + +void host_arm64_ORR_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_ORR_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_ORR_REG_V(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_RET(codeblock_t *block, int reg); + +void host_arm64_ROR(codeblock_t *block, int dst_reg, int src_n_reg, int shift_reg); + +void host_arm64_SADDLP_V2S_4H(codeblock_t *block, int dst_reg, int src_n_reg); + +void host_arm64_SBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm64_SCVTF_D_Q(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_SCVTF_D_W(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_SCVTF_V2S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_SQADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SQADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SQSUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SQSUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_SQXTN_V8B_8H(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_SQXTN_V4H_4S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_SHL_V4H(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_SHL_V2S(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_SHL_V2D(codeblock_t *block, int dst_reg, int src_reg, int shift); + +void host_arm64_SHRN_V4H_4S(codeblock_t *block, int dst_reg, int src_n_reg, int shift); + +void host_arm64_SMULL_V4S_4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_SSHR_V4H(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_SSHR_V2S(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_SSHR_V2D(codeblock_t *block, int dst_reg, int src_reg, int shift); + +void host_arm64_STP_PREIDX_X(codeblock_t *block, int src_reg1, int src_reg2, int base_reg, int offset); + +void host_arm64_STR_IMM_W(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STR_IMM_Q(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STR_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_STR_REG_F32(codeblock_t *block, int src_reg, int base_reg, int offset_reg); +void host_arm64_STR_IMM_F64(codeblock_t *block, int src_reg, int base_reg, int offset); +void host_arm64_STR_REG_F64(codeblock_t *block, int src_reg, int base_reg, int offset_reg); +void host_arm64_STR_REG_F64_S(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_STRB_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STRB_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_STRH_IMM(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm64_STRH_REG(codeblock_t *block, int src_reg, int base_reg, int offset_reg); + +void host_arm64_SUB_IMM(codeblock_t *block, int dst_reg, int src_n_reg, uint32_t imm_data); +void host_arm64_SUB_REG(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg, int shift); +void host_arm64_SUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_SUB_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +uint32_t *host_arm64_TBNZ(codeblock_t *block, int reg, int bit); + +#define host_arm64_TST_IMM(block, src_n_reg, imm_data) host_arm64_ANDS_IMM(block, REG_XZR, src_n_reg, imm_data) + +void host_arm64_UBFX(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm64_UQADD_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_UQADD_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_UQSUB_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_UQSUB_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_UQXTN_V8B_8H(codeblock_t *block, int dst_reg, int src_reg); +void host_arm64_UQXTN_V4H_4S(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm64_USHR_V4H(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_USHR_V2S(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm64_USHR_V2D(codeblock_t *block, int dst_reg, int src_reg, int shift); + +void host_arm64_ZIP1_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP1_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP1_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP2_V8B(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP2_V4H(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); +void host_arm64_ZIP2_V2S(codeblock_t *block, int dst_reg, int src_n_reg, int src_m_reg); + +void host_arm64_call(codeblock_t *block, void *dst_addr); +void host_arm64_jump(codeblock_t *block, uintptr_t dst_addr); +void host_arm64_mov_imm(codeblock_t *block, int reg, uint32_t imm_data); + + +#define in_range7_x(offset) (((offset) >= -0x200) && ((offset) < (0x200)) && !((offset) & 7)) +#define in_range12_b(offset) (((offset) >= 0) && ((offset) < 0x1000)) +#define in_range12_h(offset) (((offset) >= 0) && ((offset) < 0x2000) && !((offset) & 1)) +#define in_range12_w(offset) (((offset) >= 0) && ((offset) < 0x4000) && !((offset) & 3)) +#define in_range12_q(offset) (((offset) >= 0) && ((offset) < 0x8000) && !((offset) & 7)) + + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p); + +void codegen_alloc(codeblock_t *block, int size); \ No newline at end of file diff --git a/src/codegen_backend_arm64_uops.c b/src/codegen_backend_arm64_uops.c new file mode 100644 index 0000000..73623f0 --- /dev/null +++ b/src/codegen_backend_arm64_uops.c @@ -0,0 +1,3368 @@ +#ifdef __aarch64__ + +#include "ibm.h" +#include "x86.h" +#include "x87.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_backend_arm64_defs.h" +#include "codegen_backend_arm64_ops.h" +#include "codegen_ir_defs.h" + +#define OFFSET19(offset) (((offset >> 2) << 5) & 0x00ffffe0) + +#define HOST_REG_GET(reg) (IREG_GET_REG(reg) & 0x1f) + +#define REG_IS_L(size) (size == IREG_SIZE_L) +#define REG_IS_W(size) (size == IREG_SIZE_W) +#define REG_IS_B(size) (size == IREG_SIZE_B) +#define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) +#define REG_IS_Q(size) (size == IREG_SIZE_Q) + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_ADD_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_ADD_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_ADD_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_ADD_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_ADD_REG_LSR(block, REG_TEMP, src_reg_b, src_reg_a, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_a, 0x0000ff00); + host_arm64_ADD_REG(block, REG_TEMP, REG_TEMP, src_reg_b, 0); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_ADD_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ADD_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + host_arm64_ADD_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); + return 0; +} + +static int codegen_AND(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_AND_REG_V(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_AND_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffff0000); + host_arm64_AND_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffffff00); + host_arm64_AND_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffff00ff); + host_arm64_AND_REG_ASR(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffffff00); + host_arm64_AND_REG_ROR(block, dest_reg, src_reg_a, REG_TEMP, 24); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffff00ff); + host_arm64_AND_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_AND_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_AND_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_b, 0xffff00ff); + host_arm64_AND_REG_ROR(block, REG_TEMP, src_reg_a, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_ORR_IMM(block, REG_TEMP, src_reg_a, 0xffff00ff); + host_arm64_AND_REG_ROR(block, REG_TEMP, src_reg_b, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_AND_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("AND %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, uop->imm_data | 0xffff0000); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, uop->imm_data | 0xffffff00); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, (uop->imm_data << 8) | 0xffff00ff); + } + else + fatal("AND_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_ANDN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_BIC_REG_V(block, dest_reg, src_reg_b, src_reg_a); + } + else + fatal("ANDN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) +{ + host_arm64_call(block, uop->p); + + return 0; +} + +static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_L(dest_size)) + fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); + host_arm64_call(block, uop->p); + host_arm64_MOV_REG(block, dest_reg, REG_W0, 0); + + return 0; +} + +static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) +{ + host_arm64_call(block, uop->p); + host_arm64_CBNZ(block, REG_X0, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_CMP_IMM(block, src_reg, uop->imm_data); + } + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); + host_arm64_BEQ(block, uop->p); + + return 0; +} + +static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_CMP_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff); + host_arm64_CMP_IMM(block, REG_TEMP, uop->imm_data); + } + else + fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BNE_(block); + + return 0; +} +static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_CMP_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff); + host_arm64_CMP_IMM(block, REG_TEMP, uop->imm_data); + } + else + fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BEQ_(block); + + return 0; +} + +static int codegen_CMP_JB(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else + fatal("CMP_JB %02x\n", uop->src_reg_a_real); + + jump_p = host_arm64_BCC_(block); + host_arm64_branch_set_offset(jump_p, uop->p); + + return 0; +} +static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else + fatal("CMP_JNBE %02x\n", uop->src_reg_a_real); + + jump_p = host_arm64_BHI_(block); + host_arm64_branch_set_offset(jump_p, uop->p); + + return 0; +} + +static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BCS_(block); + + return 0; +} +static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BHI_(block); + + return 0; +} +static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BGE_(block); + + return 0; +} +static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BGT_(block); + + return 0; +} +static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BVC_(block); + + return 0; +} +static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BNE_(block); + + return 0; +} +static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BCC_(block); + + return 0; +} +static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BLS_(block); + + return 0; +} +static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BLT_(block); + + return 0; +} +static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BLE_(block); + + return 0; +} +static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BVS_(block); + + return 0; +} +static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 16); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg_a, 24); + host_arm64_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BEQ_(block); + + return 0; +} + +static int codegen_FABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FABS_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FCHS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FNEG_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FSQRT_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FTST(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_arm64_FSUB_D(block, REG_V_TEMP, REG_V_TEMP, REG_V_TEMP); + host_arm64_MOVZ_IMM(block, dest_reg, 0); + host_arm64_FCMP_D(block, src_reg_a, REG_V_TEMP); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C3); + host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, C0); + host_arm64_CSEL_EQ(block, dest_reg, REG_TEMP, dest_reg); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C0|C2|C3); + host_arm64_CSEL_CC(block, dest_reg, REG_TEMP2, dest_reg); + host_arm64_CSEL_VS(block, dest_reg, REG_TEMP, dest_reg); + } + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FADD_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FCOM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_MOVZ_IMM(block, dest_reg, 0); + host_arm64_FCMP_D(block, src_reg_a, src_reg_b); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C3); + host_arm64_ORR_IMM(block, REG_TEMP2, dest_reg, C0); + host_arm64_CSEL_EQ(block, dest_reg, REG_TEMP, dest_reg); + host_arm64_ORR_IMM(block, REG_TEMP, dest_reg, C0|C2|C3); + host_arm64_CSEL_CC(block, dest_reg, REG_TEMP2, dest_reg); + host_arm64_CSEL_VS(block, dest_reg, REG_TEMP, dest_reg); + } + else + fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FDIV_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FMUL_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm64_FSUB_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range12_w((uintptr_t)&cr0 - (uintptr_t)&cpu_state)) + fatal("codegen_FP_ENTER - out of range\n"); + + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm64_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm64_BEQ_(block); + + host_arm64_mov_imm(block, REG_TEMP, uop->imm_data); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm64_mov_imm(block, REG_ARG0, 7); + host_arm64_call(block, x86_int); + host_arm64_B(block, codegen_exit_rout); + + host_arm64_branch_set_offset(branch_ptr, &block_write_data[block_pos]); + + return 0; +} +static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range12_w((uintptr_t)&cr0 - (uintptr_t)&cpu_state)) + fatal("codegen_MMX_ENTER - out of range\n"); + + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm64_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm64_BEQ_(block); + + host_arm64_mov_imm(block, REG_TEMP, uop->imm_data); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm64_mov_imm(block, REG_ARG0, 7); + host_arm64_call(block, x86_int); + host_arm64_B(block, codegen_exit_rout); + + host_arm64_branch_set_offset(branch_ptr, &block->data[block_pos]); + + host_arm64_mov_imm(block, REG_TEMP, 0x01010101); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[0] - (uintptr_t)&cpu_state); + host_arm64_STR_IMM_W(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[4] - (uintptr_t)&cpu_state); + host_arm64_STR_IMM_W(block, REG_WZR, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm64_STRB_IMM(block, REG_WZR, REG_CPUSTATE, (uintptr_t)&cpu_state.ismmx - (uintptr_t)&cpu_state); + + return 0; +} + +static int codegen_JMP(codeblock_t *block, uop_t *uop) +{ + host_arm64_jump(block, (uintptr_t)uop->p); + + return 0; +} + +static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_ARG0, src_reg, 0xffff); + } + else + fatal("codegen_LOAD_FUNC_ARG0 %02x\n", uop->src_reg_a_real); + + return 0; +} +static int codegen_LOAD_FUNC_ARG1(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG1 %02x\n", uop->src_reg_a_real); + return 0; +} +static int codegen_LOAD_FUNC_ARG2(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG2 %02x\n", uop->src_reg_a_real); + return 0; +} +static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG3 %02x\n", uop->src_reg_a_real); + return 0; +} + +static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_ARG0, uop->imm_data); + + return 0; +} +static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_ARG1, uop->imm_data); + + return 0; +} +static int codegen_LOAD_FUNC_ARG2_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_ARG2, uop->imm_data); + + return 0; +} +static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_ARG3, uop->imm_data); + + return 0; +} + +static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (!REG_IS_W(src_size)) + fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); + + host_arm64_MOVX_IMM(block, REG_ARG1, (uint64_t)uop->p); + host_arm64_AND_IMM(block, REG_ARG0, src_reg, 0xffff); + host_arm64_call(block, (void *)loadseg); + host_arm64_CBNZ(block, REG_X0, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_ADD_IMM(block, REG_X0, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm64_call(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_call(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_call(block, codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_MOV_REG(block, dest_reg, REG_X0, 0); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm64_call(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_call(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_call(block, codegen_mem_load_long); + } + else if (REG_IS_Q(dest_size)) + { + host_arm64_call(block, codegen_mem_load_quad); + } + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_BFI(block, dest_reg, REG_X0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm64_MOV_REG(block, dest_reg, REG_X0, 0); + } + else if (REG_IS_Q(dest_size)) + { + host_arm64_FMOV_D_D(block, dest_reg, REG_V_TEMP); + } + + return 0; +} +static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + host_arm64_call(block, codegen_mem_load_double); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + host_arm64_FMOV_D_D(block, dest_reg, REG_V_TEMP); + + return 0; +} +static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_X0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + host_arm64_call(block, codegen_mem_load_single); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + host_arm64_FCVT_D_S(block, dest_reg, REG_V_TEMP); + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_arm64_ADD_IMM(block, REG_W0, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xff); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_W1, src_reg, 8, 8); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xffff); + host_arm64_call(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, REG_W1, src_reg, 0); + host_arm64_call(block, codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->dest_reg_a_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xff); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_W1, src_reg, 8, 8); + host_arm64_call(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_W1, src_reg, 0xffff); + host_arm64_call(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, REG_W1, src_reg, 0); + host_arm64_call(block, codegen_mem_store_long); + } + else if (REG_IS_Q(src_size)) + { + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_mem_store_quad); + } + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_c_real); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_byte); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_word); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + host_arm64_mov_imm(block, REG_W1, uop->imm_data); + host_arm64_call(block, codegen_mem_store_long); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + host_arm64_FCVT_S_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_mem_store_single); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + + host_arm64_ADD_REG(block, REG_W0, seg_reg, addr_reg, 0); + if (uop->imm_data) + host_arm64_ADD_IMM(block, REG_X0, REG_X0, uop->imm_data); + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_mem_store_double); + host_arm64_CBNZ(block, REG_X1, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, dest_reg, src_reg, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_BFI(block, dest_reg, src_reg, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_BFI(block, dest_reg, src_reg, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_B(src_size)) + { + host_arm64_BFI(block, dest_reg, src_reg, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size)) + { + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + } + else + fatal("MOV %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_arm64_mov_imm(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_MOVK_IMM(block, dest_reg, uop->imm_data & 0xffff); + } + else if (REG_IS_B(dest_size)) + { + host_arm64_MOVZ_IMM(block, REG_TEMP, uop->imm_data & 0xff); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm64_MOVZ_IMM(block, REG_TEMP, uop->imm_data & 0xff); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("MOV_IMM %x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_arm64_MOVX_IMM(block, uop->dest_reg_a_real, (uint64_t)uop->p); + + return 0; +} + +static int codegen_MOVSX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_arm64_SBFX(block, dest_reg, src_reg, 0, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_SBFX(block, dest_reg, src_reg, 8, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_arm64_SBFX(block, dest_reg, src_reg, 0, 16); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_arm64_SBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_W(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_SBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVSX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOVZX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_L(src_size)) + { + host_arm64_FMOV_D_Q(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_Q(src_size)) + { + host_arm64_FMOV_W_S(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, 0xff); + } + else if (REG_IS_L(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, dest_reg, src_reg, 8, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, dest_reg, src_reg, 0xffff); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xff); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_W(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVZX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_MOV_DOUBLE_INT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_L(src_size)) + { + host_arm64_SCVTF_D_W(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_W(src_size)) + { + host_arm64_SBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_SCVTF_D_W(block, dest_reg, REG_TEMP); + } + else if (REG_IS_D(dest_size) && REG_IS_Q(src_size)) + { + host_arm64_FMOV_Q_D(block, REG_TEMP, src_reg); + host_arm64_SCVTF_D_Q(block, dest_reg, REG_TEMP); + } + else + fatal("MOV_DOUBLE_INT %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_D(src_size)) + { + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_fp_round); + host_arm64_MOV_REG(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_D(src_size)) + { + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_fp_round); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOV_INT_DOUBLE %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), src_64_reg = HOST_REG_GET(uop->src_reg_b_real), tag_reg = HOST_REG_GET(uop->src_reg_c_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real), src_64_size = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_D(src_size) && REG_IS_Q(src_64_size)) + { + uint32_t *branch_offset; + + /*If TAG_UINT64 is set then the source is MM[]. Otherwise it is a double in ST()*/ + host_arm64_FMOV_D_D(block, dest_reg, src_64_reg); + branch_offset = host_arm64_TBNZ(block, tag_reg, 7); + + host_arm64_FMOV_D_D(block, REG_V_TEMP, src_reg); + host_arm64_call(block, codegen_fp_round_quad); + host_arm64_FMOV_D_Q(block, dest_reg, REG_TEMP); + + host_arm64_branch_set_offset(branch_offset, &block_write_data[block_pos]); + } + else + fatal("MOV_INT_DOUBLE_64 %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_MOVX_IMM(block, REG_TEMP, (uint64_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm64_LDR_IMM_W(block, dest_reg, REG_TEMP, 0); + } + else + fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_MOVX_IMM(block, REG_TEMP, (uint64_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm64_LDRB_IMM_W(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_LDRB_IMM_W(block, REG_TEMP, REG_TEMP, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size)) + { + host_arm64_LDRB_IMM_W(block, REG_TEMP, REG_TEMP, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("MOVZX_REG_PTR_8 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_16(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm64_MOVX_IMM(block, REG_TEMP, (uint64_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm64_LDRH_IMM(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size)) + { + host_arm64_LDRH_IMM(block, REG_TEMP, REG_TEMP, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVZX_REG_PTR_16 %02x\n", uop->dest_reg_a_real); + + return 0; +} + +static int codegen_NOP(codeblock_t *block, uop_t *uop) +{ + return 0; +} + +static int codegen_OR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ORR_REG_V(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_ORR_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_ORR_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xff); + host_arm64_ORR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_UBFX(block, REG_TEMP, src_reg_b, 8, 8); + host_arm64_ORR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xff); + host_arm64_ORR_REG(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_UBFX(block, REG_TEMP, src_reg_b, 8, 8); + host_arm64_ORR_REG(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else + fatal("OR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm64_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm64_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm64_ORR_IMM(block, dest_reg, src_reg, uop->imm_data << 8); + } + else + fatal("OR_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_PACKSSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_arm64_SQXTN_V8B_8H(block, REG_V_TEMP, src_reg_b); + host_arm64_SQXTN_V8B_8H(block, dest_reg, dest_reg); + host_arm64_ZIP1_V2S(block, dest_reg, dest_reg, REG_V_TEMP); + } + else + fatal("PACKSSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PACKSSDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_arm64_SQXTN_V4H_4S(block, REG_V_TEMP, src_reg_b); + host_arm64_SQXTN_V4H_4S(block, dest_reg, dest_reg); + host_arm64_ZIP1_V2S(block, dest_reg, dest_reg, REG_V_TEMP); + } + else + fatal("PACKSSDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PACKUSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_arm64_UQXTN_V8B_8H(block, REG_V_TEMP, src_reg_b); + host_arm64_UQXTN_V8B_8H(block, dest_reg, dest_reg); + host_arm64_ZIP1_V2S(block, dest_reg, dest_reg, REG_V_TEMP); + } + else + fatal("PACKUSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PADDB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ADD_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ADD_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ADD_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SQADD_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SQADD_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_UQADD_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_UQADD_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PCMPEQB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMEQ_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPEQW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMEQ_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPEQD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMEQ_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMGT_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMGT_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_CMGT_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PF2ID(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_arm64_FCVTZS_V2S(block, dest_reg, src_reg_a); + } + else + fatal("PF2ID %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FADD_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPEQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FCMEQ_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPEQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPGE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FCMGE_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPGE %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPGT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FCMGT_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPGT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMAX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FMAX_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMAX %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMIN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FMIN_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMIN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FMUL_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFRCP(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use VRECPE/VRECPS)*/ + host_arm64_FMOV_S_ONE(block, REG_V_TEMP); + host_arm64_FDIV_S(block, dest_reg, REG_V_TEMP, src_reg_a); + host_arm64_DUP_V2S(block, dest_reg, dest_reg, 0); + } + else + fatal("PFRCP %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFRSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use VRSQRTE/VRSQRTS)*/ + host_arm64_FSQRT_S(block, REG_V_TEMP, src_reg_a); + host_arm64_FMOV_S_ONE(block, REG_V_TEMP); + host_arm64_FDIV_S(block, dest_reg, dest_reg, REG_V_TEMP); + host_arm64_DUP_V2S(block, dest_reg, dest_reg, 0); + } + else + fatal("PFRSQRT %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_FSUB_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PI2FD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_arm64_SCVTF_V2S(block, dest_reg, src_reg_a); + } + else + fatal("PI2FD %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} + +static int codegen_PMADDWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SMULL_V4S_4H(block, REG_V_TEMP, src_reg_a, src_reg_b); + host_arm64_ADDP_V4S(block, dest_reg, REG_V_TEMP, REG_V_TEMP); + } + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PMULHW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SMULL_V4S_4H(block, dest_reg, src_reg_a, src_reg_b); + host_arm64_SHRN_V4H_4S(block, dest_reg, dest_reg, 16); + } + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PMULLW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_MUL_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PMULLW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PSLLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_SHL_V4H(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSLLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_SHL_V2S(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSLLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_SHL_V2D(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm64_SSHR_V4H(block, dest_reg, src_reg, 15); + else + host_arm64_SSHR_V4H(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm64_SSHR_V2S(block, dest_reg, src_reg, 31); + else + host_arm64_SSHR_V2S(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm64_SSHR_V2D(block, dest_reg, src_reg, 63); + else + host_arm64_SSHR_V2D(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_USHR_V4H(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_USHR_V2S(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm64_FMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm64_EOR_REG_V(block, dest_reg, dest_reg, dest_reg); + else + host_arm64_USHR_V2D(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_PSUBB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SUB_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SUB_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SUB_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SQSUB_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_SQSUB_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_UQSUB_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_UQSUB_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PUNPCKHBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP2_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKHBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKHWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP2_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKHWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKHDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP2_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKHDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP1_V8B(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKLBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP1_V4H(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKLWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_ZIP1_V2S(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PUNPCKLDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_ROL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_mov_imm(block, REG_TEMP2, 32); + host_arm64_SUB_REG(block, REG_TEMP2, REG_TEMP2, shift_reg, 0); + host_arm64_ROR(block, dest_reg, src_reg, REG_TEMP2); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_mov_imm(block, REG_TEMP2, 16); + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_SUB_REG(block, REG_TEMP2, REG_TEMP2, shift_reg, 0); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm64_ROR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + cs = cs; + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_mov_imm(block, REG_TEMP2, 8); + host_arm64_SUB_REG(block, REG_TEMP2, REG_TEMP2, shift_reg, 0); + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_AND_IMM(block, REG_TEMP2, REG_TEMP2, 7); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_mov_imm(block, REG_TEMP2, 8); + host_arm64_SUB_REG(block, REG_TEMP2, REG_TEMP2, shift_reg, 0); + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_AND_IMM(block, REG_TEMP2, REG_TEMP2, 7); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ROL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (!(uop->imm_data & 31)) + { + if (src_reg != dest_reg) + host_arm64_MOV_REG(block, dest_reg, src_reg, 0); + } + else + { + host_arm64_MOV_REG_ROR(block, dest_reg, src_reg, 32 - (uop->imm_data & 31)); + } + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if ((uop->imm_data & 15) == 0) + { + if (src_reg != dest_reg) + host_arm64_BFI(block, dest_reg, src_reg, 0, 16); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 16-(uop->imm_data & 15)); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + host_arm64_BFI(block, dest_reg, src_reg, 0, 8); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8-(uop->imm_data & 7)); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8-(uop->imm_data & 7)); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + } + else + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_ROR(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_AND_IMM(block, REG_TEMP2, shift_reg, 15); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_AND_IMM(block, REG_TEMP2, shift_reg, 7); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_AND_IMM(block, REG_TEMP2, shift_reg, 7); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ROR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (!(uop->imm_data & 31)) + { + if (src_reg != dest_reg) + host_arm64_MOV_REG(block, dest_reg, src_reg, 0); + } + else + { + host_arm64_MOV_REG_ROR(block, dest_reg, src_reg, uop->imm_data & 31); + } + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if ((uop->imm_data & 15) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 16); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 15); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 0, 8); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 7); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_ORR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 7); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + } + else + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_SAR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_ASR(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 16); + host_arm64_ASR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 16, 16); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 24); + host_arm64_ASR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 24, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 16); + host_arm64_ASR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 24, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SAR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SAR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_MOV_REG_ASR(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 16); + host_arm64_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 16, 16); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 24); + host_arm64_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 24, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, 16); + host_arm64_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_UBFX(block, REG_TEMP, REG_TEMP, 24, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SAR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_LSL(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_LSL(block, REG_TEMP, src_reg, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_LSL(block, REG_TEMP, src_reg, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_LSL(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_MOV_REG(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_MOV_REG(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_MOV_REG(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_LSR(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xff); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_LSR(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_MOV_REG_LSR(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xffff); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg, 0xff); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_UBFX(block, REG_TEMP, src_reg, 8, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_W16, uop->imm_data); + + if (in_range12_w((uintptr_t)uop->p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_W(block, REG_W16, REG_CPUSTATE, (uintptr_t)uop->p - (uintptr_t)&cpu_state); + else + fatal("codegen_STORE_PTR_IMM - not in range\n"); + + return 0; +} +static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) +{ + host_arm64_mov_imm(block, REG_W16, uop->imm_data); + + if (in_range12_b((uintptr_t)uop->p - (uintptr_t)&cpu_state)) + host_arm64_STRB_IMM(block, REG_W16, REG_CPUSTATE, (uintptr_t)uop->p - (uintptr_t)&cpu_state); + else + fatal("codegen_STORE_PTR_IMM - not in range\n"); + + return 0; +} + +static int codegen_SUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_SUB_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm64_SUB_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_SUB_REG(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_SUB_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_SUB_REG(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg_a, 8); + host_arm64_SUB_REG_LSR(block, REG_TEMP, REG_TEMP, src_reg_b, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm64_SUB_REG(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm64_MOV_REG_LSR(block, REG_TEMP, src_reg_a, 8); + host_arm64_SUB_REG_LSR(block, REG_TEMP, REG_TEMP, src_reg_b, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_SUB_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm64_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm64_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm64_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm64_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm64_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SUB_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 31); + } + else if (REG_IS_W(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 15); + } + else if (REG_IS_B(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 7); + } + else + fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BEQ_(block); + + return 0; +} +static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 31); + } + else if (REG_IS_W(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 15); + } + else if (REG_IS_B(src_size)) + { + host_arm64_TST_IMM(block, src_reg, 1 << 7); + } + else + fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm64_BNE_(block); + + return 0; +} + +static int codegen_XOR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm64_EOR_REG_V(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm64_EOR_REG(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xffff); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xff); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_UBFX(block, REG_TEMP, src_reg_b, 8, 8); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_AND_IMM(block, REG_TEMP, src_reg_b, 0xff); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm64_UBFX(block, REG_TEMP, src_reg_b, 8, 8); + host_arm64_EOR_REG(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else + fatal("XOR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm64_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm64_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm64_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm64_EOR_IMM(block, dest_reg, src_reg, uop->imm_data << 8); + } + else + fatal("XOR_IMM %x %x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +const uOpFn uop_handlers[UOP_MAX] = +{ + [UOP_CALL_FUNC & UOP_MASK] = codegen_CALL_FUNC, + [UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT, + [UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC, + + [UOP_JMP & UOP_MASK] = codegen_JMP, + + [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, + + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, + [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, + [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, + [UOP_LOAD_FUNC_ARG_3 & UOP_MASK] = codegen_LOAD_FUNC_ARG3, + + [UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM, + [UOP_LOAD_FUNC_ARG_1_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG1_IMM, + [UOP_LOAD_FUNC_ARG_2_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG2_IMM, + [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, + + [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, + [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, + [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, + [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, + + [UOP_MOV & UOP_MASK] = codegen_MOV, + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + [UOP_MOVSX & UOP_MASK] = codegen_MOVSX, + [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, + [UOP_MOV_DOUBLE_INT & UOP_MASK] = codegen_MOV_DOUBLE_INT, + [UOP_MOV_INT_DOUBLE & UOP_MASK] = codegen_MOV_INT_DOUBLE, + [UOP_MOV_INT_DOUBLE_64 & UOP_MASK] = codegen_MOV_INT_DOUBLE_64, + [UOP_MOV_REG_PTR & UOP_MASK] = codegen_MOV_REG_PTR, + [UOP_MOVZX_REG_PTR_8 & UOP_MASK] = codegen_MOVZX_REG_PTR_8, + [UOP_MOVZX_REG_PTR_16 & UOP_MASK] = codegen_MOVZX_REG_PTR_16, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND & UOP_MASK] = codegen_AND, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM, + [UOP_ANDN & UOP_MASK] = codegen_ANDN, + [UOP_OR & UOP_MASK] = codegen_OR, + [UOP_OR_IMM & UOP_MASK] = codegen_OR_IMM, + [UOP_SUB & UOP_MASK] = codegen_SUB, + [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, + [UOP_XOR & UOP_MASK] = codegen_XOR, + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_SAR & UOP_MASK] = codegen_SAR, + [UOP_SAR_IMM & UOP_MASK] = codegen_SAR_IMM, + [UOP_SHL & UOP_MASK] = codegen_SHL, + [UOP_SHL_IMM & UOP_MASK] = codegen_SHL_IMM, + [UOP_SHR & UOP_MASK] = codegen_SHR, + [UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM, + [UOP_ROL & UOP_MASK] = codegen_ROL, + [UOP_ROL_IMM & UOP_MASK] = codegen_ROL_IMM, + [UOP_ROR & UOP_MASK] = codegen_ROR, + [UOP_ROR_IMM & UOP_MASK] = codegen_ROR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ, + + [UOP_CMP_JB & UOP_MASK] = codegen_CMP_JB, + [UOP_CMP_JNBE & UOP_MASK] = codegen_CMP_JNBE, + + [UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST, + [UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST, + [UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST, + [UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST, + [UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST, + [UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST, + [UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST, + [UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST, + [UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST, + [UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST, + [UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST, + [UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST, + + [UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST, + [UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST, + + [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, + [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FCOM & UOP_MASK] = codegen_FCOM, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, + [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, + [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, + + [UOP_PADDB & UOP_MASK] = codegen_PADDB, + [UOP_PADDW & UOP_MASK] = codegen_PADDW, + [UOP_PADDD & UOP_MASK] = codegen_PADDD, + [UOP_PADDSB & UOP_MASK] = codegen_PADDSB, + [UOP_PADDSW & UOP_MASK] = codegen_PADDSW, + [UOP_PADDUSB & UOP_MASK] = codegen_PADDUSB, + [UOP_PADDUSW & UOP_MASK] = codegen_PADDUSW, + + [UOP_PCMPEQB & UOP_MASK] = codegen_PCMPEQB, + [UOP_PCMPEQW & UOP_MASK] = codegen_PCMPEQW, + [UOP_PCMPEQD & UOP_MASK] = codegen_PCMPEQD, + [UOP_PCMPGTB & UOP_MASK] = codegen_PCMPGTB, + [UOP_PCMPGTW & UOP_MASK] = codegen_PCMPGTW, + [UOP_PCMPGTD & UOP_MASK] = codegen_PCMPGTD, + + [UOP_PF2ID & UOP_MASK] = codegen_PF2ID, + [UOP_PFADD & UOP_MASK] = codegen_PFADD, + [UOP_PFCMPEQ & UOP_MASK] = codegen_PFCMPEQ, + [UOP_PFCMPGE & UOP_MASK] = codegen_PFCMPGE, + [UOP_PFCMPGT & UOP_MASK] = codegen_PFCMPGT, + [UOP_PFMAX & UOP_MASK] = codegen_PFMAX, + [UOP_PFMIN & UOP_MASK] = codegen_PFMIN, + [UOP_PFMUL & UOP_MASK] = codegen_PFMUL, + [UOP_PFRCP & UOP_MASK] = codegen_PFRCP, + [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, + [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, + [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, + + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, + [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, + [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, + + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, + [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, + [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, + [UOP_PSRAW_IMM & UOP_MASK] = codegen_PSRAW_IMM, + [UOP_PSRAD_IMM & UOP_MASK] = codegen_PSRAD_IMM, + [UOP_PSRAQ_IMM & UOP_MASK] = codegen_PSRAQ_IMM, + [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, + [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, + [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, + + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, + [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, + [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, + [UOP_PSUBSB & UOP_MASK] = codegen_PSUBSB, + [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, + [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, + [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, + + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, + [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, + [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, + [UOP_PUNPCKLBW & UOP_MASK] = codegen_PUNPCKLBW, + [UOP_PUNPCKLWD & UOP_MASK] = codegen_PUNPCKLWD, + [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, + + [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP +}; + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDRB_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_8 - not in range\n"); +} +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_h((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDRH_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_16 - not in range\n"); +} +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_w((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_32 - not in range\n"); +} +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_double - not in range\n"); +} +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_X(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_pointer - not in range\n"); +} +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_LDR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_double - not in range\n"); +} +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_LDRB_REG(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_LDR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_LDR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_b((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STRB_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_8 - not in range\n"); +} +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_h((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STRH_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_16 - not in range\n"); +} +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_w((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_W(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_32 - not in range\n"); +} +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_double - not in range\n"); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_F64(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_double - not in range\n"); +} +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_STRB_REG(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_STR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm64_LDR_IMM_W(block, REG_TEMP, REG_XSP, IREG_TOP_diff_stack_offset); + host_arm64_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm64_ADDX_IMM(block, REG_TEMP2, REG_CPUSTATE, (uintptr_t)base - (uintptr_t)&cpu_state); + host_arm64_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm64_STR_REG_F64_S(block, host_reg, REG_TEMP2, REG_TEMP); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + if (in_range12_q((uintptr_t)p - (uintptr_t)&cpu_state)) + host_arm64_STR_IMM_Q(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_ptr - not in range\n"); +} + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (in_range12_h(stack_offset)) + host_arm64_LDRH_IMM(block, host_reg, REG_XSP, stack_offset); + else + fatal("codegen_direct_read_32_stack - not in range\n"); +} +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (in_range12_w(stack_offset)) + host_arm64_LDR_IMM_W(block, host_reg, REG_XSP, stack_offset); + else + fatal("codegen_direct_read_32_stack - not in range\n"); +} +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (in_range12_q(stack_offset)) + host_arm64_LDR_IMM_X(block, host_reg, REG_XSP, stack_offset); + else + fatal("codegen_direct_read_pointer_stack - not in range\n"); +} +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_arm64_LDR_IMM_F64(block, host_reg, REG_XSP, stack_offset); +} +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_arm64_LDR_IMM_F64(block, host_reg, REG_XSP, stack_offset); +} + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + if (in_range12_w(stack_offset)) + host_arm64_STR_IMM_W(block, host_reg, REG_XSP, stack_offset); + else + fatal("codegen_direct_write_32_stack - not in range\n"); +} +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_arm64_STR_IMM_F64(block, host_reg, REG_XSP, stack_offset); +} +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_arm64_STR_IMM_F64(block, host_reg, REG_XSP, stack_offset); +} + +void codegen_set_jump_dest(codeblock_t *block, void *p) +{ + host_arm64_branch_set_offset(p, &block_write_data[block_pos]); +} +#endif diff --git a/src/codegen_backend_arm_defs.h b/src/codegen_backend_arm_defs.h new file mode 100644 index 0000000..2f50129 --- /dev/null +++ b/src/codegen_backend_arm_defs.h @@ -0,0 +1,89 @@ +#define REG_R0 0 +#define REG_R1 1 +#define REG_R2 2 +#define REG_R3 3 +#define REG_R4 4 +#define REG_R5 5 +#define REG_R6 6 +#define REG_R7 7 +#define REG_R8 8 +#define REG_R9 9 +#define REG_R10 10 +#define REG_R11 11 +#define REG_R12 12 +#define REG_HOST_SP 13 +#define REG_LR 14 +#define REG_PC 15 + +#define REG_ARG0 REG_R0 +#define REG_ARG1 REG_R1 +#define REG_ARG2 REG_R2 +#define REG_ARG3 REG_R3 + +#define REG_CPUSTATE REG_R10 + +#define REG_TEMP REG_R3 +#define REG_TEMP2 REG_R2 + +#define REG_D0 0 +#define REG_D1 1 +#define REG_D2 2 +#define REG_D3 3 +#define REG_D4 4 +#define REG_D5 5 +#define REG_D6 6 +#define REG_D7 7 +#define REG_D8 8 +#define REG_D9 9 +#define REG_D10 10 +#define REG_D11 11 +#define REG_D12 12 +#define REG_D13 13 +#define REG_D14 14 +#define REG_D15 15 + +#define REG_D_TEMP REG_D0 +#define REG_Q_TEMP REG_D0 +#define REG_Q_TEMP_2 REG_D2 + +#define REG_MASK_R0 (1 << REG_R0) +#define REG_MASK_R1 (1 << REG_R1) +#define REG_MASK_R2 (1 << REG_R2) +#define REG_MASK_R3 (1 << REG_R3) +#define REG_MASK_R4 (1 << REG_R4) +#define REG_MASK_R5 (1 << REG_R5) +#define REG_MASK_R6 (1 << REG_R6) +#define REG_MASK_R7 (1 << REG_R7) +#define REG_MASK_R8 (1 << REG_R8) +#define REG_MASK_R9 (1 << REG_R9) +#define REG_MASK_R10 (1 << REG_R10) +#define REG_MASK_R11 (1 << REG_R11) +#define REG_MASK_R12 (1 << REG_R12) +#define REG_MASK_SP (1 << REG_HOST_SP) +#define REG_MASK_LR (1 << REG_LR) +#define REG_MASK_PC (1 << REG_PC) + +#define REG_MASK_LOCAL (REG_MASK_R4 | REG_MASK_R5 | REG_MASK_R6 | REG_MASK_R7 | \ + REG_MASK_R8 | REG_MASK_R9 | REG_MASK_R10 | REG_MASK_R11) + +#define CODEGEN_HOST_REGS 7 +#define CODEGEN_HOST_FP_REGS 8 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; +extern void *codegen_mem_load_quad; +extern void *codegen_mem_load_single; +extern void *codegen_mem_load_double; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; +extern void *codegen_mem_store_quad; +extern void *codegen_mem_store_single; +extern void *codegen_mem_store_double; + +extern void *codegen_fp_round; + +extern void *codegen_gpf_rout; +extern void *codegen_exit_rout; diff --git a/src/codegen_backend_arm_ops.c b/src/codegen_backend_arm_ops.c new file mode 100644 index 0000000..9be45f2 --- /dev/null +++ b/src/codegen_backend_arm_ops.c @@ -0,0 +1,1272 @@ +#ifdef __ARM_EABI__ + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" + +#define Rm(x) (x) +#define Rs(x) ((x) << 8) +#define Rd(x) ((x) << 12) +#define Rt(x) ((x) << 12) +#define Rn(x) ((x) << 16) +#define Rt2(x) ((x) << 16) + +#define Vm(x) (x) +#define Vd(x) ((x) << 12) +#define Vn(x) ((x) << 16) + +#define DATA_OFFSET_UP (1 << 23) +#define DATA_OFFSET_DOWN (0 << 23) + +#define OPCODE_SHIFT 20 +#define OPCODE_ADD_IMM (0x28 << OPCODE_SHIFT) +#define OPCODE_ADD_REG (0x08 << OPCODE_SHIFT) +#define OPCODE_AND_IMM (0x20 << OPCODE_SHIFT) +#define OPCODE_AND_REG (0x00 << OPCODE_SHIFT) +#define OPCODE_B (0xa0 << OPCODE_SHIFT) +#define OPCODE_BIC_IMM (0x3c << OPCODE_SHIFT) +#define OPCODE_BIC_REG (0x1c << OPCODE_SHIFT) +#define OPCODE_BL (0xb0 << OPCODE_SHIFT) +#define OPCODE_CMN_IMM (0x37 << OPCODE_SHIFT) +#define OPCODE_CMN_REG (0x17 << OPCODE_SHIFT) +#define OPCODE_CMP_IMM (0x35 << OPCODE_SHIFT) +#define OPCODE_CMP_REG (0x15 << OPCODE_SHIFT) +#define OPCODE_EOR_IMM (0x22 << OPCODE_SHIFT) +#define OPCODE_EOR_REG (0x02 << OPCODE_SHIFT) +#define OPCODE_LDMIA_WB (0x8b << OPCODE_SHIFT) +#define OPCODE_LDR_IMM (0x51 << OPCODE_SHIFT) +#define OPCODE_LDR_IMM_POST (0x41 << OPCODE_SHIFT) +#define OPCODE_LDR_REG (0x79 << OPCODE_SHIFT) +#define OPCODE_LDRB_IMM (0x55 << OPCODE_SHIFT) +#define OPCODE_LDRB_REG (0x7d << OPCODE_SHIFT) +#define OPCODE_MOV_IMM (0x3a << OPCODE_SHIFT) +#define OPCODE_MOVT_IMM (0x34 << OPCODE_SHIFT) +#define OPCODE_MOVW_IMM (0x30 << OPCODE_SHIFT) +#define OPCODE_MOV_REG (0x1a << OPCODE_SHIFT) +#define OPCODE_MVN_REG (0x1e << OPCODE_SHIFT) +#define OPCODE_ORR_IMM (0x38 << OPCODE_SHIFT) +#define OPCODE_ORR_REG (0x18 << OPCODE_SHIFT) +#define OPCODE_RSB_IMM (0x26 << OPCODE_SHIFT) +#define OPCODE_RSB_REG (0x06 << OPCODE_SHIFT) +#define OPCODE_STMDB_WB (0x92 << OPCODE_SHIFT) +#define OPCODE_STR_IMM (0x50 << OPCODE_SHIFT) +#define OPCODE_STR_IMM_WB (0x52 << OPCODE_SHIFT) +#define OPCODE_STR_REG (0x78 << OPCODE_SHIFT) +#define OPCODE_STRB_IMM (0x54 << OPCODE_SHIFT) +#define OPCODE_STRB_REG (0x7c << OPCODE_SHIFT) +#define OPCODE_SUB_IMM (0x24 << OPCODE_SHIFT) +#define OPCODE_SUB_REG (0x04 << OPCODE_SHIFT) +#define OPCODE_TST_IMM (0x31 << OPCODE_SHIFT) +#define OPCODE_TST_REG (0x11 << OPCODE_SHIFT) + +#define OPCODE_BFI 0xe7c00010 +#define OPCODE_BLX 0xe12fff30 +#define OPCODE_BX 0xe12fff10 +#define OPCODE_LDRH_IMM 0xe1d000b0 +#define OPCODE_LDRH_REG 0xe19000b0 +#define OPCODE_STRH_IMM 0xe1c000b0 +#define OPCODE_STRH_REG 0xe18000b0 +#define OPCODE_SXTB 0xe6af0070 +#define OPCODE_SXTH 0xe6bf0070 +#define OPCODE_UADD8 0xe6500f90 +#define OPCODE_UADD16 0xe6500f10 +#define OPCODE_USUB8 0xe6500ff0 +#define OPCODE_USUB16 0xe6500f70 +#define OPCODE_UXTB 0xe6ef0070 +#define OPCODE_UXTH 0xe6ff0070 +#define OPCODE_VABS_D 0xeeb00bc0 +#define OPCODE_VADD 0xee300b00 +#define OPCODE_VADD_I8 0xf2000800 +#define OPCODE_VADD_I16 0xf2100800 +#define OPCODE_VADD_I32 0xf2200800 +#define OPCODE_VADD_F32 0xf2000d00 +#define OPCODE_VAND_D 0xf2000110 +#define OPCODE_VBIC_D 0xf2100110 +#define OPCODE_VCEQ_F32 0xf2000e00 +#define OPCODE_VCEQ_I8 0xf3000810 +#define OPCODE_VCEQ_I16 0xf3100810 +#define OPCODE_VCEQ_I32 0xf3200810 +#define OPCODE_VCGE_F32 0xf3000e00 +#define OPCODE_VCGT_F32 0xf3200e00 +#define OPCODE_VCGT_S8 0xf2000300 +#define OPCODE_VCGT_S16 0xf2100300 +#define OPCODE_VCGT_S32 0xf2200300 +#define OPCODE_VCMP_D 0xeeb40b40 +#define OPCODE_VCVT_D_IS 0xeeb80bc0 +#define OPCODE_VCVT_D_S 0xeeb70ac0 +#define OPCODE_VCVT_F32_S32 0xf3bb0700 +#define OPCODE_VCVT_IS_D 0xeebd0bc0 +#define OPCODE_VCVT_S32_F32 0xf3bb0600 +#define OPCODE_VCVT_S_D 0xeeb70bc0 +#define OPCODE_VCVTR_IS_D 0xeebd0b40 +#define OPCODE_VDIV 0xee800b00 +#define OPCODE_VDIV_S 0xee800a00 +#define OPCODE_VDUP_32 0xf3b40c00 +#define OPCODE_VEOR_D 0xf3000110 +#define OPCODE_VLDR_D 0xed900b00 +#define OPCODE_VLDR_S 0xed900a00 +#define OPCODE_VMAX_F32 0xf200f00 +#define OPCODE_VMIN_F32 0xf220f00 +#define OPCODE_VMOV_32_S 0xee100a10 +#define OPCODE_VMOV_64_D 0xec500b10 +#define OPCODE_VMOV_D_64 0xec400b10 +#define OPCODE_VMOV_S_32 0xee000a10 +#define OPCODE_VMOV_D_D 0xeeb00b40 +#define OPCODE_VMOVN_I32 0xf3b60200 +#define OPCODE_VMOVN_I64 0xf3ba0200 +#define OPCODE_VMOV_F32_ONE 0xf2870f10 +#define OPCODE_VMRS_APSR 0xeef1fa10 +#define OPCODE_VMSR_FPSCR 0xeee10a10 +#define OPCODE_VMUL 0xee200b00 +#define OPCODE_VMUL_F32 0xf3000d10 +#define OPCODE_VMUL_S16 0xf2100910 +#define OPCODE_VMULL_S16 0xf2900c00 +#define OPCODE_VNEG_D 0xeeb10b40 +#define OPCODE_VORR_D 0xf2200110 +#define OPCODE_VPADDL_S16 0xf3b40200 +#define OPCODE_VPADDL_S32 0xf3b80200 +#define OPCODE_VPADDL_Q_S32 0xf3b80240 +#define OPCODE_VQADD_S8 0xf2000010 +#define OPCODE_VQADD_S16 0xf2100010 +#define OPCODE_VQADD_U8 0xf3000010 +#define OPCODE_VQADD_U16 0xf3100010 +#define OPCODE_VQMOVN_S16 0xf3b20280 +#define OPCODE_VQMOVN_S32 0xf3b60280 +#define OPCODE_VQMOVN_U16 0xf3b202c0 +#define OPCODE_VQSUB_S8 0xf2000210 +#define OPCODE_VQSUB_S16 0xf2100210 +#define OPCODE_VQSUB_U8 0xf3000210 +#define OPCODE_VQSUB_U16 0xf3100210 +#define OPCODE_VSHL_D_IMM_16 0xf2900510 +#define OPCODE_VSHL_D_IMM_32 0xf2a00510 +#define OPCODE_VSHL_D_IMM_64 0xf2800590 +#define OPCODE_VSHR_D_S16 0xf2900010 +#define OPCODE_VSHR_D_S32 0xf2a00010 +#define OPCODE_VSHR_D_S64 0xf2800090 +#define OPCODE_VSHR_D_U16 0xf3900010 +#define OPCODE_VSHR_D_U32 0xf3a00010 +#define OPCODE_VSHR_D_U64 0xf3800090 +#define OPCODE_VSHRN 0xf2800810 +#define OPCODE_VSQRT_D 0xeeb10bc0 +#define OPCODE_VSQRT_S 0xeeb10ac0 +#define OPCODE_VSTR_D 0xed800b00 +#define OPCODE_VSTR_S 0xed800a00 +#define OPCODE_VSUB 0xee300b40 +#define OPCODE_VSUB_I8 0xf3000800 +#define OPCODE_VSUB_I16 0xf3100800 +#define OPCODE_VSUB_I32 0xf3200800 +#define OPCODE_VSUB_F32 0xf3000d00 +#define OPCODE_VZIP_D8 0xf3b20180 +#define OPCODE_VZIP_D16 0xf3b60180 +#define OPCODE_VZIP_D32 0xf3ba0080 + +#define B_OFFSET(x) (((x) >> 2) & 0xffffff) + +#define SHIFT_TYPE_SHIFT 5 +#define SHIFT_TYPE_LSL (0 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_LSR (1 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_ASR (2 << SHIFT_TYPE_SHIFT) +#define SHIFT_TYPE_ROR (3 << SHIFT_TYPE_SHIFT) + +#define SHIFT_TYPE_IMM (0 << 4) +#define SHIFT_TYPE_REG (1 << 4) + +#define SHIFT_IMM_SHIFT 7 +#define SHIFT_ASR_IMM(x) (SHIFT_TYPE_ASR | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) +#define SHIFT_LSL_IMM(x) (SHIFT_TYPE_LSL | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) +#define SHIFT_LSR_IMM(x) (SHIFT_TYPE_LSR | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) +#define SHIFT_ROR_IMM(x) (SHIFT_TYPE_ROR | SHIFT_TYPE_IMM | ((x) << SHIFT_IMM_SHIFT)) + +#define SHIFT_ASR_REG(x) (SHIFT_TYPE_ASR | SHIFT_TYPE_REG | Rs(x)) +#define SHIFT_LSL_REG(x) (SHIFT_TYPE_LSL | SHIFT_TYPE_REG | Rs(x)) +#define SHIFT_LSR_REG(x) (SHIFT_TYPE_LSR | SHIFT_TYPE_REG | Rs(x)) +#define SHIFT_ROR_REG(x) (SHIFT_TYPE_ROR | SHIFT_TYPE_REG | Rs(x)) + +#define BFI_lsb(lsb) ((lsb) << 7) +#define BFI_msb(msb) ((msb) << 16) + +#define UXTB_ROTATE(rotate) (((rotate) >> 3) << 10) + +#define MOVT_IMM(imm) (((imm) & 0xfff) | (((imm) & 0xf000) << 4)) +#define MOVW_IMM(imm) (((imm) & 0xfff) | (((imm) & 0xf000) << 4)) + +#define LDRH_IMM(imm) (((imm) & 0xf) | (((imm) & 0xf0) << 4)) +#define STRH_IMM(imm) LDRH_IMM(imm) + +#define VSHIFT_IMM(shift) ((shift) << 16) + +#define VSHIFT_IMM_32(shift) (((16 - (shift)) | 0x10) << 16) + +#define VDUP_32_IMM(imm) ((imm) << 19) + +static void codegen_allocate_new_block(codeblock_t *block); + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + if (block_pos >= (BLOCK_MAX-4)) + codegen_allocate_new_block(block); + *(uint32_t *)&block_write_data[block_pos] = val; + block_pos += 4; +} + +static void codegen_allocate_new_block(codeblock_t *block) +{ + /*Current block is full. Allocate a new block*/ + struct mem_block_t *new_block = codegen_allocator_allocate(block->head_mem_block, get_block_nr(block)); + uint8_t *new_ptr = codeblock_allocator_get_ptr(new_block); + uint32_t offset = ((uintptr_t)new_ptr - (uintptr_t)&block_write_data[block_pos]) - 8; + + /*Add a jump instruction to the new block*/ + *(uint32_t *)&block_write_data[block_pos] = COND_AL | OPCODE_B | B_OFFSET(offset); + + /*Set write address to start of new block*/ + block_pos = 0; + block_write_data = new_ptr; +} + +static inline void codegen_alloc_4(codeblock_t *block) +{ + if (block_pos >= (BLOCK_MAX-4)) + codegen_allocate_new_block(block); +} + +void codegen_alloc(codeblock_t *block, int size) +{ + if (block_pos >= (BLOCK_MAX-size)) + codegen_allocate_new_block(block); +} + +static inline uint32_t arm_data_offset(int offset) +{ + if (offset < -0xffc || offset > 0xffc) + fatal("arm_data_offset out of range - %i\n", offset); + + if (offset >= 0) + return offset | DATA_OFFSET_UP; + return (-offset) | DATA_OFFSET_DOWN; +} + +static inline int get_arm_imm(uint32_t imm_data, uint32_t *arm_imm) +{ + int shift = 0; +//pclog("get_arm_imm - imm_data=%08x\n", imm_data); + if (!(imm_data & 0xffff)) + { + shift += 16; + imm_data >>= 16; + } + if (!(imm_data & 0xff)) + { + shift += 8; + imm_data >>= 8; + } + if (!(imm_data & 0xf)) + { + shift += 4; + imm_data >>= 4; + } + if (!(imm_data & 0x3)) + { + shift += 2; + imm_data >>= 2; + } + if (imm_data > 0xff) /*Note - should handle rotation round the word*/ + return 0; +//pclog(" imm_data=%02x shift=%i\n", imm_data, shift); + *arm_imm = imm_data | ((((32 - shift) >> 1) & 15) << 8); + return 1; +} + +static inline int in_range(void *addr, void *base) +{ + int diff = (uintptr_t)addr - (uintptr_t)base; + + if (diff < -4095 || diff > 4095) + return 0; + return 1; +} + +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +//void host_arm_ORR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_SUB_IMM(block, dst_reg, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_ADD_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_ADD_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_ADD_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_ADD_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else if (get_arm_imm(~imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_BIC_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_AND_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_AND_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_AND_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_B(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + { + host_arm_MOV_IMM(block, REG_R3, dest_addr); + host_arm_BX(block, REG_R3); + } + else + codegen_addlong(block, COND_AL | OPCODE_B | B_OFFSET(offset)); +} + +void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width) +{ + codegen_addlong(block, OPCODE_BFI | Rd(dst_reg) | Rm(src_reg) | BFI_lsb(lsb) | BFI_msb((lsb + width) - 1)); +} + +void host_arm_BIC_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_BIC_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else if (get_arm_imm(~imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_AND_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_BIC_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} +void host_arm_BIC_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_BIC_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_BIC_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_BIC_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_BL(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + { + host_arm_MOV_IMM(block, REG_R3, dest_addr); + host_arm_BLX(block, REG_R3); + } + else + codegen_addlong(block, COND_AL | OPCODE_BL | B_OFFSET(offset)); +} +void host_arm_BL_r1(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + { + host_arm_MOV_IMM(block, REG_R1, dest_addr); + host_arm_BLX(block, REG_R1); + } + else + codegen_addlong(block, COND_AL | OPCODE_BL | B_OFFSET(offset)); +} +void host_arm_BLX(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BLX | Rm(addr_reg)); +} + +uint32_t *host_arm_BCC_(codeblock_t *block) +{ + codegen_addlong(block, COND_CC | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BCS_(codeblock_t *block) +{ + codegen_addlong(block, COND_CS | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BEQ_(codeblock_t *block) +{ + codegen_addlong(block, COND_EQ | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BGE_(codeblock_t *block) +{ + codegen_addlong(block, COND_GE | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BGT_(codeblock_t *block) +{ + codegen_addlong(block, COND_GT | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BHI_(codeblock_t *block) +{ + codegen_addlong(block, COND_HI | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BLE_(codeblock_t *block) +{ + codegen_addlong(block, COND_LE | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BLS_(codeblock_t *block) +{ + codegen_addlong(block, COND_LS | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BLT_(codeblock_t *block) +{ + codegen_addlong(block, COND_LT | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BMI_(codeblock_t *block) +{ + codegen_addlong(block, COND_MI | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BNE_(codeblock_t *block) +{ + codegen_addlong(block, COND_NE | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BPL_(codeblock_t *block) +{ + codegen_addlong(block, COND_PL | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BVC_(codeblock_t *block) +{ + codegen_addlong(block, COND_VC | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} +uint32_t *host_arm_BVS_(codeblock_t *block) +{ + codegen_addlong(block, COND_VS | OPCODE_B); + + return (uint32_t *)&block_write_data[block_pos - 4]; +} + +void host_arm_BEQ(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + fatal("host_arm_BEQ - out of range %08x %i\n", offset, offset); + + codegen_addlong(block, COND_EQ | OPCODE_B | B_OFFSET(offset)); +} +void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr) +{ + uint32_t offset; + + codegen_alloc_4(block); + offset = (dest_addr - (uintptr_t)&block_write_data[block_pos]) - 8; + + if ((offset & 0xfe000000) && (offset & 0xfe000000) != 0xfe000000) + fatal("host_arm_BNE - out of range %08x %i\n", offset, offset); + + codegen_addlong(block, COND_NE | OPCODE_B | B_OFFSET(offset)); +} + +void host_arm_BX(codeblock_t *block, int addr_reg) +{ + codegen_addlong(block, OPCODE_BLX | Rm(addr_reg)); +} + +void host_arm_CMN_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_CMP_IMM(block, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_CMN_IMM | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_CMN_REG_LSL(block, src_reg, REG_TEMP, 0); + } +} +void host_arm_CMN_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_CMN_REG | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_CMP_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_CMN_IMM(block, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_CMP_IMM | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_CMP_REG_LSL(block, src_reg, REG_TEMP, 0); + } +} +void host_arm_CMP_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_CMP_REG | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_EOR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_EOR_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_EOR_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_EOR_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) +{ + codegen_addlong(block, COND_AL | OPCODE_LDMIA_WB | Rn(addr_reg) | reg_mask); +} + +void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_IMM | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDR_IMM_POST(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_IMM_POST | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDR_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_LDR_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDRB_ABS(codeblock_t *block, int dst_reg, void *p) +{ + if (in_range(p, &cpu_state)) + host_arm_LDRB_IMM(block, dst_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("LDRB_ABS - not in range\n"); +} +void host_arm_LDRB_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRB_IMM | Rn(addr_reg) | Rd(dst_reg) | arm_data_offset(offset)); +} +void host_arm_LDRB_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRB_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_LDRH_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRH_IMM | Rn(addr_reg) | Rd(dst_reg) | LDRH_IMM(offset)); +} +void host_arm_LDRH_REG(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_LDRH_REG | Rn(addr_reg) | Rd(dst_reg) | Rm(offset_reg)); +} + +void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_MOV_IMM | Rd(dst_reg) | arm_imm); + } + else + { + host_arm_MOVW_IMM(block, dst_reg, imm & 0xffff); + if (imm >> 16) + host_arm_MOVT_IMM(block, dst_reg, imm >> 16); + } +} + +void host_arm_MOV_REG_ASR(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_ASR_IMM(shift)); +} +void host_arm_MOV_REG_ASR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_ASR_REG(shift_reg)); +} +void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); +} +void host_arm_MOV_REG_LSL_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_REG(shift_reg)); +} +void host_arm_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSR_IMM(shift)); +} +void host_arm_MOV_REG_LSR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSR_REG(shift_reg)); +} +void host_arm_MOV_REG_ROR(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_ROR_IMM(shift)); +} +void host_arm_MOV_REG_ROR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_MOV_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_ROR_REG(shift_reg)); +} + +void host_arm_MOVT_IMM(codeblock_t *block, int dst_reg, uint16_t imm) +{ + codegen_addlong(block, COND_AL | OPCODE_MOVT_IMM | Rd(dst_reg) | MOVT_IMM(imm)); +} +void host_arm_MOVW_IMM(codeblock_t *block, int dst_reg, uint16_t imm) +{ + codegen_addlong(block, COND_AL | OPCODE_MOVW_IMM | Rd(dst_reg) | MOVW_IMM(imm)); +} + +void host_arm_MVN_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_MVN_REG | Rd(dst_reg) | Rm(src_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_ORR_IMM_cond(codeblock_t *block, uint32_t cond, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, cond | OPCODE_ORR_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_ORR_REG_LSL_cond(block, cond, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_ORR_REG_LSL_cond(codeblock_t *block, uint32_t cond, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, cond | OPCODE_ORR_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_RSB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_RSB_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_RSB_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} +void host_arm_RSB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_RSB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_RSB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_RSB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask) +{ + codegen_addlong(block, COND_AL | OPCODE_STMDB_WB | Rn(addr_reg) | reg_mask); +} + +void host_arm_STR_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_IMM | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STR_IMM_WB(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_IMM_WB | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STR_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_STR_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_STRB_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STRB_IMM | Rn(addr_reg) | Rd(src_reg) | arm_data_offset(offset)); +} +void host_arm_STRB_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_STRB_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg) | SHIFT_LSL_IMM(shift)); +} + +void host_arm_STRH_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset) +{ + codegen_addlong(block, COND_AL | OPCODE_STRH_IMM | Rn(addr_reg) | Rd(dst_reg) | STRH_IMM(offset)); +} +void host_arm_STRH_REG(codeblock_t *block, int src_reg, int addr_reg, int offset_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_STRH_REG | Rn(addr_reg) | Rd(src_reg) | Rm(offset_reg)); +} + +void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if ((int32_t)imm < 0 && imm != 0x80000000) + { + host_arm_ADD_IMM(block, dst_reg, src_reg, -(int32_t)imm); + } + else if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_SUB_IMM | Rd(dst_reg) | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_SUB_REG_LSL(block, dst_reg, src_reg, REG_TEMP, 0); + } +} + +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_SUB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSL_IMM(shift)); +} +void host_arm_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift) +{ + codegen_addlong(block, COND_AL | OPCODE_SUB_REG | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m) | SHIFT_LSR_IMM(shift)); +} + +void host_arm_SXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_SXTB | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} +void host_arm_SXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_SXTH | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} + +void host_arm_TST_IMM(codeblock_t *block, int src_reg, uint32_t imm) +{ + uint32_t arm_imm; + + if (get_arm_imm(imm, &arm_imm)) + { + codegen_addlong(block, COND_AL | OPCODE_TST_IMM | Rn(src_reg) | arm_imm); + } + else + { + host_arm_MOV_IMM(block, REG_TEMP, imm); + host_arm_TST_REG(block, src_reg, REG_TEMP); + } +} +void host_arm_TST_REG(codeblock_t *block, int src_reg1, int src_reg2) +{ + codegen_addlong(block, COND_AL | OPCODE_TST_REG | Rn(src_reg1) | Rm(src_reg2)); +} + +void host_arm_UADD8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_UADD8 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_UADD16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_UADD16 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_USUB8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_USUB8 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_USUB16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_addlong(block, COND_AL | OPCODE_USUB16 | Rd(dst_reg) | Rn(src_reg_a) | Rm(src_reg_b)); +} + +void host_arm_UXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_UXTB | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} + +void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate) +{ + codegen_addlong(block, OPCODE_UXTH | Rd(dst_reg) | Rm(src_reg) | UXTB_ROTATE(rotate)); +} + +void host_arm_VABS_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VABS_D | Vd(dest_reg) | Vm(src_reg)); +} + +void host_arm_VADD_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VADD | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VADD_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VADD_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VADD_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VADD_I8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VADD_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VADD_I16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VADD_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VADD_I32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VAND_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VAND_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VBIC_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VBIC_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCMP_D(codeblock_t *block, int src_reg_d, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VCMP_D | Rd(src_reg_d) | Rm(src_reg_m)); +} + +void host_arm_VCEQ_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCEQ_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCEQ_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCEQ_I8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCEQ_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCEQ_I16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCEQ_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCEQ_I32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGE_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGE_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGT_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGT_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGT_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGT_S8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGT_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGT_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VCGT_S32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VCGT_S32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VCVT_D_IS(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_D_IS | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_D_S(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_D_S | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_F32_S32(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_F32_S32 | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_IS_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_IS_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_S32_F32(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_S32_F32 | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVT_S_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVT_S_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VCVTR_IS_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VCVTR_IS_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VDIV_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VDIV | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VDIV_S(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VDIV_S | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VDUP_32(codeblock_t *block, int dst_reg, int src_reg_m, int imm) +{ + codegen_addlong(block, COND_AL | OPCODE_VDUP_32 | Rd(dst_reg) | Rm(src_reg_m) | VDUP_32_IMM(imm)); +} +void host_arm_VEOR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VEOR_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VLDR_D(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VLDR_D bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VLDR_D | Rd(dest_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VLDR_S(codeblock_t *block, int dest_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VLDR_S bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VLDR_S | Rd(dest_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VMOV_32_S(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_32_S | Rt(dest_reg) | Vn(src_reg)); +} +void host_arm_VMOV_64_D(codeblock_t *block, int dest_reg_low, int dest_reg_high, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_64_D | Rt(dest_reg_low) | Rt2(dest_reg_high) | Vm(src_reg)); +} +void host_arm_VMOV_D_64(codeblock_t *block, int dest_reg, int src_reg_low, int src_reg_high) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_D_64 | Vm(dest_reg) | Rt(src_reg_low) | Rt2(src_reg_high)); +} +void host_arm_VMOV_S_32(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_S_32 | Vn(dest_reg) | Rt(src_reg)); +} +void host_arm_VMOV_D_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_D_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VMOVN_I32(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VMOVN_I32 | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VMOVN_I64(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VMOVN_I64 | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VMOV_F32_ONE(codeblock_t *block, int dst_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMOV_F32_ONE | Rd(dst_reg)); +} +void host_arm_VMSR_FPSCR(codeblock_t *block, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VMSR_FPSCR | Rd(src_reg)); +} +void host_arm_VMRS_APSR(codeblock_t *block) +{ + codegen_addlong(block, COND_AL | OPCODE_VMRS_APSR); +} + +void host_arm_VMAX_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VMAX_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VMIN_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VMIN_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VMUL_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VMUL | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VMUL_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VMUL_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VMUL_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VMUL_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VMULL_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VMULL_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VNEG_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VNEG_D | Vd(dest_reg) | Vm(src_reg)); +} + +void host_arm_VORR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VORR_D | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VPADDL_S16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VPADDL_S16 | Vd(dst_reg) | Vm(src_reg)); +} +void host_arm_VPADDL_S32(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VPADDL_S32 | Vd(dst_reg) | Vm(src_reg)); +} +void host_arm_VPADDL_Q_S32(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VPADDL_Q_S32 | Vd(dst_reg) | Vm(src_reg)); +} + +void host_arm_VQADD_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQADD_S8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQADD_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQADD_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQADD_U8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQADD_U8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQADD_U16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQADD_U16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQSUB_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQSUB_S8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQSUB_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQSUB_S16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQSUB_U8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQSUB_U8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VQSUB_U16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VQSUB_U16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VQMOVN_S16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VQMOVN_S16 | Vd(dst_reg) | Vm(src_reg)); +} +void host_arm_VQMOVN_S32(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VQMOVN_S32 | Vd(dst_reg) | Vm(src_reg)); +} +void host_arm_VQMOVN_U16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_addlong(block, OPCODE_VQMOVN_U16 | Vd(dst_reg) | Vm(src_reg)); +} + +void host_arm_VSHL_D_IMM_16(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 15) + fatal("host_arm_VSHL_D_IMM_16 : shift > 15\n"); + codegen_addlong(block, OPCODE_VSHL_D_IMM_16 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(shift)); +} +void host_arm_VSHL_D_IMM_32(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 31) + fatal("host_arm_VSHL_D_IMM_32 : shift > 31\n"); + codegen_addlong(block, OPCODE_VSHL_D_IMM_32 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(shift)); +} +void host_arm_VSHL_D_IMM_64(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 63) + fatal("host_arm_VSHL_D_IMM_64 : shift > 63\n"); + codegen_addlong(block, OPCODE_VSHL_D_IMM_64 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(shift)); +} +void host_arm_VSHR_D_S16(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 15) + fatal("host_arm_VSHR_SD_IMM_16 : shift > 15\n"); + codegen_addlong(block, OPCODE_VSHR_D_S16 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(16-shift)); +} +void host_arm_VSHR_D_S32(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 31) + fatal("host_arm_VSHR_SD_IMM_32 : shift > 31\n"); + codegen_addlong(block, OPCODE_VSHR_D_S32 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(32-shift)); +} +void host_arm_VSHR_D_S64(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 63) + fatal("host_arm_VSHR_SD_IMM_64 : shift > 63\n"); + codegen_addlong(block, OPCODE_VSHR_D_S64 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(64-shift)); +} +void host_arm_VSHR_D_U16(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 15) + fatal("host_arm_VSHR_UD_IMM_16 : shift > 15\n"); + codegen_addlong(block, OPCODE_VSHR_D_U16 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(16-shift)); +} +void host_arm_VSHR_D_U32(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 31) + fatal("host_arm_VSHR_UD_IMM_32 : shift > 31\n"); + codegen_addlong(block, OPCODE_VSHR_D_U32 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(32-shift)); +} +void host_arm_VSHR_D_U64(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 63) + fatal("host_arm_VSHR_UD_IMM_64 : shift > 63\n"); + codegen_addlong(block, OPCODE_VSHR_D_U64 | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM(64-shift)); +} +void host_arm_VSHRN_32(codeblock_t *block, int dst_reg, int src_reg, int shift) +{ + if (shift > 16) + fatal("host_arm_VSHRN_32 : shift > 16\n"); + codegen_addlong(block, OPCODE_VSHRN | Vd(dst_reg) | Vm(src_reg) | VSHIFT_IMM_32(16-shift)); +} + +void host_arm_VSQRT_D(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VSQRT_D | Vd(dest_reg) | Vm(src_reg)); +} +void host_arm_VSQRT_S(codeblock_t *block, int dest_reg, int src_reg) +{ + codegen_addlong(block, COND_AL | OPCODE_VSQRT_S | Vd(dest_reg) | Vm(src_reg)); +} + +void host_arm_VSTR_D(codeblock_t *block, int src_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VSTR_D bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VSTR_D | Rd(src_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VSTR_S(codeblock_t *block, int src_reg, int base_reg, int offset) +{ + if ((offset > 1020) || (offset & 3)) + fatal("VSTR_S bad offset %i\n", offset); + codegen_addlong(block, COND_AL | OPCODE_VSTR_S | Rd(src_reg) | Rn(base_reg) | (offset >> 2)); +} +void host_arm_VSUB_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VSUB | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSUB_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, COND_AL | OPCODE_VSUB_F32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSUB_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VSUB_I8 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSUB_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VSUB_I16 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} +void host_arm_VSUB_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m) +{ + codegen_addlong(block, OPCODE_VSUB_I32 | Rd(dst_reg) | Rn(src_reg_n) | Rm(src_reg_m)); +} + +void host_arm_VZIP_D8(codeblock_t *block, int d_reg, int m_reg) +{ + codegen_addlong(block, OPCODE_VZIP_D8 | Vd(d_reg) | Vm(m_reg)); +} +void host_arm_VZIP_D16(codeblock_t *block, int d_reg, int m_reg) +{ + codegen_addlong(block, OPCODE_VZIP_D16 | Vd(d_reg) | Vm(m_reg)); +} +void host_arm_VZIP_D32(codeblock_t *block, int d_reg, int m_reg) +{ + codegen_addlong(block, OPCODE_VZIP_D32 | Vd(d_reg) | Vm(m_reg)); +} + +#endif diff --git a/src/codegen_backend_arm_ops.h b/src/codegen_backend_arm_ops.h new file mode 100644 index 0000000..7627f51 --- /dev/null +++ b/src/codegen_backend_arm_ops.h @@ -0,0 +1,252 @@ +#define COND_SHIFT 28 +#define COND_EQ (0x0 << COND_SHIFT) +#define COND_NE (0x1 << COND_SHIFT) +#define COND_CS (0x2 << COND_SHIFT) +#define COND_CC (0x3 << COND_SHIFT) +#define COND_MI (0x4 << COND_SHIFT) +#define COND_PL (0x5 << COND_SHIFT) +#define COND_VS (0x6 << COND_SHIFT) +#define COND_VC (0x7 << COND_SHIFT) +#define COND_HI (0x8 << COND_SHIFT) +#define COND_LS (0x9 << COND_SHIFT) +#define COND_GE (0xa << COND_SHIFT) +#define COND_LT (0xb << COND_SHIFT) +#define COND_GT (0xc << COND_SHIFT) +#define COND_LE (0xd << COND_SHIFT) +#define COND_AL (0xe << COND_SHIFT) + +void host_arm_ADD_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +#define host_arm_ADD_REG(block, dst_reg, src_reg_n, src_reg_m) host_arm_ADD_REG_LSL(block, dst_reg, src_reg_n, src_reg_m, 0) +void host_arm_ADD_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_ADD_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_AND_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_AND_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_AND_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_B(codeblock_t *block, uintptr_t dest_addr); + +void host_arm_BFI(codeblock_t *block, int dst_reg, int src_reg, int lsb, int width); + +void host_arm_BIC_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_BIC_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_BIC_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_BL(codeblock_t *block, uintptr_t dest_addr); +void host_arm_BL_r1(codeblock_t *block, uintptr_t dest_addr); +void host_arm_BLX(codeblock_t *block, int addr_reg); + +uint32_t *host_arm_BCC_(codeblock_t *block); +uint32_t *host_arm_BCS_(codeblock_t *block); +uint32_t *host_arm_BEQ_(codeblock_t *block); +uint32_t *host_arm_BGE_(codeblock_t *block); +uint32_t *host_arm_BGT_(codeblock_t *block); +uint32_t *host_arm_BHI_(codeblock_t *block); +uint32_t *host_arm_BLE_(codeblock_t *block); +uint32_t *host_arm_BLS_(codeblock_t *block); +uint32_t *host_arm_BLT_(codeblock_t *block); +uint32_t *host_arm_BMI_(codeblock_t *block); +uint32_t *host_arm_BNE_(codeblock_t *block); +uint32_t *host_arm_BPL_(codeblock_t *block); +uint32_t *host_arm_BVC_(codeblock_t *block); +uint32_t *host_arm_BVS_(codeblock_t *block); + +void host_arm_BEQ(codeblock_t *block, uintptr_t dest_addr); +void host_arm_BNE(codeblock_t *block, uintptr_t dest_addr); + +void host_arm_BX(codeblock_t *block, int addr_reg); + +void host_arm_CMN_IMM(codeblock_t *block, int src_reg, uint32_t imm); +void host_arm_CMN_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift); + +void host_arm_CMP_IMM(codeblock_t *block, int src_reg, uint32_t imm); +#define host_arm_CMP_REG(block, src_reg_n, src_reg_m) host_arm_CMP_REG_LSL(block, src_reg_n, src_reg_m, 0) +void host_arm_CMP_REG_LSL(codeblock_t *block, int src_reg_n, int src_reg_m, int shift); + +void host_arm_EOR_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_EOR_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_LDMIA_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); + +void host_arm_LDR_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +void host_arm_LDR_IMM_POST(codeblock_t *block, int dst_reg, int addr_reg, int offset); +#define host_arm_LDR_REG(block, dst_reg, addr_reg, offset_reg) host_arm_LDR_REG_LSL(block, dst_reg, addr_reg, offset_reg, 0) +void host_arm_LDR_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_LDRB_ABS(codeblock_t *block, int dst, void *p); +void host_arm_LDRB_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +#define host_arm_LDRB_REG(block, dst_reg, addr_reg, offset_reg) host_arm_LDRB_REG_LSL(block, dst_reg, addr_reg, offset_reg, 0) +void host_arm_LDRB_REG_LSL(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_LDRH_IMM(codeblock_t *block, int dst_reg, int addr_reg, int offset); +void host_arm_LDRH_REG(codeblock_t *block, int dst_reg, int addr_reg, int offset_reg); + +void host_arm_MOV_IMM(codeblock_t *block, int dst_reg, uint32_t imm); +#define host_arm_MOV_REG(block, dst_reg, src_reg) host_arm_MOV_REG_LSL(block, dst_reg, src_reg, 0) +void host_arm_MOV_REG_ASR(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_ASR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg); +void host_arm_MOV_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_LSL_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg); +void host_arm_MOV_REG_LSR(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_LSR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg); +void host_arm_MOV_REG_ROR(codeblock_t *block, int dst_reg, int src_reg, int shift); +void host_arm_MOV_REG_ROR_REG(codeblock_t *block, int dst_reg, int src_reg, int shift_reg); +void host_arm_MOVT_IMM(codeblock_t *block, int dst_reg, uint16_t imm); +void host_arm_MOVW_IMM(codeblock_t *block, int dst_reg, uint16_t imm); + +void host_arm_MVN_REG_LSL(codeblock_t *block, int dst_reg, int src_reg, int shift); + +#define host_arm_NOP(block) host_arm_MOV_REG(block, REG_R0, REG_R0) + +void host_arm_ORR_IMM_cond(codeblock_t *block, uint32_t cond, int dst_reg, int src_reg, uint32_t imm); +void host_arm_ORR_REG_LSL_cond(codeblock_t *block, uint32_t cond, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +#define host_arm_ORR_IMM(block, dst_reg, src_reg, imm) host_arm_ORR_IMM_cond(block, COND_AL, dst_reg, src_reg, imm) +#define host_arm_ORR_REG_LSL(block, dst_reg, src_reg_a, src_reg_b, shift) host_arm_ORR_REG_LSL_cond(block, COND_AL, dst_reg, src_reg_a, src_reg_b, shift) + +#define host_arm_ORRCC_IMM(block, dst_reg, src_reg, imm) host_arm_ORR_IMM_cond(block, COND_CC, dst_reg, src_reg, imm) +#define host_arm_ORREQ_IMM(block, dst_reg, src_reg, imm) host_arm_ORR_IMM_cond(block, COND_EQ, dst_reg, src_reg, imm) +#define host_arm_ORRVS_IMM(block, dst_reg, src_reg, imm) host_arm_ORR_IMM_cond(block, COND_VS, dst_reg, src_reg, imm) + +void host_arm_RSB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_RSB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_RSB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_STMDB_WB(codeblock_t *block, int addr_reg, uint32_t reg_mask); + +void host_arm_STR_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset); +void host_arm_STR_IMM_WB(codeblock_t *block, int src_reg, int addr_reg, int offset); +#define host_arm_STR_REG(block, src_reg, addr_reg, offset_reg) host_arm_STR_REG_LSL(block, src_reg, addr_reg, offset_reg, 0) +void host_arm_STR_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_STRB_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset); +#define host_arm_STRB_REG(block, src_reg, addr_reg, offset_reg) host_arm_STRB_REG_LSL(block, src_reg, addr_reg, offset_reg, 0) +void host_arm_STRB_REG_LSL(codeblock_t *block, int src_reg, int addr_reg, int offset_reg, int shift); + +void host_arm_STRH_IMM(codeblock_t *block, int src_reg, int addr_reg, int offset); +void host_arm_STRH_REG(codeblock_t *block, int src_reg, int addr_reg, int offset_reg); + +void host_arm_SUB_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t imm); +void host_arm_SUB_REG_LSL(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); +void host_arm_SUB_REG_LSR(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m, int shift); + +void host_arm_SXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate); +void host_arm_SXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate); + +void host_arm_TST_IMM(codeblock_t *block, int src_reg1, uint32_t imm); +void host_arm_TST_REG(codeblock_t *block, int src_reg1, int src_reg2); + +void host_arm_UADD8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_arm_UADD16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_arm_USUB8(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_arm_USUB16(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); + +void host_arm_UXTB(codeblock_t *block, int dst_reg, int src_reg, int rotate); +void host_arm_UXTH(codeblock_t *block, int dst_reg, int src_reg, int rotate); + +void host_arm_VABS_D(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VADD_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VADD_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VADD_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VADD_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VADD_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VAND_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VBIC_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCMP_D(codeblock_t *block, int src_reg_d, int src_reg_m); + +void host_arm_VCEQ_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCEQ_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCEQ_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCEQ_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGE_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGT_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGT_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGT_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VCGT_S32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VCHS_D(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VCVT_D_IS(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_D_S(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_F32_S32(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_IS_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_S32_F32(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVT_S_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VCVTR_IS_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VDIV_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VDIV_S(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VDUP_32(codeblock_t *block, int dst_reg, int src_reg_m, int imm); +void host_arm_VEOR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VLDR_D(codeblock_t *block, int dest_reg, int base_reg, int offset); +void host_arm_VLDR_S(codeblock_t *block, int dest_reg, int base_reg, int offset); + +void host_arm_VMOV_32_S(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VMOV_64_D(codeblock_t *block, int dest_reg_low, int dest_reg_high, int src_reg); +void host_arm_VMOV_D_64(codeblock_t *block, int dest_reg, int src_reg_low, int src_reg_high); +void host_arm_VMOV_S_32(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VMOV_D_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VMOVN_I32(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VMOVN_I64(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VMRS_APSR(codeblock_t *block); +void host_arm_VMSR_FPSCR(codeblock_t *block, int src_reg); + +void host_arm_VMAX_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VMIN_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VMOV_F32_ONE(codeblock_t *block, int dst_reg); + +void host_arm_VMUL_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VMUL_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VMUL_S16(codeblock_t *block, int dest_reg, int src_reg_n, int src_reg_m); +void host_arm_VMULL_S16(codeblock_t *block, int dest_reg, int src_reg_n, int src_reg_m); + +void host_arm_VNEG_D(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VORR_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VPADDL_S16(codeblock_t *block, int dst_reg, int src_reg); +void host_arm_VPADDL_S32(codeblock_t *block, int dst_reg, int src_reg); +void host_arm_VPADDL_Q_S32(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm_VQADD_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQADD_U8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQADD_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQADD_U16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQSUB_S8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQSUB_U8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQSUB_S16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VQSUB_U16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VQMOVN_S16(codeblock_t *block, int dst_reg, int src_reg); +void host_arm_VQMOVN_S32(codeblock_t *block, int dst_reg, int src_reg); +void host_arm_VQMOVN_U16(codeblock_t *block, int dst_reg, int src_reg); + +void host_arm_VSHL_D_IMM_16(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHL_D_IMM_32(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHL_D_IMM_64(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_S16(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_S32(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_S64(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_U16(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_U32(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHR_D_U64(codeblock_t *block, int dest_reg, int src_reg, int shift); +void host_arm_VSHRN_32(codeblock_t *block, int dest_reg, int src_reg, int shift); + +void host_arm_VSQRT_D(codeblock_t *block, int dest_reg, int src_reg); +void host_arm_VSQRT_S(codeblock_t *block, int dest_reg, int src_reg); + +void host_arm_VSTR_D(codeblock_t *block, int src_reg, int base_reg, int offset); +void host_arm_VSTR_S(codeblock_t *block, int src_reg, int base_reg, int offset); +void host_arm_VSUB_D(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_F32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_S(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_I8(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_I16(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); +void host_arm_VSUB_I32(codeblock_t *block, int dst_reg, int src_reg_n, int src_reg_m); + +void host_arm_VZIP_D8(codeblock_t *block, int d_reg, int m_reg); +void host_arm_VZIP_D16(codeblock_t *block, int d_reg, int m_reg); +void host_arm_VZIP_D32(codeblock_t *block, int d_reg, int m_reg); diff --git a/src/codegen_backend_arm_uops.c b/src/codegen_backend_arm_uops.c new file mode 100644 index 0000000..19706cd --- /dev/null +++ b/src/codegen_backend_arm_uops.c @@ -0,0 +1,3500 @@ +#ifdef __ARM_EABI__ + +#include +#include "ibm.h" +#include "x86.h" +#include "x87.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_arm_defs.h" +#include "codegen_backend_arm_ops.h" +#include "codegen_ir_defs.h" + +static inline int get_arm_imm(uint32_t imm_data, uint32_t *arm_imm) +{ + int shift = 0; +//pclog("get_arm_imm - imm_data=%08x\n", imm_data); + if (!(imm_data & 0xffff)) + { + shift += 16; + imm_data >>= 16; + } + if (!(imm_data & 0xff)) + { + shift += 8; + imm_data >>= 8; + } + if (!(imm_data & 0xf)) + { + shift += 4; + imm_data >>= 4; + } + if (!(imm_data & 0x3)) + { + shift += 2; + imm_data >>= 2; + } + if (imm_data > 0xff) /*Note - should handle rotation round the word*/ + return 0; +//pclog(" imm_data=%02x shift=%i\n", imm_data, shift); + *arm_imm = imm_data | ((((32 - shift) >> 1) & 15) << 8); + return 1; +} + +static inline int in_range(void *addr, void *base) +{ + int diff = (uintptr_t)addr - (uintptr_t)base; + + if (diff < -4095 || diff > 4095) + return 0; + return 1; +} + +static inline int in_range_h(void *addr, void *base) +{ + int diff = (uintptr_t)addr - (uintptr_t)base; + + if (diff < 0 || diff > 255) + return 0; + return 1; +} + +void host_arm_call(codeblock_t *block, void *dst_addr) +{ + host_arm_MOV_IMM(block, REG_R3, (uintptr_t)dst_addr); + host_arm_BLX(block, REG_R3); +} + +void host_arm_nop(codeblock_t *block) +{ + host_arm_MOV_REG_LSL(block, REG_R0, REG_R0, 0); +} + +#define HOST_REG_GET(reg) (IREG_GET_REG(reg) & 0xf) + +#define REG_IS_L(size) (size == IREG_SIZE_L) +#define REG_IS_W(size) (size == IREG_SIZE_W) +#define REG_IS_B(size) (size == IREG_SIZE_B) +#define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) +#define REG_IS_Q(size) (size == IREG_SIZE_Q) + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_ADD_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_ADD_REG(block, REG_TEMP, src_reg_a, src_reg_b); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_ADD_REG(block, REG_TEMP, src_reg_a, src_reg_b); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_UADD8(block, dest_reg, src_reg_a, REG_TEMP); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_ADD_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_MOV_REG_LSL(block, REG_TEMP, REG_TEMP, 8); + host_arm_UADD8(block, dest_reg, src_reg_a, REG_TEMP); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_AND_IMM(block, REG_TEMP, src_reg_b, 0x0000ff00); + host_arm_UADD8(block, dest_reg, src_reg_a, REG_TEMP); + } + else + fatal("ADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ +// host_arm_ADD_IMM(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->imm_data); +// return 0; + + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_ADD_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_ADD_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && src_reg == dest_reg) + { + host_arm_MOV_IMM(block, REG_TEMP, uop->imm_data << 8); + host_arm_UADD8(block, dest_reg, src_reg, REG_TEMP); + } + else + fatal("ADD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; + +} +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + host_arm_ADD_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); + return 0; +} + +static int codegen_AND(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VAND_D(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_AND_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 16); + host_arm_BIC_REG_LSR(block, dest_reg, src_reg_a, REG_TEMP, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 24); + host_arm_BIC_REG_LSR(block, dest_reg, src_reg_a, REG_TEMP, 24); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 16); + host_arm_BIC_REG_LSR(block, dest_reg, src_reg_a, REG_TEMP, 24); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 8); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 0x0000ff00); + host_arm_BIC_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_MVN_REG_LSL(block, REG_TEMP, src_reg_b, 0); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 0x0000ff00); + host_arm_BIC_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_AND_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_AND_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_AND_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_AND_REG_LSR(block, REG_TEMP, src_reg_b, src_reg_a, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_AND_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("AND %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_AND_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm_AND_IMM(block, dest_reg, src_reg, uop->imm_data | 0xffff0000); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm_AND_IMM(block, dest_reg, src_reg, uop->imm_data | 0xffffff00); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm_AND_IMM(block, dest_reg, src_reg, (uop->imm_data << 8) | 0xffff00ff); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_AND_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_AND_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("AND_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ANDN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VBIC_D(block, dest_reg, src_reg_b, src_reg_a); + } + else + fatal("ANDN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) +{ + host_arm_call(block, uop->p); + + return 0; +} + +static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_L(dest_size)) + fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); + host_arm_call(block, uop->p); + host_arm_MOV_REG(block, dest_reg, REG_R0); + + return 0; +} + +static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) +{ + host_arm_call(block, uop->p); + host_arm_TST_REG(block, REG_R0, REG_R0); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_CMP_IMM(block, src_reg, uop->imm_data); + } + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); + host_arm_BEQ(block, (uintptr_t)uop->p); + + return 0; +} + +static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_CMP_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_CMP_IMM(block, REG_TEMP, uop->imm_data); + } + else + fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BNE_(block); + + return 0; +} +static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_CMP_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_CMP_IMM(block, REG_TEMP, uop->imm_data); + } + else + fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BEQ_(block); + + return 0; +} + +static int codegen_CMP_JB(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else + fatal("CMP_JB %02x\n", uop->src_reg_a_real); + + jump_p = host_arm_BCC_(block); + *jump_p |= ((((uintptr_t)uop->p - (uintptr_t)jump_p) - 8) & 0x3fffffc) >> 2; + + return 0; +} +static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else + fatal("CMP_JNBE %02x\n", uop->src_reg_a_real); + + jump_p = host_arm_BHI_(block); + *jump_p |= ((((uintptr_t)uop->p - (uintptr_t)jump_p) - 8) & 0x3fffffc) >> 2; + + return 0; +} + +static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BCS_(block); + + return 0; +} +static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BHI_(block); + + return 0; +} +static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BGE_(block); + + return 0; +} +static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BGT_(block); + + return 0; +} +static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BVC_(block); + + return 0; +} +static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BNE_(block); + + return 0; +} +static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BCC_(block); + + return 0; +} +static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BLS_(block); + + return 0; +} +static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BLT_(block); + + return 0; +} +static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BLE_(block); + + return 0; +} +static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BVS_(block); + + return 0; +} +static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_CMP_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 16); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 16); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg_a, 24); + host_arm_CMP_REG_LSL(block, REG_TEMP, src_reg_b, 24); + } + else + fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BEQ_(block); + + return 0; +} + +static int codegen_FABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VABS_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FCHS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VNEG_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VSQRT_D(block, dest_reg, src_reg_a); + } + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_FTST(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_arm_VSUB_D(block, REG_D_TEMP, REG_D_TEMP, REG_D_TEMP); + host_arm_VCMP_D(block, src_reg_a, REG_D_TEMP); + host_arm_MOV_IMM(block, dest_reg, 0); + host_arm_VMRS_APSR(block); + host_arm_ORREQ_IMM(block, dest_reg, dest_reg, C3); + host_arm_ORRCC_IMM(block, dest_reg, dest_reg, C0); + host_arm_ORRVS_IMM(block, dest_reg, dest_reg, C0|C2|C3); + } + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VADD_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FCOM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VCMP_D(block, src_reg_a, src_reg_b); + host_arm_MOV_IMM(block, dest_reg, 0); + host_arm_VMRS_APSR(block); + host_arm_ORREQ_IMM(block, dest_reg, dest_reg, C3); + host_arm_ORRCC_IMM(block, dest_reg, dest_reg, C0); + host_arm_ORRVS_IMM(block, dest_reg, dest_reg, C0|C2|C3); + } + else + fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VDIV_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VMUL_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_arm_VSUB_D(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range(&cr0, &cpu_state)) + fatal("codegen_FP_ENTER - out of range\n"); + + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm_BEQ_(block); + + host_arm_MOV_IMM(block, REG_TEMP, uop->imm_data); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm_MOV_IMM(block, REG_ARG0, 7); + host_arm_call(block, x86_int); + host_arm_B(block, (uintptr_t)codegen_exit_rout); + + *branch_ptr |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_ptr) - 8) & 0x3fffffc) >> 2; + + return 0; +} +static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_ptr; + + if (!in_range(&cr0, &cpu_state)) + fatal("codegen_MMX_ENTER - out of range\n"); + + host_arm_LDR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cr0 - (uintptr_t)&cpu_state); + host_arm_TST_IMM(block, REG_TEMP, 0xc); + branch_ptr = host_arm_BEQ_(block); + + host_arm_MOV_IMM(block, REG_TEMP, uop->imm_data); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.oldpc - (uintptr_t)&cpu_state); + host_arm_MOV_IMM(block, REG_ARG0, 7); + host_arm_call(block, x86_int); + host_arm_B(block, (uintptr_t)codegen_exit_rout); + + *branch_ptr |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_ptr) - 8) & 0x3fffffc) >> 2; + + host_arm_MOV_IMM(block, REG_TEMP, 0x01010101); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[0] - (uintptr_t)&cpu_state); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.tag[4] - (uintptr_t)&cpu_state); + host_arm_MOV_IMM(block, REG_TEMP, 0); + host_arm_STR_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.TOP - (uintptr_t)&cpu_state); + host_arm_STRB_IMM(block, REG_TEMP, REG_CPUSTATE, (uintptr_t)&cpu_state.ismmx - (uintptr_t)&cpu_state); + + return 0; +} + +static int codegen_JMP(codeblock_t *block, uop_t *uop) +{ + host_arm_B(block, (uintptr_t)uop->p); + + return 0; +} + +static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_ARG0, src_reg, 0); + } + else + fatal("codegen_LOAD_FUNC_ARG0 %02x\n", uop->src_reg_a_real); + + return 0; +} +static int codegen_LOAD_FUNC_ARG1(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG1 %02x\n", uop->src_reg_a_real); + return 0; +} +static int codegen_LOAD_FUNC_ARG2(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG2 %02x\n", uop->src_reg_a_real); + return 0; +} +static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) +{ + fatal("codegen_LOAD_FUNC_ARG3 %02x\n", uop->src_reg_a_real); + return 0; +} + +static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_ARG0, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_ARG1, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG2_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_ARG2, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_ARG3, uop->imm_data); + return 0; +} + +static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (!REG_IS_W(src_size)) + fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); + host_arm_UXTH(block, REG_ARG0, src_reg, 0); + host_arm_MOV_IMM(block, REG_ARG1, (uint32_t)uop->p); + host_arm_call(block, loadseg); + host_arm_TST_REG(block, REG_R0, REG_R0); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_ADD_IMM(block, REG_R0, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_long); + } + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm_MOV_REG(block, dest_reg, REG_R0); + } + + return 0; +} + +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + if (REG_IS_B(dest_size) || REG_IS_BH(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_long); + } + else if (REG_IS_Q(dest_size)) + { + host_arm_BL(block, (uintptr_t)codegen_mem_load_quad); + } + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 8); + } + else if (REG_IS_BH(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 8, 8); + } + else if (REG_IS_W(dest_size)) + { + host_arm_BFI(block, dest_reg, REG_R0, 0, 16); + } + else if (REG_IS_L(dest_size)) + { + host_arm_MOV_REG(block, dest_reg, REG_R0); + } + else if (REG_IS_Q(dest_size)) + { + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + } + + return 0; +} +static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_SINGLE - %02x\n", uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_load_single); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + host_arm_VCVT_D_S(block, dest_reg, REG_D_TEMP); + + return 0; +} +static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_load_double); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_arm_ADD_IMM(block, REG_R0, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_long); + } + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_byte); + } + else if (REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_R1, src_reg, 8); + host_arm_BL(block, (uintptr_t)codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_arm_MOV_REG(block, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_long); + } + else if (REG_IS_Q(src_size)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_quad); + } + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_c_real); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_store_byte); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_store_word); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + host_arm_MOV_IMM(block, REG_R1, uop->imm_data); + host_arm_BL(block, (uintptr_t)codegen_mem_store_long); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + host_arm_VCVT_S_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_single); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_REG - %02x\n", uop->dest_reg_a_real); + + host_arm_ADD_REG(block, REG_R0, seg_reg, addr_reg); + if (uop->imm_data) + host_arm_ADD_IMM(block, REG_R0, REG_R0, uop->imm_data); + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_mem_store_double); + host_arm_TST_REG(block, REG_R1, REG_R1); + host_arm_BNE(block, (uintptr_t)codegen_exit_rout); + + return 0; +} + +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSL(block, dest_reg, src_reg, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_BFI(block, dest_reg, src_reg, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_BFI(block, dest_reg, src_reg, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_B(src_size)) + { + host_arm_BFI(block, dest_reg, src_reg, 8, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size)) + { + host_arm_VMOV_D_D(block, dest_reg, src_reg); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + host_arm_VMOV_D_D(block, dest_reg, src_reg); + } + else + fatal("MOV %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_arm_MOV_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size)) + { + host_arm_MOVW_IMM(block, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size)) + { + host_arm_AND_IMM(block, dest_reg, dest_reg, ~0x000000ff); + host_arm_ORR_IMM(block, dest_reg, dest_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size)) + { + host_arm_AND_IMM(block, dest_reg, dest_reg, ~0x0000ff00); + host_arm_ORR_IMM(block, dest_reg, dest_reg, uop->imm_data << 8); + } + else + fatal("MOV_IMM %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, uop->dest_reg_a_real, (uintptr_t)uop->p); + + return 0; +} + +static int codegen_MOVSX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_arm_SXTB(block, dest_reg, src_reg, 0); + } + else if (REG_IS_L(dest_size) && REG_IS_BH(src_size)) + { + host_arm_SXTB(block, dest_reg, src_reg, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_arm_SXTH(block, dest_reg, src_reg, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_arm_SXTB(block, REG_TEMP, src_reg, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_W(dest_size) && REG_IS_BH(src_size)) + { + host_arm_SXTB(block, REG_TEMP, src_reg, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVSX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOVZX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_IMM(block, REG_TEMP, 0); + host_arm_VMOV_D_64(block, dest_reg, src_reg, REG_TEMP); + } + else if (REG_IS_L(dest_size) && REG_IS_Q(src_size)) + { + host_arm_VMOV_32_S(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_arm_UXTB(block, dest_reg, src_reg, 0); + } + else if (REG_IS_L(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, dest_reg, src_reg, 8); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, dest_reg, src_reg, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + if (src_reg == dest_reg) + host_arm_BIC_IMM(block, dest_reg, dest_reg, 0xff00); + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_W(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg, 8); + host_arm_BIC_IMM(block, dest_reg, dest_reg, 0xff00); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("MOVZX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static double int64_to_double(int64_t a) +{ + return (double)a; +} +static int codegen_MOV_DOUBLE_INT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_L(src_size)) + { + host_arm_VMOV_S_32(block, REG_D_TEMP, src_reg); + host_arm_VCVT_D_IS(block, dest_reg, REG_D_TEMP); + } + else if (REG_IS_D(dest_size) && REG_IS_W(src_size)) + { + host_arm_SXTH(block, REG_TEMP, src_reg, 0); + host_arm_VMOV_S_32(block, REG_D_TEMP, REG_TEMP); + host_arm_VCVT_D_IS(block, dest_reg, REG_D_TEMP); + } + else if (REG_IS_D(dest_size) && REG_IS_Q(src_size)) + { + /*ARMv7 has no instructions to convert a 64-bit integer to a double. + For simplicity, call a C function and let the compiler do it.*/ + host_arm_VMOV_64_D(block, REG_R0, REG_R1, src_reg); + host_arm_BL(block, (uintptr_t)int64_to_double); /*Input - R0/R1, Output - D0*/ + host_arm_VMOV_D_D(block, dest_reg, REG_D0); + } + else + fatal("MOV_DOUBLE_INT %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_D(src_size)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_fp_round); + host_arm_VMOV_32_S(block, dest_reg, REG_D_TEMP); + } + else if (REG_IS_W(dest_size) && REG_IS_D(src_size)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg); + host_arm_BL(block, (uintptr_t)codegen_fp_round); + host_arm_VMOV_32_S(block, REG_TEMP, REG_D_TEMP); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOV_INT_DOUBLE %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int64_t x87_fround64(double b) +{ + int64_t a, c; + + switch ((cpu_state.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; + } + + return 0; +} +static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), src_64_reg = HOST_REG_GET(uop->src_reg_b_real), tag_reg = HOST_REG_GET(uop->src_reg_c_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real), src_64_size = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_D(src_size) && REG_IS_Q(src_64_size)) + { + uint32_t *branch_offset; + + /*If TAG_UINT64 is set then the source is MM[]. Otherwise it is a double in ST()*/ + host_arm_VMOV_D_D(block, dest_reg, src_64_reg); + host_arm_TST_IMM(block, tag_reg, TAG_UINT64); + branch_offset = host_arm_BNE_(block); + + /*VFP/NEON has no instructions to convert a float to 64-bit integer, + so call out to C.*/ + host_arm_VMOV_D_D(block, REG_D0, src_reg); + host_arm_call(block, x87_fround64); + host_arm_VMOV_D_64(block, REG_D_TEMP, REG_R0, REG_R1); + + *branch_offset |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 8) & 0x3fffffc) >> 2; + } + else + fatal("MOV_INT_DOUBLE_64 %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_MOV_IMM(block, REG_TEMP, (uintptr_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm_LDR_IMM(block, dest_reg, REG_TEMP, 0); + } + else + fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_MOV_IMM(block, REG_TEMP, (uintptr_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm_LDRB_IMM(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size)) + { + host_arm_LDRB_IMM(block, REG_TEMP, REG_TEMP, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size)) + { + host_arm_LDRB_IMM(block, REG_TEMP, REG_TEMP, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else + fatal("MOVZX_REG_PTR_8 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_16(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_arm_MOV_IMM(block, REG_TEMP, (uintptr_t)uop->p); + if (REG_IS_L(dest_size)) + { + host_arm_LDRH_IMM(block, dest_reg, REG_TEMP, 0); + } + else if (REG_IS_W(dest_size)) + { + host_arm_LDRH_IMM(block, REG_TEMP, REG_TEMP, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else + fatal("MOVZX_REG_PTR_16 %02x\n", uop->dest_reg_a_real); + + return 0; +} + +static int codegen_NOP(codeblock_t *block, uop_t *uop) +{ + return 0; +} + +static int codegen_OR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VORR_D(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_ORR_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_ORR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else + fatal("OR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm_ORR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm_ORR_IMM(block, dest_reg, src_reg, uop->imm_data << 8); + } + else + fatal("OR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_PACKSSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_Q_TEMP, src_reg_a); + host_arm_VMOV_D_D(block, REG_Q_TEMP_2, src_reg_b); + host_arm_VQMOVN_S16(block, dest_reg, REG_Q_TEMP); + host_arm_VQMOVN_S16(block, REG_D_TEMP, REG_Q_TEMP_2); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + } + else + fatal("PACKSSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PACKSSDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_Q_TEMP, src_reg_a); + host_arm_VMOV_D_D(block, REG_Q_TEMP_2, src_reg_b); + host_arm_VQMOVN_S32(block, dest_reg, REG_Q_TEMP); + host_arm_VQMOVN_S32(block, REG_D_TEMP, REG_Q_TEMP_2); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + } + else + fatal("PACKSSDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PACKUSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_Q_TEMP, src_reg_a); + host_arm_VMOV_D_D(block, REG_Q_TEMP_2, src_reg_b); + host_arm_VQMOVN_U16(block, dest_reg, REG_Q_TEMP); + host_arm_VQMOVN_U16(block, REG_D_TEMP, REG_Q_TEMP_2); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + } + else + fatal("PACKUSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PADDB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VADD_I8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VADD_I16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VADD_I32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQADD_S8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQADD_S16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQADD_U8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PADDUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQADD_U16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PADDUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PCMPEQB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCEQ_I8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPEQW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCEQ_I16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPEQD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCEQ_I32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPEQD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGT_S8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGT_S16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PCMPGTD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGT_S32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PCMPGTD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PF2ID(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_arm_VCVT_S32_F32(block, dest_reg, src_reg_a); + } + else + fatal("PF2ID %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VADD_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPEQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCEQ_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPEQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPGE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGE_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPGE %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFCMPGT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VCGT_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFCMPGT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMAX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMAX_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMAX %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMIN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMIN_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMIN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMUL_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PFRCP(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use VRECPE/VRECPS)*/ + host_arm_VMOV_F32_ONE(block, REG_D_TEMP); + host_arm_VDIV_S(block, dest_reg, REG_D_TEMP, src_reg_a); + host_arm_VDUP_32(block, dest_reg, dest_reg, 0); + } + else + fatal("PFRCP %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFRSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use VRSQRTE/VRSQRTS)*/ + host_arm_VSQRT_S(block, REG_D_TEMP, src_reg_a); + host_arm_VMOV_F32_ONE(block, REG_D_TEMP); + host_arm_VDIV_S(block, dest_reg, dest_reg, REG_D_TEMP); + host_arm_VDUP_32(block, dest_reg, dest_reg, 0); + } + else + fatal("PFRSQRT %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_PFSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VSUB_F32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PFSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PI2FD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_arm_VCVT_F32_S32(block, dest_reg, src_reg_a); + } + else + fatal("PI2FD %02x %02x\n", uop->dest_reg_a_real); + + return 0; +} + +static int codegen_PMADDWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMULL_S16(block, REG_Q_TEMP, src_reg_a, src_reg_b); + host_arm_VPADDL_Q_S32(block, REG_Q_TEMP, REG_Q_TEMP); + host_arm_VMOVN_I64(block, dest_reg, REG_Q_TEMP); + } + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PMULHW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMULL_S16(block, REG_Q_TEMP, src_reg_a, src_reg_b); + host_arm_VSHRN_32(block, dest_reg, REG_Q_TEMP, 16); + } + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PMULLW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMUL_S16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PMULLW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PSLLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHL_D_IMM_16(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSLLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHL_D_IMM_32(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSLLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHL_D_IMM_64(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSLLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm_VSHR_D_S16(block, dest_reg, src_reg, 15); + else + host_arm_VSHR_D_S16(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm_VSHR_D_S32(block, dest_reg, src_reg, 31); + else + host_arm_VSHR_D_S32(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRAQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm_VSHR_D_S64(block, dest_reg, src_reg, 63); + else + host_arm_VSHR_D_S64(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRAQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 15) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHR_D_U16(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 31) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHR_D_U32(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_PSRLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + if (uop->imm_data == 0) + host_arm_VMOV_D_D(block, dest_reg, src_reg); + else if (uop->imm_data > 63) + host_arm_VEOR_D(block, dest_reg, dest_reg, dest_reg); + else + host_arm_VSHR_D_U64(block, dest_reg, src_reg, uop->imm_data); + } + else + fatal("PSRLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_PSUBB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VSUB_I8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VSUB_I16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VSUB_I32(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQSUB_S8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQSUB_S16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQSUB_U8(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PSUBUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VQSUB_U16(block, dest_reg, src_reg_a, src_reg_b); + } + else + fatal("PSUBUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_PUNPCKHBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D8(block, dest_reg, REG_D_TEMP); + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKHBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKHWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D16(block, dest_reg, REG_D_TEMP); + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKHWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKHDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + host_arm_VMOV_D_D(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKHDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D8(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKLBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D16(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKLWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_PUNPCKLDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VMOV_D_D(block, REG_D_TEMP, src_reg_b); + if (dest_reg != src_reg_a) + host_arm_VMOV_D_D(block, dest_reg, src_reg_a); + host_arm_VZIP_D32(block, dest_reg, REG_D_TEMP); + } + else + fatal("PUNPCKLDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} + +static int codegen_ROL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_RSB_IMM(block, REG_TEMP2, shift_reg, 32); + host_arm_MOV_REG_ROR_REG(block, dest_reg, src_reg, REG_TEMP2); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_RSB_IMM(block, REG_TEMP2, shift_reg, 16); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm_MOV_REG_ROR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_RSB_IMM(block, REG_TEMP2, shift_reg, 8); + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_AND_IMM(block, REG_TEMP2, REG_TEMP2, 7); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_RSB_IMM(block, REG_TEMP2, shift_reg, 8); + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_AND_IMM(block, REG_TEMP2, REG_TEMP2, 7); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ROL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (!(uop->imm_data & 31)) + { + if (src_reg != dest_reg) + host_arm_MOV_REG(block, dest_reg, src_reg); + } + else + { + host_arm_MOV_REG_ROR(block, dest_reg, src_reg, 32 - (uop->imm_data & 31)); + } + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if ((uop->imm_data & 15) == 0) + { + if (src_reg != dest_reg) + host_arm_BFI(block, dest_reg, src_reg, 0, 16); + } + else + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 16-(uop->imm_data & 15)); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + host_arm_BFI(block, dest_reg, src_reg, 0, 8); + } + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8-(uop->imm_data & 7)); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8-(uop->imm_data & 7)); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + } + else + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_ROR_REG(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_AND_IMM(block, REG_TEMP2, shift_reg, 15); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_AND_IMM(block, REG_TEMP2, shift_reg, 7); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_AND_IMM(block, REG_TEMP2, shift_reg, 7); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, REG_TEMP2); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("ROR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_ROR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (!(uop->imm_data & 31)) + { + if (src_reg != dest_reg) + host_arm_MOV_REG(block, dest_reg, src_reg); + } + else + { + host_arm_MOV_REG_ROR(block, dest_reg, src_reg, uop->imm_data & 31); + } + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if ((uop->imm_data & 15) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 16); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 15); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 7); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + if ((uop->imm_data & 7) == 0) + { + if (src_reg != dest_reg) + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + } + else + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_ORR_REG_LSL(block, REG_TEMP, REG_TEMP, REG_TEMP, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data & 7); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + } + else + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_SAR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_ASR_REG(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 16); + host_arm_MOV_REG_ASR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_UXTH(block, REG_TEMP, REG_TEMP, 16); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 24); + host_arm_MOV_REG_ASR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_UXTB(block, REG_TEMP, REG_TEMP, 24); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 16); + host_arm_MOV_REG_ASR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_UXTB(block, REG_TEMP, REG_TEMP, 24); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SAR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SAR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_ASR(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 16); + host_arm_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_UXTH(block, REG_TEMP, REG_TEMP, 16); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 24); + host_arm_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_UXTB(block, REG_TEMP, REG_TEMP, 24); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, 16); + host_arm_MOV_REG_ASR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_UXTB(block, REG_TEMP, REG_TEMP, 24); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SAR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSL_REG(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_MOV_REG_LSL_REG(block, REG_TEMP, src_reg, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_MOV_REG_LSL_REG(block, REG_TEMP, src_reg, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_MOV_REG_LSL_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSL(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_MOV_REG_LSL(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_MOV_REG_LSL(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSR_REG(block, dest_reg, src_reg, shift_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_MOV_REG_LSR_REG(block, REG_TEMP, REG_TEMP, shift_reg); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} +static int codegen_SHR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_MOV_REG_LSR(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_UXTH(block, REG_TEMP, src_reg, 0); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 0); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_UXTB(block, REG_TEMP, src_reg, 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SHR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_R0, uop->imm_data); + + if (in_range(uop->p, &cpu_state)) + host_arm_STR_IMM(block, REG_R0, REG_CPUSTATE, (uintptr_t)uop->p - (uintptr_t)&cpu_state); + else + fatal("codegen_STORE_PTR_IMM - not in range\n"); + + return 0; +} +static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) +{ + host_arm_MOV_IMM(block, REG_R0, uop->imm_data); + if (in_range(uop->p, &cpu_state)) + host_arm_STRB_IMM(block, REG_R0, REG_CPUSTATE, (uintptr_t)uop->p - (uintptr_t)&cpu_state); + else + fatal("codegen_STORE_PTR_IMM - not in range\n"); + + return 0; +} + +static int codegen_SUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_SUB_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_arm_SUB_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_SUB_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_SUB_REG_LSR(block, REG_TEMP, src_reg_a, src_reg_b, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_RSB_REG_LSR(block, REG_TEMP, src_reg_b, src_reg_a, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_SUB_REG_LSL(block, REG_TEMP, src_reg_a, src_reg_b, 0); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b)) + { + host_arm_RSB_REG_LSR(block, REG_TEMP, src_reg_b, src_reg_a, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b)) + { + host_arm_MOV_REG_LSR(block, REG_TEMP, src_reg_a, 8); + host_arm_SUB_REG_LSR(block, REG_TEMP, REG_TEMP, src_reg_b, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; + +// host_arm_SUB_REG_LSL(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, 0); +// return 0; +} +static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_SUB_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_arm_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 16); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_arm_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_B(dest_size) && REG_IS_BH(src_size)) + { + host_arm_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 0, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size)) + { + host_arm_SUB_IMM(block, REG_TEMP, src_reg, uop->imm_data << 8); + host_arm_MOV_REG_LSR(block, REG_TEMP, REG_TEMP, 8); + host_arm_BFI(block, dest_reg, REG_TEMP, 8, 8); + } + else + fatal("SUB_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 31); + } + else if (REG_IS_W(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 15); + } + else if (REG_IS_B(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 7); + } + else + fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BEQ_(block); + + return 0; +} +static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 31); + } + else if (REG_IS_W(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 15); + } + else if (REG_IS_B(src_size)) + { + host_arm_TST_IMM(block, src_reg, 1 << 7); + } + else + fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real); + + uop->p = host_arm_BNE_(block); + + return 0; +} + +static int codegen_XOR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_arm_VEOR_D(block, dest_reg, src_reg_a, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, src_reg_b, 0); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTH(block, REG_TEMP, src_reg_b, 0); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 0); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_B(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 0); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size_a) && REG_IS_BH(src_size_b) && dest_reg == src_reg_a) + { + host_arm_UXTB(block, REG_TEMP, src_reg_b, 8); + host_arm_EOR_REG_LSL(block, dest_reg, src_reg_a, REG_TEMP, 8); + } + else + fatal("XOR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + + return 0; +} +static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_arm_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && dest_reg == src_reg) + { + host_arm_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && dest_reg == src_reg) + { + host_arm_EOR_IMM(block, dest_reg, src_reg, uop->imm_data); + } + else if (REG_IS_BH(dest_size) && REG_IS_BH(src_size) && dest_reg == src_reg) + { + host_arm_EOR_IMM(block, dest_reg, src_reg, uop->imm_data << 8); + } + else + fatal("XOR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); + + return 0; +} + +const uOpFn uop_handlers[UOP_MAX] = +{ + [UOP_CALL_FUNC & UOP_MASK] = codegen_CALL_FUNC, + [UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT, + [UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC, + + [UOP_JMP & UOP_MASK] = codegen_JMP, + + [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, + + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, + [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, + [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, + [UOP_LOAD_FUNC_ARG_3 & UOP_MASK] = codegen_LOAD_FUNC_ARG3, + + [UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM, + [UOP_LOAD_FUNC_ARG_1_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG1_IMM, + [UOP_LOAD_FUNC_ARG_2_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG2_IMM, + [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, + + [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, + [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, + [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, + [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, + + [UOP_MOV & UOP_MASK] = codegen_MOV, + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + [UOP_MOVSX & UOP_MASK] = codegen_MOVSX, + [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, + [UOP_MOV_DOUBLE_INT & UOP_MASK] = codegen_MOV_DOUBLE_INT, + [UOP_MOV_INT_DOUBLE & UOP_MASK] = codegen_MOV_INT_DOUBLE, + [UOP_MOV_INT_DOUBLE_64 & UOP_MASK] = codegen_MOV_INT_DOUBLE_64, + [UOP_MOV_REG_PTR & UOP_MASK] = codegen_MOV_REG_PTR, + [UOP_MOVZX_REG_PTR_8 & UOP_MASK] = codegen_MOVZX_REG_PTR_8, + [UOP_MOVZX_REG_PTR_16 & UOP_MASK] = codegen_MOVZX_REG_PTR_16, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND & UOP_MASK] = codegen_AND, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM, + [UOP_ANDN & UOP_MASK] = codegen_ANDN, + [UOP_OR & UOP_MASK] = codegen_OR, + [UOP_OR_IMM & UOP_MASK] = codegen_OR_IMM, + [UOP_SUB & UOP_MASK] = codegen_SUB, + [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, + [UOP_XOR & UOP_MASK] = codegen_XOR, + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_SAR & UOP_MASK] = codegen_SAR, + [UOP_SAR_IMM & UOP_MASK] = codegen_SAR_IMM, + [UOP_SHL & UOP_MASK] = codegen_SHL, + [UOP_SHL_IMM & UOP_MASK] = codegen_SHL_IMM, + [UOP_SHR & UOP_MASK] = codegen_SHR, + [UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM, + [UOP_ROL & UOP_MASK] = codegen_ROL, + [UOP_ROL_IMM & UOP_MASK] = codegen_ROL_IMM, + [UOP_ROR & UOP_MASK] = codegen_ROR, + [UOP_ROR_IMM & UOP_MASK] = codegen_ROR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ, + + [UOP_CMP_JB & UOP_MASK] = codegen_CMP_JB, + [UOP_CMP_JNBE & UOP_MASK] = codegen_CMP_JNBE, + + [UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST, + [UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST, + [UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST, + [UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST, + [UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST, + [UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST, + [UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST, + [UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST, + [UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST, + [UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST, + [UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST, + [UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST, + + [UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST, + [UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST, + + [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, + [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FCOM & UOP_MASK] = codegen_FCOM, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, + [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, + [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, + + [UOP_PADDB & UOP_MASK] = codegen_PADDB, + [UOP_PADDW & UOP_MASK] = codegen_PADDW, + [UOP_PADDD & UOP_MASK] = codegen_PADDD, + [UOP_PADDSB & UOP_MASK] = codegen_PADDSB, + [UOP_PADDSW & UOP_MASK] = codegen_PADDSW, + [UOP_PADDUSB & UOP_MASK] = codegen_PADDUSB, + [UOP_PADDUSW & UOP_MASK] = codegen_PADDUSW, + + [UOP_PCMPEQB & UOP_MASK] = codegen_PCMPEQB, + [UOP_PCMPEQW & UOP_MASK] = codegen_PCMPEQW, + [UOP_PCMPEQD & UOP_MASK] = codegen_PCMPEQD, + [UOP_PCMPGTB & UOP_MASK] = codegen_PCMPGTB, + [UOP_PCMPGTW & UOP_MASK] = codegen_PCMPGTW, + [UOP_PCMPGTD & UOP_MASK] = codegen_PCMPGTD, + + [UOP_PF2ID & UOP_MASK] = codegen_PF2ID, + [UOP_PFADD & UOP_MASK] = codegen_PFADD, + [UOP_PFCMPEQ & UOP_MASK] = codegen_PFCMPEQ, + [UOP_PFCMPGE & UOP_MASK] = codegen_PFCMPGE, + [UOP_PFCMPGT & UOP_MASK] = codegen_PFCMPGT, + [UOP_PFMAX & UOP_MASK] = codegen_PFMAX, + [UOP_PFMIN & UOP_MASK] = codegen_PFMIN, + [UOP_PFMUL & UOP_MASK] = codegen_PFMUL, + [UOP_PFRCP & UOP_MASK] = codegen_PFRCP, + [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, + [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, + [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, + + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, + [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, + [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, + + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, + [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, + [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, + [UOP_PSRAW_IMM & UOP_MASK] = codegen_PSRAW_IMM, + [UOP_PSRAD_IMM & UOP_MASK] = codegen_PSRAD_IMM, + [UOP_PSRAQ_IMM & UOP_MASK] = codegen_PSRAQ_IMM, + [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, + [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, + [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, + + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, + [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, + [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, + [UOP_PSUBSB & UOP_MASK] = codegen_PSUBSB, + [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, + [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, + [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, + + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, + [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, + [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, + [UOP_PUNPCKLBW & UOP_MASK] = codegen_PUNPCKLBW, + [UOP_PUNPCKLWD & UOP_MASK] = codegen_PUNPCKLWD, + [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, + + [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP +}; + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + if (in_range_h(p, &cpu_state)) + host_arm_LDRB_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_8 - not in range\n"); +} +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) +{ + if (in_range_h(p, &cpu_state)) + host_arm_LDRH_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + { + host_arm_MOV_IMM(block, REG_R3, (uintptr_t)p - (uintptr_t)&cpu_state); + host_arm_LDRH_REG(block, host_reg, REG_CPUSTATE, REG_R3); + } +} +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + if (in_range(p, &cpu_state)) + host_arm_LDR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_read_32 - not in range\n"); +} +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p) +{ + codegen_direct_read_32(block, host_reg, p); +} +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p) +{ + host_arm_VLDR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_arm_VLDR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_LDRB_IMM(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VLDR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VLDR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STRB_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_8 - not in range\n"); +} +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg) +{ + if (in_range_h(p, &cpu_state)) + host_arm_STRH_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + { + host_arm_MOV_IMM(block, REG_R3, (uintptr_t)p - (uintptr_t)&cpu_state); + host_arm_STRH_REG(block, host_reg, REG_CPUSTATE, REG_R3); + } +} +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_32 - not in range\n"); +} +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); +} +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_STRB_IMM(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VSTR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + host_arm_LDR_IMM(block, REG_TEMP, REG_HOST_SP, IREG_TOP_diff_stack_offset); + host_arm_ADD_IMM(block, REG_TEMP, REG_TEMP, reg_idx); + host_arm_AND_IMM(block, REG_TEMP, REG_TEMP, 7); + host_arm_ADD_REG_LSL(block, REG_TEMP, REG_CPUSTATE, REG_TEMP, 3); + host_arm_VSTR_D(block, host_reg, REG_TEMP, (uintptr_t)base - (uintptr_t)&cpu_state); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + if (in_range(p, &cpu_state)) + host_arm_STR_IMM(block, host_reg, REG_CPUSTATE, (uintptr_t)p - (uintptr_t)&cpu_state); + else + fatal("codegen_direct_write_ptr - not in range\n"); +} + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (stack_offset >= 0 && stack_offset < 256) + host_arm_LDRH_IMM(block, host_reg, REG_HOST_SP, stack_offset); + else + fatal("codegen_direct_read_32 - not in range\n"); +} +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + if (stack_offset >= 0 && stack_offset < 4096) + host_arm_LDR_IMM(block, host_reg, REG_HOST_SP, stack_offset); + else + fatal("codegen_direct_read_32 - not in range\n"); +} +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + codegen_direct_read_32_stack(block, host_reg, stack_offset); +} +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_arm_VLDR_D(block, host_reg, REG_HOST_SP, stack_offset); +} +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_arm_VLDR_D(block, host_reg, REG_HOST_SP, stack_offset); +} + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + if (stack_offset >= 0 && stack_offset < 4096) + host_arm_STR_IMM(block, host_reg, REG_HOST_SP, stack_offset); + else + fatal("codegen_direct_write_32 - not in range\n"); +} +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_HOST_SP, stack_offset); +} +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_arm_VSTR_D(block, host_reg, REG_HOST_SP, stack_offset); +} + +void codegen_set_jump_dest(codeblock_t *block, void *p) +{ + *(uint32_t *)p |= ((((uintptr_t)&block_write_data[block_pos] - (uintptr_t)p) - 8) & 0x3fffffc) >> 2; +} +#endif diff --git a/src/codegen_backend_x86-64.c b/src/codegen_backend_x86-64.c new file mode 100644 index 0000000..a214b69 --- /dev/null +++ b/src/codegen_backend_x86-64.c @@ -0,0 +1,383 @@ +#ifdef __amd64__ + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" +#include "codegen_backend_x86-64_ops_sse.h" +#include "codegen_reg.h" +#include "x86.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; +void *codegen_mem_load_quad; +void *codegen_mem_load_single; +void *codegen_mem_load_double; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; +void *codegen_mem_store_quad; +void *codegen_mem_store_single; +void *codegen_mem_store_double; + +void *codegen_gpf_rout; +void *codegen_exit_rout; + +host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + /*Note: while EAX and EDX are normally volatile registers under x86 + calling conventions, the recompiler will explicitly save and restore + them across funcion calls*/ + {REG_EAX, 0}, + {REG_EBX, 0}, + {REG_EDX, 0} +}; + +host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ +#if WIN64 + /*Windows x86-64 calling convention preserves XMM6-XMM15*/ + {REG_XMM6, 0}, + {REG_XMM7, 0}, +#else + /*System V AMD64 calling convention does not preserve any XMM registers*/ + {REG_XMM6, HOST_REG_FLAG_VOLATILE}, + {REG_XMM7, HOST_REG_FLAG_VOLATILE}, +#endif + {REG_XMM1, HOST_REG_FLAG_VOLATILE}, + {REG_XMM2, HOST_REG_FLAG_VOLATILE}, + {REG_XMM3, HOST_REG_FLAG_VOLATILE}, + {REG_XMM4, HOST_REG_FLAG_VOLATILE}, + {REG_XMM5, HOST_REG_FLAG_VOLATILE} +}; + +static void build_load_routine(codeblock_t *block, int size, int is_float) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - ESI = address + Out - ECX = data, ESI = abrt*/ + /*MOV ECX, ESI + SHR ESI, 12 + MOV RSI, [readlookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOVZX ECX, B[RSI+RCX] + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL readmembl + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_ECX, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV64_REG_IMM(block, REG_RDI, (uint64_t)(uintptr_t)readlookup2); + host_x86_MOV64_REG_BASE_INDEX_SHIFT(block, REG_RSI, REG_RDI, REG_RSI, 3); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_ECX, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP64_REG_IMM(block, REG_RSI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1 && !is_float) + host_x86_MOVZX_BASE_INDEX_32_8(block, REG_ECX, REG_RSI, REG_RCX); + else if (size == 2 && !is_float) + host_x86_MOVZX_BASE_INDEX_32_16(block, REG_ECX, REG_RSI, REG_RCX); + else if (size == 4 && !is_float) + host_x86_MOV32_REG_BASE_INDEX(block, REG_ECX, REG_RSI, REG_RCX); + else if (size == 4 && is_float) + host_x86_CVTSS2SD_XREG_BASE_INDEX(block, REG_XMM_TEMP, REG_RSI, REG_RCX); + else if (size == 8) + host_x86_MOVQ_XREG_BASE_INDEX(block, REG_XMM_TEMP, REG_RSI, REG_RCX); + else + fatal("build_load_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_RAX); + host_x86_PUSH(block, REG_RDX); +#if WIN64 + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x20); + //host_x86_MOV32_REG_REG(block, REG_ECX, uop->imm_data); +#else + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ECX); +#endif + if (size == 1 && !is_float) + { + host_x86_CALL(block, (void *)readmembl); + host_x86_MOVZX_REG_32_8(block, REG_ECX, REG_EAX); + } + else if (size == 2 && !is_float) + { + host_x86_CALL(block, (void *)readmemwl); + host_x86_MOVZX_REG_32_16(block, REG_ECX, REG_EAX); + } + else if (size == 4 && !is_float) + { + host_x86_CALL(block, (void *)readmemll); + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + } + else if (size == 4 && is_float) + { + host_x86_CALL(block, (void *)readmemll); + host_x86_MOVD_XREG_REG(block, REG_XMM_TEMP, REG_EAX); + host_x86_CVTSS2SD_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + } + else if (size == 8) + { + host_x86_CALL(block, (void *)readmemql); + host_x86_MOVQ_XREG_REG(block, REG_XMM_TEMP, REG_RAX); + } +#if WIN64 + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x20); +#endif + host_x86_POP(block, REG_RDX); + host_x86_POP(block, REG_RAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); +} + +static void build_store_routine(codeblock_t *block, int size, int is_float) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset; + + /*In - ECX = data, ESI = address + Out - ESI = abrt + Corrupts EDI*/ + /*MOV EDI, ESI + SHR ESI, 12 + MOV ESI, [writelookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOV [RSI+RDI], ECX + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL writemembl + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV64_REG_IMM(block, REG_R8, (uint64_t)(uintptr_t)writelookup2); + host_x86_MOV64_REG_BASE_INDEX_SHIFT(block, REG_RSI, REG_R8, REG_RSI, 3); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_EDI, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP64_REG_IMM(block, REG_RSI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1 && !is_float) + host_x86_MOV8_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else if (size == 2 && !is_float) + host_x86_MOV16_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else if (size == 4 && !is_float) + host_x86_MOV32_BASE_INDEX_REG(block, REG_RSI, REG_RDI, REG_ECX); + else if (size == 4 && is_float) + host_x86_MOVD_BASE_INDEX_XREG(block, REG_RSI, REG_RDI, REG_XMM_TEMP); + else if (size == 8) + host_x86_MOVQ_BASE_INDEX_XREG(block, REG_RSI, REG_RDI, REG_XMM_TEMP); + else + fatal("build_store_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_RAX); + host_x86_PUSH(block, REG_RDX); +#if WIN64 + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x28); + if (size == 4 && is_float) + host_x86_MOVD_REG_XREG(block, REG_EDX, REG_XMM_TEMP); //data + else if (size == 8) + host_x86_MOVQ_REG_XREG(block, REG_RDX, REG_XMM_TEMP); //data + else + host_x86_MOV32_REG_REG(block, REG_EDX, REG_ECX); //data + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EDI); //address +#else + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x8); + //host_x86_MOV32_REG_REG(block, REG_EDI, REG_ECX); //address + if (size == 4 && is_float) + host_x86_MOVD_REG_XREG(block, REG_ESI, REG_XMM_TEMP); //data + else if (size == 8) + host_x86_MOVQ_REG_XREG(block, REG_RSI, REG_XMM_TEMP); //data + else + host_x86_MOV32_REG_REG(block, REG_ESI, REG_ECX); //data +#endif + if (size == 1) + host_x86_CALL(block, (void *)writemembl); + else if (size == 2) + host_x86_CALL(block, (void *)writememwl); + else if (size == 4) + host_x86_CALL(block, (void *)writememll); + else if (size == 8) + host_x86_CALL(block, (void *)writememql); +#if WIN64 + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x28); +#else + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x8); +#endif + host_x86_POP(block, REG_RDX); + host_x86_POP(block, REG_RAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 1, 0); + codegen_mem_load_word = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 2, 0); + codegen_mem_load_long = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4, 0); + codegen_mem_load_quad = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 8, 0); + codegen_mem_load_single = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4, 1); + codegen_mem_load_double = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 8, 1); + + codegen_mem_store_byte = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 1, 0); + codegen_mem_store_word = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 2, 0); + codegen_mem_store_long = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4, 0); + codegen_mem_store_quad = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 8, 0); + codegen_mem_store_single = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4, 1); + codegen_mem_store_double = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 8, 1); +} + +void codegen_backend_init() +{ + codeblock_t *block; + int c; + + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); + 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 *)); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].pc = BLOCK_PC_INVALID; + +// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); + + block_current = 0; + block_pos = 0; + block = &codeblock[block_current]; + codeblock[block_current].head_mem_block = codegen_allocator_allocate(NULL, block_current); + codeblock[block_current].data = codeblock_allocator_get_ptr(codeblock[block_current].head_mem_block); + block_write_data = codeblock[block_current].data; + build_loadstore_routines(&codeblock[block_current]); + + codegen_gpf_rout = &codeblock[block_current].data[block_pos]; +#if WIN64 + host_x86_XOR32_REG_REG(block, REG_ECX, REG_ECX); + host_x86_XOR32_REG_REG(block, REG_EDX, REG_EDX); +#else + host_x86_XOR32_REG_REG(block, REG_EDI, REG_EDI); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); +#endif + host_x86_CALL(block, (void *)x86gpf); + codegen_exit_rout = &codeblock[block_current].data[block_pos]; + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x38); + host_x86_POP(block, REG_R15); + host_x86_POP(block, REG_R14); + host_x86_POP(block, REG_R13); + host_x86_POP(block, REG_R12); + host_x86_POP(block, REG_RDI); + host_x86_POP(block, REG_RSI); + host_x86_POP(block, REG_RBP); + host_x86_POP(block, REG_RDX); + host_x86_RET(block); + + block_write_data = NULL; + + asm( + "stmxcsr %0\n" + : "=m" (cpu_state.old_fp_control) + ); + cpu_state.trunc_fp_control = cpu_state.old_fp_control | 0x6000; +} + +void codegen_set_rounding_mode(int mode) +{ + cpu_state.new_fp_control = (cpu_state.old_fp_control & ~0x6000) | (mode << 13); +} + +void codegen_backend_prologue(codeblock_t *block) +{ + block_pos = BLOCK_START; /*Entry code*/ + host_x86_PUSH(block, REG_RBX); + host_x86_PUSH(block, REG_RBP); + host_x86_PUSH(block, REG_RSI); + host_x86_PUSH(block, REG_RDI); + host_x86_PUSH(block, REG_R12); + host_x86_PUSH(block, REG_R13); + host_x86_PUSH(block, REG_R14); + host_x86_PUSH(block, REG_R15); + host_x86_SUB64_REG_IMM(block, REG_RSP, 0x38); + host_x86_MOV64_REG_IMM(block, REG_RBP, ((uintptr_t)&cpu_state) + 128); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_x86_MOV32_REG_ABS(block, REG_EAX, &cpu_state.TOP); + host_x86_SUB32_REG_IMM(block, REG_EAX, block->TOP); + host_x86_MOV32_BASE_OFFSET_REG(block, REG_RSP, IREG_TOP_diff_stack_offset, REG_EAX); + } + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + host_x86_MOV64_REG_IMM(block, REG_R12, (uintptr_t)ram); +} + +void codegen_backend_epilogue(codeblock_t *block) +{ + host_x86_ADD64_REG_IMM(block, REG_RSP, 0x38); + host_x86_POP(block, REG_R15); + host_x86_POP(block, REG_R14); + host_x86_POP(block, REG_R13); + host_x86_POP(block, REG_R12); + host_x86_POP(block, REG_RDI); + host_x86_POP(block, REG_RSI); + host_x86_POP(block, REG_RBP); + host_x86_POP(block, REG_RDX); + host_x86_RET(block); +} +#endif diff --git a/src/codegen_backend_x86-64.h b/src/codegen_backend_x86-64.h new file mode 100644 index 0000000..3339224 --- /dev/null +++ b/src/codegen_backend_x86-64.h @@ -0,0 +1,14 @@ +#include "codegen_backend_x86-64_defs.h" + +#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_MAX 0x3c0 + +#define CODEGEN_BACKEND_HAS_MOV_IMM diff --git a/src/codegen_backend_x86-64_defs.h b/src/codegen_backend_x86-64_defs.h new file mode 100644 index 0000000..8856887 --- /dev/null +++ b/src/codegen_backend_x86-64_defs.h @@ -0,0 +1,67 @@ +/*RBP = cpu_state + 128 + R12 = ram (if block->flags & CODEBLOCK_NO_IMMEDIATES)*/ +#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_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_RAX 0 +#define REG_RCX 1 +#define REG_RDX 2 +#define REG_RBX 3 +#define REG_RSP 4 +#define REG_RBP 5 +#define REG_RSI 6 +#define REG_RDI 7 +#define REG_R8 8 +#define REG_R9 9 +#define REG_R10 10 +#define REG_R11 11 +#define REG_R12 12 +#define REG_R13 13 +#define REG_R14 14 +#define REG_R15 15 + +#define REG_XMM0 0 +#define REG_XMM1 1 +#define REG_XMM2 2 +#define REG_XMM3 3 +#define REG_XMM4 4 +#define REG_XMM5 5 +#define REG_XMM6 6 +#define REG_XMM7 7 + +#define REG_XMM_TEMP REG_XMM0 + +#define CODEGEN_HOST_REGS 3 +#define CODEGEN_HOST_FP_REGS 7 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; +extern void *codegen_mem_load_quad; +extern void *codegen_mem_load_single; +extern void *codegen_mem_load_double; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; +extern void *codegen_mem_store_quad; +extern void *codegen_mem_store_single; +extern void *codegen_mem_store_double; + +extern void *codegen_gpf_rout; +extern void *codegen_exit_rout; diff --git a/src/codegen_backend_x86-64_ops.c b/src/codegen_backend_x86-64_ops.c new file mode 100644 index 0000000..41a88b2 --- /dev/null +++ b/src/codegen_backend_x86-64_ops.c @@ -0,0 +1,1827 @@ +#ifdef __amd64__ + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" +#include "codegen_backend_x86-64_ops_helpers.h" + +#define RM_OP_ADD 0x00 +#define RM_OP_OR 0x08 +#define RM_OP_AND 0x20 +#define RM_OP_SUB 0x28 +#define RM_OP_XOR 0x30 +#define RM_OP_CMP 0x38 + +#define RM_OP_ROL 0x00 +#define RM_OP_ROR 0x08 +#define RM_OP_SHL 0x20 +#define RM_OP_SHR 0x28 +#define RM_OP_SAR 0x38 + +static inline void call(codeblock_t *block, uintptr_t func) +{ + uintptr_t diff; + + codegen_alloc_bytes(block, 5); + diff = func - (uintptr_t)&block_write_data[block_pos + 5]; + + if (diff >= -0x80000000 && diff < 0x7fffffff) + { + codegen_addbyte(block, 0xE8); /*CALL*/ + codegen_addlong(block, (uint32_t)diff); + } + else + { + codegen_alloc_bytes(block, 13); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, func*/ + codegen_addquad(block, func); + codegen_addbyte3(block, 0x41, 0xff, 0xd1); /*CALL R9*/ + } +} + +static inline void jmp(codeblock_t *block, uintptr_t func) +{ + uintptr_t diff; + + codegen_alloc_bytes(block, 5); + diff = func - (uintptr_t)&block_write_data[block_pos + 5]; + + if (diff >= -0x80000000 && diff < 0x7fffffff) + { + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, (uint32_t)diff); + } + else + { + codegen_alloc_bytes(block, 13); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, func*/ + codegen_addquad(block, func); + codegen_addbyte3(block, 0x41, 0xff, 0xe1); /*JMP R9*/ + } +} + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x04, imm_data); /*ADD EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data); /*ADD dst_reg, imm_data*/ + } +} +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x05); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_ADD | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_ADD | (dst_reg & 7)); /*ADD dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_ADD64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_ADD64_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_ADD | (dst_reg & 7), imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else + fatal("ADD64_REG_IMM !is_imm8 %016llx\n", imm_data); +} +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD8_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x00, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*ADD dst_reg, src_reg*/ +} +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD16_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*ADD dst_reg, src_reg*/ +} +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_ADD32_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x01, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*ADD dst_reg, src_reg*/ +} + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_AND8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x24, imm_data); /*AND EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data); /*AND dst_reg, imm_data*/ + } +} +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_AND16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x25); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_AND | (dst_reg & 7)); /*AND dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_AND32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_AND | (dst_reg & 7), imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_AND | (dst_reg & 7)); /*AND dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND8_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x20, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*AND dst_reg, src_reg*/ +} +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND16_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x21, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*AND dst_reg, src_reg*/ +} +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_AND32_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x21, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*AND dst_reg, src_reg*/ +} + +void host_x86_CALL(codeblock_t *block, void *p) +{ + call(block, (uintptr_t)p); +} + +void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x3d); /*CMP AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x3d); /*CMP EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_CMP64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else + fatal("CMP64_REG_IMM not 8-bit imm\n"); +} + +void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x38, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} +void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} +void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} + +void host_x86_JMP(codeblock_t *block, void *p) +{ + jmp(block, (uintptr_t)p); +} + +void host_x86_JNZ(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} +void host_x86_JZ(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} + +uint8_t *host_x86_JNZ_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x75, 0); /*JNZ*/ + return &block_write_data[block_pos-1]; +} +uint8_t *host_x86_JS_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x78, 0); /*JS*/ + return &block_write_data[block_pos-1]; +} +uint8_t *host_x86_JZ_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x74, 0); /*JZ*/ + return &block_write_data[block_pos-1]; +} + +uint32_t *host_x86_JNB_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x83); /*JNB*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNBE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x87); /*JNBE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNL_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8d); /*JNL*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNLE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8f); /*JNLE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNO_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x81); /*JNO*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNS_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x89); /*JNS*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNZ_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JB_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x82); /*JB*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JBE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x86); /*JBE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JL_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8c); /*JL*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JLE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8e); /*JLE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JO_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x80); /*JO*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JS_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x88); /*JS*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JZ_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_x86_LAHF(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x9f); /*LAHF*/ +} + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset) +{ + if (offset) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x8d, 0x80 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [offset+src_reg]*/ + codegen_addlong(block, offset); + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x8d, 0x00 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [src_reg]*/ + } +} +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_LEA_REG_REG - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b]*/ + ((src_reg_b & 7) << 3) | (src_reg_a & 7)); +} +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_LEA_REG_REG_SHIFT - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8d, 0x04 | ((dst_reg & 7) << 3), /*LEA dst_reg, [Rsrc_reg_a + Rsrc_reg_b * (1 << shift)]*/ + (shift << 6) | ((src_reg_b & 7) << 3) | (src_reg_a & 7)); +} + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[RBP], imm_data*/ + codegen_addbyte(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV8_ABS_IMM - out of range %p\n", p); + codegen_alloc_bytes(block, 8); + codegen_addbyte3(block, 0xc6, 0x04, 0x25); /*MOVB p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addbyte(block, imm_data); + } +} +void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ + codegen_addword(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); + codegen_alloc_bytes(block, 10); + codegen_addbyte4(block, 0x66, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addword(block, imm_data); + } +} +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[RBP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_IMM - out of range %p\n", p); + codegen_alloc_bytes(block, 11); + codegen_addbyte3(block, 0xc7, 0x04, 0x25); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV8_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x88, 0x45 | ((src_reg & 7) << 3), offset); /*MOVB offset[RBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV8_ABS_REG - out of range %p\n", p); + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV16_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x89, 0x85 | ((src_reg & 7) << 3)); /*MOV offset[RBP], src_reg*/ + codegen_addlong(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p); + } +} +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV32_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x89, 0x85 | ((src_reg & 7) << 3)); /*MOV offset[RBP], src_reg*/ + codegen_addlong(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV32_ABS_REG - out of range %p\n", p); + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((src_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOV64_ABS_REG - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x89, 0x45 | ((src_reg & 7) << 3), offset); /*MOV offset[RBP], src_reg*/ + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOV64_ABS_REG - out of range %p\n", p); + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x48, 0x89, 0x04 | ((src_reg & 7) << 3), 0x25); /*MOV [p], src_reg*/ + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} + +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int index_reg, int shift, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x88, 0x44 | (src_reg << 3), base_reg | (index_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x88, 0x84 | (src_reg << 3), base_reg | (index_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x88, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV B[base_reg + index_reg], src_reg*/ +} +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV W[base_reg + index_reg], src_reg*/ +} +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int index_reg, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_BASE_INDEX_REG reg & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x04 | (src_reg << 3), (index_reg << 3) | base_reg); /*MOV L[base_reg + index_reg], src_reg*/ +} + +void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOV8_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8a, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x8a, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x41, 0x8a, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + fatal("host_x86_MOV8_REG_ABS - out of range\n"); + } +} +void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOV16_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3)); /*MOV dst_reg, ram_offset[R12]*/ + codegen_addbyte(block, 0x24); + codegen_addlong(block, ram_offset); + } + else + { + fatal("host_x86_MOV16_REG_ABS - out of range\n"); + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t)p); + codegen_alloc_bytes(block, 1); + codegen_addbyte4(block, 0x66, 0x41, 0x8b, 0x01 | ((dst_reg & 7) << 3)); /*MOV dst_reg, [r9]*/ + } +} +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOV32_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x41, 0x8b, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOV dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + fatal("host_x86_MOV32_REG_ABS - out of range\n"); + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | ((dst_reg & 7) << 3)); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOV64_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (dst_reg & 8) + fatal("host_x86_MOV64_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x8b, 0x45 | ((dst_reg & 7) << 3), offset); /*MOV dst_reg, offset[RBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x48, 0x8b, 0x85 | ((dst_reg & 7) << 3)); /*MOV dst_reg, offset[RBP]*/ + codegen_addlong(block, offset); + } + else + fatal("host_x86_MOV64_REG_ABS - out of range\n"); +} + +void host_x86_MOV8_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int base_reg, int index_reg, int shift) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV8_REG_ABS_REG_REG_SHIFT reg & 8\n"); + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x8a, 0x44 | (dst_reg << 3), base_reg | (index_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x8a, 0x84 | (dst_reg << 3), base_reg | (index_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOV32_REG_BASE_INDEX reg & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); /*MOV dst_reg, Q[base_reg + index_reg]*/ +} + +void host_x86_MOV64_REG_BASE_INDEX_SHIFT(codeblock_t *block, int dst_reg, int base_reg, int index_reg, int scale) +{ + if ((dst_reg & 8) || (index_reg & 8)) + fatal("host_x86_MOV64_REG_BASE_INDEX_SHIFT reg & 8\n"); + codegen_alloc_bytes(block, 4); + if (base_reg & 8) + codegen_addbyte4(block, 0x49, 0x8b, 0x04 | ((dst_reg & 7) << 3), (scale << 6) | ((index_reg & 7) << 3) | (base_reg & 7)); /*MOV dst_reg, Q[base_reg + index_reg << scale]*/ + else + codegen_addbyte4(block, 0x48, 0x8b, 0x04 | ((dst_reg & 7) << 3), (scale << 6) | ((index_reg & 7) << 3) | (base_reg & 7)); /*MOV dst_reg, Q[base_reg + index_reg << scale]*/ +} + +void host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if ((dst_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV16_REG_BASE_OFFSET reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV16_REG_BASE_OFFSET - offset %i\n", offset); +} +void host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if ((dst_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV32_REG_BASE_OFFSET reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV32_REG_BASE_OFFSET - offset %i\n", offset); +} +void host_x86_MOV64_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if ((dst_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV64_REG_BASE_OFFSET reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x48); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV32_REG_BASE_OFFSET - offset %i\n", offset); +} + +void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV32_BASE_OFFSET_REG reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + } + } + else + fatal("MOV32_BASE_OFFSET_REG - offset %i\n", offset); +} +void host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if ((src_reg & 8) || (base_reg & 8)) + fatal("host_x86_MOV64_BASE_OFFSET_REG reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x48); + codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + } + } + else + fatal("MOV64_BASE_OFFSET_REG - offset %i\n", offset); +} + +void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data) +{ + if (base_reg & 8) + fatal("host_x86_MOV32_BASE_OFFSET_IMM reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset); + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x40 | base_reg, offset); + codegen_addlong(block, imm_data); + } + } + else + fatal("MOV32_BASE_OFFSET_IMM - offset %i\n", offset); +} + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) +{ + if (reg >= 8) + fatal("host_x86_MOV8_REG_IMM reg >= 4\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xb0 | reg, imm_data); /*MOV reg, imm_data*/ +} +void host_x86_MOV16_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data) +{ + if (reg & 8) + fatal("host_x86_MOV16_REG_IMM reg & 8\n"); + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x66, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ + codegen_addword(block, imm_data); +} +void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data) +{ + if (reg & 8) + fatal("host_x86_MOV32_REG_IMM reg & 8\n"); + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xb8 | (reg & 7)); /*MOV reg, imm_data*/ + codegen_addlong(block, imm_data); +} + +void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_data) +{ + if (reg & 8) + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/ + codegen_addquad(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x48, 0xb8 | (reg & 7)); /*MOVQ reg, imm_data*/ + codegen_addquad(block, imm_data); + } +} + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV8_REG_REG - bad reg\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x88, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV16_REG_REG - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOV32_REG_REG - bad reg\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x89, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); +} + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) +{ + if (!offset) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else if (offset >= -0x80 && offset < 0x80) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 11); + codegen_addbyte3(block, 0xc7, 0x84, 0x24); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, offset); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} +void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} +void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xbf, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOVZX_BASE_INDEX_32_8 reg & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb6, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); +} +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int index_reg) +{ + if ((dst_reg & 8) || (base_reg & 8) | (index_reg & 8)) + fatal("host_x86_MOVZX_BASE_INDEX_32_16 reg & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb7, 0x04 | (dst_reg << 3), (index_reg << 3) | base_reg); +} + +void host_x86_MOVZX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOVZX_REG_16_8 - bad reg\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOVZX_REG_32_8 - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_MOVZX_REG_16_8 - bad reg\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xb7, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOVZX_REG_ABS_16_8 - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x66, 0x41); + codegen_addbyte4(block, 0x0f, 0xb6, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOVZX dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t)p); + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x41, 0x0f, 0xb6, 0x01 | ((dst_reg & 7) << 3)); /*MOVZX dst_reg, [r9]*/ + } +} +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + +// if (dst_reg & 8) +// fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + if (dst_reg & 8) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x44); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + if (dst_reg & 8) + fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); + + codegen_alloc_bytes(block, 9); + codegen_addbyte(block, 0x41); + codegen_addbyte4(block, 0x0f, 0xb6, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOVZX dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + if (dst_reg & 8) + fatal("host_x86_MOVZX_REG_ABS_32_8 - bad reg\n"); + + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t)p); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x41, 0x0f, 0xb6, 0x01 | ((dst_reg & 7) << 3)); /*MOVZX dst_reg, [r9]*/ + } +} +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p) +{ + int64_t offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + int64_t ram_offset = (uintptr_t)p - (uintptr_t)ram; + + if (dst_reg & 8) + fatal("host_x86_MOVZX_REG_ABS_32_16 - bad reg\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb7, 0x45 | ((dst_reg & 7) << 3), offset); /*MOVZX dst_reg, offset[RBP]*/ + } + else if ((ram_offset < (1ull << 32)) && (block->flags & CODEBLOCK_NO_IMMEDIATES)) + { + codegen_alloc_bytes(block, 9); + codegen_addbyte(block, 0x41); + codegen_addbyte4(block, 0x0f, 0xb7, 0x84 | ((dst_reg & 7) << 3), 0x24); /*MOVZX dst_reg, ram_offset[R12]*/ + codegen_addlong(block, ram_offset); + } + else + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0x49, 0xb9); /*MOV R9, p*/ + codegen_addquad(block, (uintptr_t)p); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x41, 0x0f, 0xb7, 0x01 | ((dst_reg & 7) << 3)); /*MOVZX dst_reg, [r9]*/ + } +} + +void host_x86_NOP(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x90); /*NOP*/ +} + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_OR8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x0c, imm_data); /*OR EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data); /*OR dst_reg, imm_data*/ + } +} +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_OR16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data & 0xff); /*OR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x0d); /*OR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_OR | (dst_reg & 7)); /*OR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_OR32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_OR | (dst_reg & 7), imm_data & 0xff); /*OR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x0d); /*OR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_OR | (dst_reg & 7)); /*OR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR8_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x08, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*OR dst_reg, src_reg*/ +} +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR16_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x09, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*OR dst_reg, src_reg*/ +} +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_OR32_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x09, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*OR dst_reg, src_reg*/ +} + +void host_x86_POP(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x41, 0x58 | (dst_reg & 7)); /*POP reg*/ + } + else + { + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x58 | dst_reg); /*POP reg*/ + } +} + +void host_x86_PUSH(codeblock_t *block, int src_reg) +{ + if (src_reg & 8) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x41, 0x50 | (src_reg & 7)); /*PUSH reg*/ + } + else + { + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x50 | src_reg); /*PUSH reg*/ + } +} + +void host_x86_RET(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0xc3); /*RET*/ +} + +void host_x86_ROL8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROL8 CL & 8\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_ROL16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROL16 CL & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_ROL32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROL32 CL & 8\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} + +void host_x86_ROL8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROL8 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_ROL16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROL16 imm & 8\n"); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_ROL32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROL32 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} + +void host_x86_ROR8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROR8 CL & 8\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_ROR16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROR16 CL & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_ROR32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("ROR32 CL & 8\n"); + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} + +void host_x86_ROR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROR8 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_ROR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROR16 imm & 8\n"); + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_ROR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("ROR32 im & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +void host_x86_SAR8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SAR8 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} +void host_x86_SAR16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SAR16 CL & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} +void host_x86_SAR32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SAR32 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} + +void host_x86_SAR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SAR8 imm & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} +void host_x86_SAR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SAR16 imm & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} +void host_x86_SAR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SAR32 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} + +void host_x86_SHL8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHL8 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_SHL16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHL16 CL & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_SHL32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHL32 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} + +void host_x86_SHL8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHL8 imm & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_SHL16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHL16 imm & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_SHL32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHL32 imm & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} + +void host_x86_SHR8_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHR8 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_SHR16_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHR16 CL & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_SHR32_CL(codeblock_t *block, int dst_reg) +{ + if (dst_reg & 8) + fatal("SHR32 CL & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} + +void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHR8 imm & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHR16 imm & 8\n"); + + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + if (dst_reg & 8) + fatal("SHR32 imm & 8\n"); + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x2c, imm_data); /*SUB EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data); /*SUB dst_reg, imm_data*/ + } +} +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x2d); /*SUB AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_SUB | (dst_reg & 7)); /*SUB dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x2d); /*SUB EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_SUB | (dst_reg & 7)); /*SUB dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_SUB64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_SUB64_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x48, 0x83, 0xc0 | RM_OP_SUB | (dst_reg & 7), imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else + fatal("SUB64_REG_IMM !is_imm8 %016llx\n", imm_data); +} +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB8_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x28, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*SUB dst_reg, src_reg*/ +} +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB16_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*SUB dst_reg, src_reg*/ +} +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_SUB32_REG_REG - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x29, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*SUB dst_reg, src_reg*/ +} + +#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) + +void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x84, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_TEST32_REG - bad reg\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_reg, src_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("TEST32_REG_IMM reg & 8\n"); + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xa9); /*TEST EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0xf7, 0xc0 | dst_reg); /*TEST dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_XOR8_REG_IMM - dst_reg & 8\n"); + + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x34, imm_data); /*XOR EAX, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data); /*XOR dst_reg, imm_data*/ + } +} +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_XOR16_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data & 0xff); /*XOR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x35); /*XOR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_XOR | (dst_reg & 7)); /*XOR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg & 8) + fatal("host_x86_XOR32_REG_IMM - dst_reg & 8\n"); + + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_XOR | (dst_reg & 7), imm_data & 0xff); /*XOR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x35); /*XOR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_XOR | (dst_reg & 7)); /*XOR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR8_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x30, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*XOR dst_reg, src_reg*/ +} +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR16_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*XOR dst_reg, src_reg*/ +} +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + if ((dst_reg & 8) || (src_reg & 8)) + fatal("host_x86_XOR32_REG_IMM - dst_reg & 8\n"); + + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x31, 0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); /*XOR dst_reg, src_reg*/ +} + +#endif diff --git a/src/codegen_backend_x86-64_ops.h b/src/codegen_backend_x86-64_ops.h new file mode 100644 index 0000000..e1db22a --- /dev/null +++ b/src/codegen_backend_x86-64_ops.h @@ -0,0 +1,196 @@ +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); +void host_x86_ADD64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CALL(codeblock_t *block, void *p); + +void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); +void host_x86_CMP64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); + +void host_x86_JMP(codeblock_t *block, void *p); + +void host_x86_JNZ(codeblock_t *block, void *p); +void host_x86_JZ(codeblock_t *block, void *p); + +uint8_t *host_x86_JNZ_short(codeblock_t *block); +uint8_t *host_x86_JS_short(codeblock_t *block); +uint8_t *host_x86_JZ_short(codeblock_t *block); + +uint32_t *host_x86_JNB_long(codeblock_t *block); +uint32_t *host_x86_JNBE_long(codeblock_t *block); +uint32_t *host_x86_JNL_long(codeblock_t *block); +uint32_t *host_x86_JNLE_long(codeblock_t *block); +uint32_t *host_x86_JNO_long(codeblock_t *block); +uint32_t *host_x86_JNS_long(codeblock_t *block); +uint32_t *host_x86_JNZ_long(codeblock_t *block); +uint32_t *host_x86_JB_long(codeblock_t *block); +uint32_t *host_x86_JBE_long(codeblock_t *block); +uint32_t *host_x86_JL_long(codeblock_t *block); +uint32_t *host_x86_JLE_long(codeblock_t *block); +uint32_t *host_x86_JO_long(codeblock_t *block); +uint32_t *host_x86_JS_long(codeblock_t *block); +uint32_t *host_x86_JZ_long(codeblock_t *block); + +void host_x86_LAHF(codeblock_t *block); + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset); +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); +void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data); +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV64_ABS_REG(codeblock_t *block, void *p, int src_reg); + +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int index_reg, int shift, int src_reg); + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg); +void host_x86_MOV64_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg); + +void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data); + +void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV64_REG_ABS(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOV8_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int base_reg, int index_reg, int shift); + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOV64_REG_BASE_INDEX_SHIFT(codeblock_t *block, int dst_reg, int base_reg, int index_reg, int scale); + +void host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); +void host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); +void host_x86_MOV64_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data); +void host_x86_MOV16_REG_IMM(codeblock_t *block, int reg, uint16_t imm_data); +void host_x86_MOV32_REG_IMM(codeblock_t *block, int reg, uint32_t imm_data); + +void host_x86_MOV64_REG_IMM(codeblock_t *block, int reg, uint64_t imm_data); + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data); + +void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int index_reg); +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int index_reg); + +void host_x86_MOVZX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p); + +void host_x86_NOP(codeblock_t *block); + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_POP(codeblock_t *block, int src_reg); + +void host_x86_PUSH(codeblock_t *block, int src_reg); + +void host_x86_RET(codeblock_t *block); + +void host_x86_ROL8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROL16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROL32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_ROL8_CL(codeblock_t *block, int dst_reg); +void host_x86_ROL16_CL(codeblock_t *block, int dst_reg); +void host_x86_ROL32_CL(codeblock_t *block, int dst_reg); + +void host_x86_ROR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_ROR8_CL(codeblock_t *block, int dst_reg); +void host_x86_ROR16_CL(codeblock_t *block, int dst_reg); +void host_x86_ROR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SAR8_CL(codeblock_t *block, int dst_reg); +void host_x86_SAR16_CL(codeblock_t *block, int dst_reg); +void host_x86_SAR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SAR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SAR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SAR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SHL8_CL(codeblock_t *block, int dst_reg); +void host_x86_SHL16_CL(codeblock_t *block, int dst_reg); +void host_x86_SHL32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SHL8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHL16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHL32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SHR8_CL(codeblock_t *block, int dst_reg); +void host_x86_SHR16_CL(codeblock_t *block, int dst_reg); +void host_x86_SHR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); +void host_x86_SUB64_REG_IMM(codeblock_t *block, int dst_reg, uint64_t imm_data); + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST32_REG(codeblock_t *block, int src_reg, int dst_reg); +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); diff --git a/src/codegen_backend_x86-64_ops_helpers.h b/src/codegen_backend_x86-64_ops_helpers.h new file mode 100644 index 0000000..4e63bbd --- /dev/null +++ b/src/codegen_backend_x86-64_ops_helpers.h @@ -0,0 +1,102 @@ +#define JMP_LEN_BYTES 5 + +static inline void codegen_addbyte(codeblock_t *block, uint8_t val) +{ + if (block_pos >= BLOCK_MAX) + { + fatal("codegen_addbyte over! %i\n", block_pos); +// CPU_BLOCK_END(); + } + block_write_data[block_pos++] = val; +} +static inline void codegen_addbyte2(codeblock_t *block, uint8_t vala, uint8_t valb) +{ + if (block_pos > (BLOCK_MAX-2)) + { + fatal("codegen_addbyte2 over! %i\n", block_pos); + CPU_BLOCK_END(); + } + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; +} +static inline void codegen_addbyte3(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc) +{ + if (block_pos > (BLOCK_MAX-3)) + { + fatal("codegen_addbyte3 over! %i\n", block_pos); + CPU_BLOCK_END(); + } + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; + block_write_data[block_pos++] = valc; +} +static inline void codegen_addbyte4(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc, uint8_t vald) +{ + if (block_pos > (BLOCK_MAX-4)) + { + fatal("codegen_addbyte4 over! %i\n", block_pos); + CPU_BLOCK_END(); + } + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; + block_write_data[block_pos++] = valc; + block_write_data[block_pos++] = vald; +} + +static inline void codegen_addword(codeblock_t *block, uint16_t val) +{ + if (block_pos > (BLOCK_MAX-2)) + { + fatal("codegen_addword over! %i\n", block_pos); + CPU_BLOCK_END(); + } + *(uint16_t *)&block_write_data[block_pos] = val; + block_pos += 2; +} + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + if (block_pos > (BLOCK_MAX-4)) + { + fatal("codegen_addlong over! %i\n", block_pos); + CPU_BLOCK_END(); + } + *(uint32_t *)&block_write_data[block_pos] = val; + block_pos += 4; +} + +static inline void codegen_addquad(codeblock_t *block, uint64_t val) +{ + if (block_pos > (BLOCK_MAX-8)) + { + fatal("codegen_addquad over! %i\n", block_pos); + CPU_BLOCK_END(); + } + *(uint64_t *)&block_write_data[block_pos] = val; + block_pos += 8; +} + +static inline void codegen_alloc_bytes(codeblock_t *block, int size) +{ + if (block_pos > ((BLOCK_MAX - size) - JMP_LEN_BYTES)) + { + /*Current block is full. Allocate a new block*/ + struct mem_block_t *new_block = codegen_allocator_allocate(block->head_mem_block, get_block_nr(block)); + uint8_t *new_ptr = codeblock_allocator_get_ptr(new_block); + + /*Add a jump instruction to the new block*/ + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, (uintptr_t)new_ptr - (uintptr_t)&block_write_data[block_pos + 4]); + + /*Set write address to start of new block*/ + block_pos = 0; + block_write_data = new_ptr; + } +} + +static inline int is_imm8(uint32_t imm_data) +{ + if (imm_data <= 0x7f || imm_data >= 0xffffff80) + return 1; + return 0; +} diff --git a/src/codegen_backend_x86-64_ops_sse.c b/src/codegen_backend_x86-64_ops_sse.c new file mode 100644 index 0000000..cdff2c6 --- /dev/null +++ b/src/codegen_backend_x86-64_ops_sse.c @@ -0,0 +1,614 @@ +#ifdef __amd64__ + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops_sse.h" +#include "codegen_backend_x86-64_ops_helpers.h" + +void host_x86_ADDPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); /*ADDPS dst_reg, src_reg*/ +} +void host_x86_ADDSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_CMPPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg, int type) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xc2, 0xc0 | src_reg | (dst_reg << 3), type); /*CMPPS dst_reg, src_reg, type*/ +} + +void host_x86_COMISD_XREG_XREG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x2e, 0xc0 | src_reg_b | (src_reg_a << 3)); +} + +void host_x86_CVTDQ2PS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5b, 0xc0 | src_reg | (dst_reg << 3)); /*CVTDQ2PS dst_reg, src_reg*/ +} +void host_x86_CVTPS2DQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x5b, 0xc0 | src_reg | (dst_reg << 3)); /*CVTPS2DQ dst_reg, src_reg*/ +} + +void host_x86_CVTSD2SI_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x2d, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSD2SI dst_reg, src_reg*/ +} +void host_x86_CVTSD2SI_REG64_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf2, 0x48, 0x0f, 0x2d); /*CVTSD2SI dst_reg, src_reg*/ + codegen_addbyte(block, 0xc0 | src_reg | (dst_reg << 3)); +} +void host_x86_CVTSD2SS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5a, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_CVTSI2SD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x2a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSI2SD dst_reg, src_reg*/ +} +void host_x86_CVTSI2SS_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x2a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSI2SD dst_reg, src_reg*/ +} +void host_x86_CVTSI2SD_XREG_REG64(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf2, 0x48, 0x0f, 0x2a); /*CVTSI2SD dst_reg, src_reg*/ + codegen_addbyte(block, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_CVTSS2SD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5a, 0xc0 | src_reg | (dst_reg << 3)); +} +void host_x86_CVTSS2SD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5a, 0x04 | (dst_reg << 3)); /*CVTSS2SD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} + +void host_x86_DIVSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); +} +void host_x86_DIVSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); /*DIVSS dst_reg, src_reg*/ +} + +void host_x86_LDMXCSR(codeblock_t *block, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xae, 0x50 | REG_EBP, offset); /*LDMXCSR offset[EBP]*/ + } + else if (offset < (1ull << 32)) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x0f, 0xae, 0x90 | REG_EBP); /*LDMXCSR offset[EBP]*/ + codegen_addlong(block, offset); + } + else + { + fatal("host_x86_LDMXCSR - out of range %p\n", p); + } +} + +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXSD dst_reg, src_reg*/ +} + +void host_x86_MOVD_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x7e, 0x04 | (src_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVD_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x7e, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOVD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x6e, 0x04 | (dst_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x6e, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_MOVQ_ABS_XREG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (src_reg & 8) + fatal("host_x86_MOVQ_ABS_REG reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x45 | (src_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOVQ_ABS_REG - out of range %p\n", p); + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addbyte(block, 0x25); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg) +{ + if ((src_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_MOVQ_ABS_REG_REG_SHIFT_REG - bad reg\n"); + + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + codegen_addbyte3(block, 0x44 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + codegen_addbyte2(block, 0x84 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} + +void host_x86_MOVQ_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVQ_BASE_OFFSET_XREG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_RSP) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x44 | (src_reg << 3)); /*MOVQ [RSP + offset], XMMx*/ + codegen_addbyte2(block, 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x40 | base_reg | (src_reg << 3)); /*MOVQ [base_reg + offset], XMMx*/ + codegen_addbyte(block, offset); + } + } + else + fatal("MOVQ_BASE_OFFSET_XREG - offset %i\n", offset); +} + +void host_x86_MOVQ_XREG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (dst_reg & 8) + fatal("host_x86_MOVQ_REG_ABS reg & 8\n"); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x45 | (dst_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + if ((uintptr_t)p >> 32) + fatal("host_x86_MOVQ_REG_ABS - out of range %p\n", p); + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x04 | (dst_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addbyte(block, 0x25); + codegen_addlong(block, (uint32_t)(uintptr_t)p); + } +} +void host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift) +{ + if ((dst_reg & 8) || (src_reg_a & 8) || (src_reg_b & 8)) + fatal("host_x86_MOVQ_REG_ABS_REG_REG_SHIFT - bad reg\n"); + + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + codegen_addbyte3(block, 0x44 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + codegen_addbyte2(block, 0x84 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} +void host_x86_MOVQ_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x04 | (dst_reg << 3)); /*MOVQ XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVQ_XREG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x44 | (dst_reg << 3)); /*MOVQ XMMx, [ESP + offset]*/ + codegen_addbyte2(block, 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x40 | base_reg | (dst_reg << 3)); /*MOVQ XMMx, [base_reg + offset]*/ + codegen_addbyte(block, offset); + } + } + else + fatal("MOVQ_REG_BASE_OFFSET - offset %i\n", offset); +} + +void host_x86_MOVQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0xc0 | src_reg | (dst_reg << 3)); /*MOVQ dst_reg, src_reg*/ +} + +void host_x86_MOVQ_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x48, 0x0f, 0x7e); /*MOVQ dst_reg, src_reg*/ + codegen_addbyte(block, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOVQ_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x48, 0x0f, 0x6e); /*MOVQ dst_reg, src_reg*/ + codegen_addbyte(block, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_MAXPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXPS dst_reg, src_reg*/ +} +void host_x86_MINPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5d, 0xc0 | src_reg | (dst_reg << 3)); /*MINPS dst_reg, src_reg*/ +} + +void host_x86_MULPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); /*MULPS dst_reg, src_reg*/ +} +void host_x86_MULSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_PACKSSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x63, 0xc0 | src_reg | (dst_reg << 3)); /*PACKSSWB dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} +void host_x86_PACKSSDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x6b, 0xc0 | src_reg | (dst_reg << 3)); /*PACKSSDW dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} +void host_x86_PACKUSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x67, 0xc0 | src_reg | (dst_reg << 3)); /*PACKUSWB dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} + +void host_x86_PADDB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfc, 0xc0 | src_reg | (dst_reg << 3)); /*PADDB dst_reg, src_reg*/ +} +void host_x86_PADDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfd, 0xc0 | src_reg | (dst_reg << 3)); /*PADDW dst_reg, src_reg*/ +} +void host_x86_PADDD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfe, 0xc0 | src_reg | (dst_reg << 3)); /*PADDD dst_reg, src_reg*/ +} +void host_x86_PADDSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xec, 0xc0 | src_reg | (dst_reg << 3)); /*PADDSB dst_reg, src_reg*/ +} +void host_x86_PADDSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xed, 0xc0 | src_reg | (dst_reg << 3)); /*PADDSW dst_reg, src_reg*/ +} +void host_x86_PADDUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdc, 0xc0 | src_reg | (dst_reg << 3)); /*PADDUSB dst_reg, src_reg*/ +} +void host_x86_PADDUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdd, 0xc0 | src_reg | (dst_reg << 3)); /*PADDUSW dst_reg, src_reg*/ +} + +void host_x86_PAND_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdb, 0xc0 | src_reg | (dst_reg << 3)); /*PAND dst_reg, src_reg*/ +} +void host_x86_PANDN_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdf, 0xc0 | src_reg | (dst_reg << 3)); /*PANDN dst_reg, src_reg*/ +} +void host_x86_POR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xeb, 0xc0 | src_reg | (dst_reg << 3)); /*POR dst_reg, src_reg*/ +} +void host_x86_PXOR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xef, 0xc0 | src_reg | (dst_reg << 3)); /*PXOR dst_reg, src_reg*/ +} + +void host_x86_PCMPEQB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x74, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQB dst_reg, src_reg*/ +} +void host_x86_PCMPEQW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x75, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQW dst_reg, src_reg*/ +} +void host_x86_PCMPEQD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x76, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQD dst_reg, src_reg*/ +} +void host_x86_PCMPGTB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x64, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTB dst_reg, src_reg*/ +} +void host_x86_PCMPGTW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x65, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTW dst_reg, src_reg*/ +} +void host_x86_PCMPGTD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x66, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTD dst_reg, src_reg*/ +} + +void host_x86_PMADDWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} +void host_x86_PMULHW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} +void host_x86_PMULLW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} + +void host_x86_PSLLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x30 | dst_reg); /*PSLLW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSLLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x30 | dst_reg); /*PSLLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSLLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x30 | dst_reg); /*PSLLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x20 | dst_reg); /*PSRAW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x20 | dst_reg); /*PSRAD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x20 | dst_reg); /*PSRAD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x10 | dst_reg); /*PSRLW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x10 | dst_reg); /*PSRLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x10 | dst_reg); /*PSRLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} + +void host_x86_PSUBB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf8, 0xc0 | src_reg | (dst_reg << 3)); /*PADDB dst_reg, src_reg*/ +} +void host_x86_PSUBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf9, 0xc0 | src_reg | (dst_reg << 3)); /*PADDW dst_reg, src_reg*/ +} +void host_x86_PSUBD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfa, 0xc0 | src_reg | (dst_reg << 3)); /*PADDD dst_reg, src_reg*/ +} +void host_x86_PSUBSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe8, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBSB dst_reg, src_reg*/ +} +void host_x86_PSUBSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe9, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBSW dst_reg, src_reg*/ +} +void host_x86_PSUBUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd8, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBUSB dst_reg, src_reg*/ +} +void host_x86_PSUBUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd9, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBUSW dst_reg, src_reg*/ +} + +void host_x86_PUNPCKHBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x60, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLBW dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0xee (move top 64-bits to low 64-bits)*/ + codegen_addbyte(block, 0xee); +} +void host_x86_PUNPCKHWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x61, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLWD dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0xee (move top 64-bits to low 64-bits)*/ + codegen_addbyte(block, 0xee); +} +void host_x86_PUNPCKHDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x62, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLDQ dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0xee (move top 64-bits to low 64-bits)*/ + codegen_addbyte(block, 0xee); +} +void host_x86_PUNPCKLBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x60, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLBW dst_reg, src_reg*/ +} +void host_x86_PUNPCKLWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x61, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLWD dst_reg, src_reg*/ +} +void host_x86_PUNPCKLDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x62, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLDQ dst_reg, src_reg*/ +} + +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSD dst_reg, src_reg*/ +} +void host_x86_SQRTSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSS dst_reg, src_reg*/ +} + +void host_x86_SUBPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); /*SUBPS dst_reg, src_reg*/ +} +void host_x86_SUBSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_UNPCKLPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x14, 0xc0 | src_reg | (dst_reg << 3)); +} + +#endif diff --git a/src/codegen_backend_x86-64_ops_sse.h b/src/codegen_backend_x86-64_ops_sse.h new file mode 100644 index 0000000..39e39f4 --- /dev/null +++ b/src/codegen_backend_x86-64_ops_sse.h @@ -0,0 +1,114 @@ +void host_x86_ADDPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADDSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +#define CMPPS_EQ 0 +#define CMPPS_NLT 5 +#define CMPPS_NLE 6 +void host_x86_CMPPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg, int type); + +void host_x86_COMISD_XREG_XREG(codeblock_t *block, int src_reg_a, int src_reg_b); + +void host_x86_CVTDQ2PS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTPS2DQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CVTSD2SI_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSD2SI_REG64_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSD2SS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSI2SD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSI2SD_XREG_REG64(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSI2SS_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSS2SD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSS2SD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_DIVSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_DIVSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_LDMXCSR(codeblock_t *block, void *p); + +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVD_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOVD_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVQ_ABS_XREG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg); +void host_x86_MOVQ_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOVQ_BASE_OFFSET_XREG(codeblock_t *block, int base_reg, int offset, int src_reg); +void host_x86_MOVQ_XREG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift); +void host_x86_MOVQ_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVQ_XREG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); + +void host_x86_MOVQ_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVQ_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MAXPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MINPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MULPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MULSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MULSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PACKSSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PACKSSDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PACKUSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PADDB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PAND_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PANDN_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_POR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PXOR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PCMPEQB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPEQW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPEQD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PMADDWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PMULHW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PMULLW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PSLLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSLLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSLLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_PSUBB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PUNPCKHBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKHWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKHDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SQRTSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_SUBPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUBSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_UNPCKLPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); diff --git a/src/codegen_backend_x86-64_uops.c b/src/codegen_backend_x86-64_uops.c new file mode 100644 index 0000000..b2ca7dc --- /dev/null +++ b/src/codegen_backend_x86-64_uops.c @@ -0,0 +1,3161 @@ +#ifdef __amd64__ + +#include "ibm.h" +#include "x86.h" +#include "x87.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_backend_x86-64_defs.h" +#include "codegen_backend_x86-64_ops.h" +#include "codegen_backend_x86-64_ops_sse.h" +#include "codegen_ir_defs.h" + +#define STACK_ARG0 (0) +#define STACK_ARG1 (4) +#define STACK_ARG2 (8) +#define STACK_ARG3 (12) + +#define HOST_REG_GET(reg) ((IREG_GET_SIZE(reg) == IREG_SIZE_BH) ? (IREG_GET_REG((reg) & 3) | 4) : (IREG_GET_REG(reg) & 7)) + +#define REG_IS_L(size) (size == IREG_SIZE_L) +#define REG_IS_W(size) (size == IREG_SIZE_W) +#define REG_IS_B(size) (size == IREG_SIZE_B || size == IREG_SIZE_BH) +#define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) +#define REG_IS_Q(size) (size == IREG_SIZE_Q) + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_LEA_REG_REG(block, dest_reg, src_reg_a, src_reg_b); + else + host_x86_ADD32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_ADD16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_ADD8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (dest_reg != src_reg) + host_x86_LEA_REG_IMM(block, dest_reg, src_reg, uop->imm_data); + else + host_x86_ADD32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ADD16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ADD8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ADD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + if (!uop->imm_data) + { + if (uop->dest_reg_a_real == uop->src_reg_a_real) + host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_b_real); + else + host_x86_LEA_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + } + else if (uop->imm_data < 4) + host_x86_LEA_REG_REG_SHIFT(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_ADD_LSHIFT - shift out of range %i\n", uop->imm_data); +#endif + return 0; +} + +static int codegen_AND(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PAND_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("AND %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_AND32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_AND16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_AND8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("AND_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_ANDN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), /*src_reg_a = HOST_REG_GET(uop->src_reg_a_real), */src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PANDN_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ANDN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) +{ + host_x86_CALL(block, uop->p); + + return 0; +} + +static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + if (!REG_IS_L(dest_size)) + fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); +#endif + host_x86_CALL(block, uop->p); + host_x86_MOV32_REG_REG(block, dest_reg, REG_EAX); + + return 0; +} + +static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) +{ + host_x86_CALL(block, uop->p); + host_x86_TEST32_REG(block, REG_EAX, REG_EAX); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); +#endif + host_x86_JZ(block, uop->p); + + return 0; +} + +static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNZ_long(block); + + return 0; +} +static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JZ_long(block); + + return 0; +} + +static int codegen_CMP_JB(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JB %02x\n", uop->src_reg_a_real); +#endif + jump_p = host_x86_JB_long(block); + *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); + + return 0; +} +static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNBE %02x\n", uop->src_reg_a_real); +#endif + jump_p = host_x86_JNBE_long(block); + *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); + + return 0; +} + +static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNB_long(block); + + return 0; +} +static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNBE_long(block); + + return 0; +} +static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNL_long(block); + + return 0; +} +static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNLE_long(block); + + return 0; +} +static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNO_long(block); + + return 0; +} +static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNZ_long(block); + + return 0; +} +static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JB_long(block); + + return 0; +} +static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JBE_long(block); + + return 0; +} +static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JL_long(block); + + return 0; +} +static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JLE_long(block); + + return 0; +} +static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JO_long(block); + + return 0; +} +static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JZ_long(block); + + return 0; +} + +static int codegen_FABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && dest_reg == src_reg_a) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, dest_reg); + host_x86_MAXSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FCHS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_PXOR_XREG_XREG(block, dest_reg, dest_reg); + host_x86_SUBSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_SQRTSD_XREG_XREG(block, dest_reg, src_reg_a); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FTST(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, REG_XMM_TEMP); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_ADDSD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FCOM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, src_reg_b); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_DIVSD_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_DIVSD_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_MULSD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_SUBSD_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_long(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_ECX, 7); +#else + host_x86_MOV32_REG_IMM(block, REG_EDI, 7); +#endif + host_x86_CALL(block, x86_int); + host_x86_JMP(block, codegen_exit_rout); + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + + return 0; +} +static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_long(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_ECX, 7); +#else + host_x86_MOV32_REG_IMM(block, REG_EDI, 7); +#endif + host_x86_CALL(block, x86_int); + host_x86_JMP(block, codegen_exit_rout); + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[0], 0x01010101); + host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[4], 0x01010101); + host_x86_MOV32_ABS_IMM(block, &cpu_state.TOP, 0); + host_x86_MOV8_ABS_IMM(block, &cpu_state.ismmx, 1); + + return 0; +} + +static int codegen_JMP(codeblock_t *block, uop_t *uop) +{ + host_x86_JMP(block, uop->p); + + return 0; +} + +static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(src_size)) + { +#if WIN64 + host_x86_MOVZX_REG_32_16(block, REG_ECX, src_reg); +#else + host_x86_MOVZX_REG_32_16(block, REG_EDI, src_reg); +#endif + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_LOAD_FUNC_ARG0 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG1(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG1 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG2(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG2 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG3 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) +{ +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data); +#else + host_x86_MOV32_REG_IMM(block, REG_EDI, uop->imm_data); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) +{ +#if WIN64 + host_x86_MOV32_REG_IMM(block, REG_EDX, uop->imm_data); +#else + host_x86_MOV32_REG_IMM(block, REG_ESI, uop->imm_data); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG2_IMM(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG2_IMM\n"); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG3_IMM\n"); +#endif + return 0; +} + +static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + if (!REG_IS_W(src_size)) + fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); +#endif +#if WIN64 + host_x86_MOV16_REG_REG(block, REG_CX, src_reg); + host_x86_MOV64_REG_IMM(block, REG_EDX, (uint64_t)uop->p); +#else + host_x86_MOV16_REG_REG(block, REG_DI, src_reg); + host_x86_MOV64_REG_IMM(block, REG_ESI, (uint64_t)uop->p); +#endif + host_x86_CALL(block, (void *)loadseg); + host_x86_TEST32_REG(block, REG_EAX, REG_EAX); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } + else if (REG_IS_Q(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_quad); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_Q(dest_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } + + return 0; +} +static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_SINGLE - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CALL(block, codegen_mem_load_single); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + + return 0; +} +static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CALL(block, codegen_mem_load_double); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV8_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_byte); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV16_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_word); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_long); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } + else if (REG_IS_Q(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_quad); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_b_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_SINGLE - %02x\n", uop->src_reg_b_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CVTSD2SS_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_single); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_DOUBLE - %02x\n", uop->src_reg_b_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_double); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_IMM %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV64_REG_IMM(block, uop->dest_reg_a_real, (uint64_t)uop->p); + return 0; +} +static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOVZX_REG_ABS_32_8(block, dest_reg, uop->p); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOVZX_REG_ABS_16_8(block, dest_reg, uop->p); + } + else if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOVZX_REG_PTR_8 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_16(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOVZX_REG_ABS_32_16(block, dest_reg, uop->p); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOVZX_REG_PTR_16 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVSX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVSX_REG_32_16(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVSX_REG_32_8(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVSX_REG_16_8(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOVSX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOVZX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_L(src_size)) + { + host_x86_MOVD_XREG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVD_REG_XREG(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVZX_REG_32_16(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVZX_REG_32_8(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVZX_REG_16_8(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOVZX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_MOV_DOUBLE_INT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_L(src_size)) + { + host_x86_CVTSI2SD_XREG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVSX_REG_32_16(block, REG_ECX, src_reg); + host_x86_CVTSI2SD_XREG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_D(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVQ_REG_XREG(block, REG_RCX, src_reg); + host_x86_CVTSI2SD_XREG_REG64(block, dest_reg, REG_RCX); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_DOUBLE_INT %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_D(src_size)) + { + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG_XREG(block, dest_reg, src_reg); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } + else if (REG_IS_W(dest_size) && REG_IS_D(src_size)) + { + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG_XREG(block, REG_ECX, src_reg); + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_INT_DOUBLE %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), src_64_reg = HOST_REG_GET(uop->src_reg_b_real), tag_reg = HOST_REG_GET(uop->src_reg_c_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real), src_64_size = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_D(src_size) && REG_IS_Q(src_64_size)) + { + uint32_t *branch_offset; + + /*If TAG_UINT64 is set then the source is MM[]. Otherwise it is a double in ST()*/ + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_64_reg); + host_x86_TEST8_REG(block, tag_reg, tag_reg); + branch_offset = host_x86_JS_long(block); + + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG64_XREG(block, REG_RCX, src_reg); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + host_x86_MOVQ_XREG_REG(block, dest_reg, REG_RCX); + + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_INT_DOUBLE_64 %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_NOP(codeblock_t *block, uop_t *uop) +{ + return 0; +} + +static int codegen_OR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_POR_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("OR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_x86_OR32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_x86_OR16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_x86_OR8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("OR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_PACKSSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKSSWB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKSSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PACKSSDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKSSDW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKSSDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PACKUSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKUSWB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKUSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PADDB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDUSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDUSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PCMPEQB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPEQW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPEQD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PF2ID(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_x86_LDMXCSR(block, &cpu_state.trunc_fp_control); + host_x86_CVTPS2DQ_XREG_XREG(block, dest_reg, src_reg_a); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PF2ID %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_ADDPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPEQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_EQ); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPEQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPGE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_NLT); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPGE %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPGT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_NLE); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPGT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMAX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MAXPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMAX %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMIN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MINPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMIN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MULPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFRCP(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use RCPSS + iteration)*/ + host_x86_MOV32_REG_IMM(block, REG_ECX, 1); + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_CVTSI2SS_XREG_REG(block, dest_reg, REG_ECX); + host_x86_DIVSS_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + host_x86_UNPCKLPS_XREG_XREG(block, dest_reg, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFRCP %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFRSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use RSQRTSS + iteration)*/ + host_x86_SQRTSS_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_MOV32_REG_IMM(block, REG_ECX, 1); + host_x86_CVTSI2SS_XREG_REG(block, dest_reg, REG_ECX); + host_x86_DIVSS_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + host_x86_UNPCKLPS_XREG_XREG(block, dest_reg, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFRSQRT %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_SUBPS_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBPS_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PI2FD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_x86_CVTDQ2PS_XREG_XREG(block, dest_reg, src_reg_a); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PI2FD %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} + +static int codegen_PMADDWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMADDWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PMULHW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMULHW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PMULLW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMULLW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULLW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PSLLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSLLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSLLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_PSUBB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBUSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBUSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PUNPCKHBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKHBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKHWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKHWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKHDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKHDQ_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLDQ_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_ROL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROL32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROL16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROL8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROL32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROL16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROL8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_SAR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SAR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SAR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SAR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SAR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SAR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SAR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SAR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SAR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SAR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHL32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHL16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHL8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHL32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHL16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHL8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + if (((uintptr_t)uop->p) >> 32) + fatal("STORE_PTR_IMM 64-bit addr\n"); +#endif + host_x86_MOV32_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} +static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + if (((uintptr_t)uop->p) >> 32) + fatal("STORE_PTR_IMM_8 64-bit addr\n"); +#endif + host_x86_MOV8_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} + +static int codegen_SUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (dest_reg != src_reg_a) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SUB32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SUB16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SUB8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SUB_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_TEST32_REG(block, src_reg, src_reg); + } + else if (REG_IS_W(src_size)) + { + host_x86_TEST16_REG(block, src_reg, src_reg); + } + else if (REG_IS_B(src_size)) + { + host_x86_TEST8_REG(block, src_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNS_long(block); + + return 0; +} +static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_TEST32_REG(block, src_reg, src_reg); + } + else if (REG_IS_W(src_size)) + { + host_x86_TEST16_REG(block, src_reg, src_reg); + } + else if (REG_IS_B(src_size)) + { + host_x86_TEST8_REG(block, src_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JS_long(block); + + return 0; +} + +static int codegen_XOR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PXOR_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("XOR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_x86_XOR32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_x86_XOR16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_x86_XOR8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("XOR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +const uOpFn uop_handlers[UOP_MAX] = +{ + [UOP_CALL_FUNC & UOP_MASK] = codegen_CALL_FUNC, + [UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT, + [UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC, + + [UOP_JMP & UOP_MASK] = codegen_JMP, + + [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, + + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, + [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, + [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, + [UOP_LOAD_FUNC_ARG_3 & UOP_MASK] = codegen_LOAD_FUNC_ARG3, + + [UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM, + [UOP_LOAD_FUNC_ARG_1_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG1_IMM, + [UOP_LOAD_FUNC_ARG_2_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG2_IMM, + [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, + + [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, + [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, + [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, + [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, + + [UOP_MOV & UOP_MASK] = codegen_MOV, + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + [UOP_MOVSX & UOP_MASK] = codegen_MOVSX, + [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, + [UOP_MOV_DOUBLE_INT & UOP_MASK] = codegen_MOV_DOUBLE_INT, + [UOP_MOV_INT_DOUBLE & UOP_MASK] = codegen_MOV_INT_DOUBLE, + [UOP_MOV_INT_DOUBLE_64 & UOP_MASK] = codegen_MOV_INT_DOUBLE_64, + [UOP_MOV_REG_PTR & UOP_MASK] = codegen_MOV_REG_PTR, + [UOP_MOVZX_REG_PTR_8 & UOP_MASK] = codegen_MOVZX_REG_PTR_8, + [UOP_MOVZX_REG_PTR_16 & UOP_MASK] = codegen_MOVZX_REG_PTR_16, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND & UOP_MASK] = codegen_AND, + [UOP_ANDN & UOP_MASK] = codegen_ANDN, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM, + [UOP_OR & UOP_MASK] = codegen_OR, + [UOP_OR_IMM & UOP_MASK] = codegen_OR_IMM, + [UOP_SUB & UOP_MASK] = codegen_SUB, + [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, + [UOP_XOR & UOP_MASK] = codegen_XOR, + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_SAR & UOP_MASK] = codegen_SAR, + [UOP_SAR_IMM & UOP_MASK] = codegen_SAR_IMM, + [UOP_SHL & UOP_MASK] = codegen_SHL, + [UOP_SHL_IMM & UOP_MASK] = codegen_SHL_IMM, + [UOP_SHR & UOP_MASK] = codegen_SHR, + [UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM, + [UOP_ROL & UOP_MASK] = codegen_ROL, + [UOP_ROL_IMM & UOP_MASK] = codegen_ROL_IMM, + [UOP_ROR & UOP_MASK] = codegen_ROR, + [UOP_ROR_IMM & UOP_MASK] = codegen_ROR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ, + + [UOP_CMP_JB & UOP_MASK] = codegen_CMP_JB, + [UOP_CMP_JNBE & UOP_MASK] = codegen_CMP_JNBE, + + [UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST, + [UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST, + [UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST, + [UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST, + [UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST, + [UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST, + [UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST, + [UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST, + [UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST, + [UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST, + [UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST, + [UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST, + + [UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST, + [UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST, + + [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, + [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FCOM & UOP_MASK] = codegen_FCOM, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, + [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, + [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, + + [UOP_PADDB & UOP_MASK] = codegen_PADDB, + [UOP_PADDW & UOP_MASK] = codegen_PADDW, + [UOP_PADDD & UOP_MASK] = codegen_PADDD, + [UOP_PADDSB & UOP_MASK] = codegen_PADDSB, + [UOP_PADDSW & UOP_MASK] = codegen_PADDSW, + [UOP_PADDUSB & UOP_MASK] = codegen_PADDUSB, + [UOP_PADDUSW & UOP_MASK] = codegen_PADDUSW, + + [UOP_PCMPEQB & UOP_MASK] = codegen_PCMPEQB, + [UOP_PCMPEQW & UOP_MASK] = codegen_PCMPEQW, + [UOP_PCMPEQD & UOP_MASK] = codegen_PCMPEQD, + [UOP_PCMPGTB & UOP_MASK] = codegen_PCMPGTB, + [UOP_PCMPGTW & UOP_MASK] = codegen_PCMPGTW, + [UOP_PCMPGTD & UOP_MASK] = codegen_PCMPGTD, + + [UOP_PF2ID & UOP_MASK] = codegen_PF2ID, + [UOP_PFADD & UOP_MASK] = codegen_PFADD, + [UOP_PFCMPEQ & UOP_MASK] = codegen_PFCMPEQ, + [UOP_PFCMPGE & UOP_MASK] = codegen_PFCMPGE, + [UOP_PFCMPGT & UOP_MASK] = codegen_PFCMPGT, + [UOP_PFMAX & UOP_MASK] = codegen_PFMAX, + [UOP_PFMIN & UOP_MASK] = codegen_PFMIN, + [UOP_PFMUL & UOP_MASK] = codegen_PFMUL, + [UOP_PFRCP & UOP_MASK] = codegen_PFRCP, + [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, + [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, + [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, + + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, + [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, + [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, + + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, + [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, + [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, + [UOP_PSRAW_IMM & UOP_MASK] = codegen_PSRAW_IMM, + [UOP_PSRAD_IMM & UOP_MASK] = codegen_PSRAD_IMM, + [UOP_PSRAQ_IMM & UOP_MASK] = codegen_PSRAQ_IMM, + [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, + [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, + [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, + + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, + [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, + [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, + [UOP_PSUBSB & UOP_MASK] = codegen_PSUBSB, + [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, + [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, + [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, + + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, + [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, + [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, + [UOP_PUNPCKLBW & UOP_MASK] = codegen_PUNPCKLBW, + [UOP_PUNPCKLWD & UOP_MASK] = codegen_PUNPCKLWD, + [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, + + [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP +}; + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV8_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV16_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV32_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_XREG_ABS(block, host_reg, p); +} +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV64_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_XREG_ABS(block, host_reg, p); +} +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOV8_REG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_RBP, REG_ECX, 0); +} +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_RBP, REG_ECX, 3); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_RBP, REG_ECX, 3); +} + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV8_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV16_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_XREG(block, p, host_reg); +} +void codegen_direct_write_pointer(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV64_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_XREG(block, p, host_reg); +} +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOV8_ABS_REG_REG_SHIFT_REG(block, offset, REG_RBP, REG_ECX, 0, host_reg); +} +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(block, offset, REG_RBP, REG_ECX, 3, host_reg); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_RSP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(block, offset, REG_RBP, REG_ECX, 3, host_reg); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV64_ABS_REG(block, p, host_reg); +} + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV16_REG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV32_REG_BASE_OFFSET(block, host_reg, REG_RSP, stack_offset); +} +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOVQ_XREG_BASE_OFFSET(block, host_reg, REG_RSP, stack_offset); +} +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV64_REG_BASE_OFFSET(block, host_reg, REG_RSP, stack_offset); +} +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOVQ_XREG_BASE_OFFSET(block, host_reg, REG_RSP, stack_offset); +} + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOV32_BASE_OFFSET_REG(block, REG_RSP, stack_offset, host_reg); +} +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_RSP, stack_offset, host_reg); +} +void codegen_direct_write_pointer_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOV64_BASE_OFFSET_REG(block, REG_RSP, stack_offset, host_reg); +} +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_RSP, stack_offset, host_reg); +} + +void codegen_set_jump_dest(codeblock_t *block, void *p) +{ + *(uint32_t *)p = (uintptr_t)&block_write_data[block_pos] - ((uintptr_t)p + 4); +} + +void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data) +{ + host_x86_MOV8_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data) +{ + host_x86_MOV16_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data) +{ + host_x86_MOV32_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data) +{ + host_x86_MOV32_BASE_OFFSET_IMM(block, REG_ESP, stack_offset, imm_data); +} + +#endif diff --git a/src/codegen_backend_x86.c b/src/codegen_backend_x86.c new file mode 100644 index 0000000..2fd0565 --- /dev/null +++ b/src/codegen_backend_x86.c @@ -0,0 +1,369 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" +#include "codegen_backend_x86_ops_sse.h" +#include "codegen_reg.h" +#include "x86.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +void *codegen_mem_load_byte; +void *codegen_mem_load_word; +void *codegen_mem_load_long; +void *codegen_mem_load_quad; +void *codegen_mem_load_single; +void *codegen_mem_load_double; + +void *codegen_mem_store_byte; +void *codegen_mem_store_word; +void *codegen_mem_store_long; +void *codegen_mem_store_quad; +void *codegen_mem_store_single; +void *codegen_mem_store_double; + +void *codegen_gpf_rout; +void *codegen_exit_rout; + +host_reg_def_t codegen_host_reg_list[CODEGEN_HOST_REGS] = +{ + /*Note: while EAX and EDX are normally volatile registers under x86 + calling conventions, the recompiler will explicitly save and restore + them across funcion calls*/ + {REG_EAX, 0}, + {REG_EBX, 0}, + {REG_EDX, 0} +}; + +host_reg_def_t codegen_host_fp_reg_list[CODEGEN_HOST_FP_REGS] = +{ + {REG_XMM0, HOST_REG_FLAG_VOLATILE}, + {REG_XMM1, HOST_REG_FLAG_VOLATILE}, + {REG_XMM2, HOST_REG_FLAG_VOLATILE}, + {REG_XMM3, HOST_REG_FLAG_VOLATILE}, + {REG_XMM4, HOST_REG_FLAG_VOLATILE}, + {REG_XMM5, HOST_REG_FLAG_VOLATILE} +}; + +static void build_load_routine(codeblock_t *block, int size, int is_float) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset = NULL; + + /*In - ESI = address + Out - ECX = data, ESI = abrt*/ + /*MOV ECX, ESI + SHR ESI, 12 + MOV ESI, [readlookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOVZX ECX, B[ESI+ECX] + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL readmembl + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_ECX, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV32_REG_ABS_INDEX_SHIFT(block, REG_ESI, readlookup2, REG_ESI, 2); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_ECX, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP32_REG_IMM(block, REG_ESI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1 && !is_float) + host_x86_MOVZX_BASE_INDEX_32_8(block, REG_ECX, REG_ESI, REG_ECX); + else if (size == 2 && !is_float) + host_x86_MOVZX_BASE_INDEX_32_16(block, REG_ECX, REG_ESI, REG_ECX); + else if (size == 4 && !is_float) + host_x86_MOV32_REG_BASE_INDEX(block, REG_ECX, REG_ESI, REG_ECX); + else if (size == 4 && is_float) + host_x86_CVTSS2SD_XREG_BASE_INDEX(block, REG_XMM_TEMP, REG_ESI, REG_ECX); + else if (size == 8) + host_x86_MOVQ_XREG_BASE_INDEX(block, REG_XMM_TEMP, REG_ESI, REG_ECX); + else + fatal("build_load_routine: size=%i\n", size); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; + host_x86_PUSH(block, REG_EAX); + host_x86_PUSH(block, REG_EDX); + host_x86_PUSH(block, REG_ECX); + if (size == 1) + host_x86_CALL(block, (void *)readmembl); + else if (size == 2) + host_x86_CALL(block, (void *)readmemwl); + else if (size == 4) + host_x86_CALL(block, (void *)readmemll); + else if (size == 8) + host_x86_CALL(block, (void *)readmemql); + host_x86_POP(block, REG_ECX); + if (size == 1 && !is_float) + host_x86_MOVZX_REG_32_8(block, REG_ECX, REG_EAX); + else if (size == 2 && !is_float) + host_x86_MOVZX_REG_32_16(block, REG_ECX, REG_EAX); + else if (size == 4 && !is_float) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + else if (size == 4 && is_float) + { + host_x86_MOVD_XREG_REG(block, REG_XMM_TEMP, REG_EAX); + host_x86_CVTSS2SD_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + } + else if (size == 8) + { + host_x86_MOVD_XREG_REG(block, REG_XMM_TEMP, REG_EAX); + host_x86_MOVD_XREG_REG(block, REG_XMM_TEMP2, REG_EDX); + host_x86_UNPCKLPS_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP2); + } + host_x86_POP(block, REG_EDX); + host_x86_POP(block, REG_EAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); + block_pos = (block_pos + 63) & ~63; +} + +static void build_store_routine(codeblock_t *block, int size, int is_float) +{ + uint8_t *branch_offset; + uint8_t *misaligned_offset = NULL; + + /*In - ECX = data, ESI = address + Out - ESI = abrt + Corrupts EDI*/ + /*MOV EDI, ESI + SHR ESI, 12 + MOV ESI, [writelookup2+ESI*4] + CMP ESI, -1 + JNZ + + MOV [ESI+EDI], ECX + XOR ESI,ESI + RET + * PUSH EAX + PUSH EDX + PUSH ECX + CALL writemembl + POP ECX + POP EDX + POP EAX + MOVZX ECX, AL + RET + */ + host_x86_MOV32_REG_REG(block, REG_EDI, REG_ESI); + host_x86_SHR32_IMM(block, REG_ESI, 12); + host_x86_MOV32_REG_ABS_INDEX_SHIFT(block, REG_ESI, writelookup2, REG_ESI, 2); + if (size != 1) + { + host_x86_TEST32_REG_IMM(block, REG_EDI, size-1); + misaligned_offset = host_x86_JNZ_short(block); + } + host_x86_CMP32_REG_IMM(block, REG_ESI, (uint32_t)-1); + branch_offset = host_x86_JZ_short(block); + if (size == 1 && !is_float) + host_x86_MOV8_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else if (size == 2 && !is_float) + host_x86_MOV16_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else if (size == 4 && !is_float) + host_x86_MOV32_BASE_INDEX_REG(block, REG_ESI, REG_EDI, REG_ECX); + else if (size == 4 && is_float) + host_x86_MOVD_BASE_INDEX_XREG(block, REG_ESI, REG_EDI, REG_XMM_TEMP); + else if (size == 8) + host_x86_MOVQ_BASE_INDEX_XREG(block, REG_ESI, REG_EDI, REG_XMM_TEMP); + else + fatal("build_store_routine: size=%i is_float=%i\n", size, is_float); + host_x86_XOR32_REG_REG(block, REG_ESI, REG_ESI); + host_x86_RET(block); + + *branch_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 1; + if (size != 1) + *misaligned_offset = (uint8_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)misaligned_offset) - 1; + if (size == 4 && is_float) + host_x86_MOVD_REG_XREG(block, REG_ECX, REG_XMM_TEMP); + host_x86_PUSH(block, REG_EAX); + host_x86_PUSH(block, REG_EDX); + host_x86_PUSH(block, REG_ECX); + if (size == 8) + { + host_x86_MOVQ_STACK_OFFSET_XREG(block, -8, REG_XMM_TEMP); + host_x86_SUB32_REG_IMM(block, REG_ESP, 8); + } + host_x86_PUSH(block, REG_EDI); + if (size == 1) + host_x86_CALL(block, (void *)writemembl); + else if (size == 2) + host_x86_CALL(block, (void *)writememwl); + else if (size == 4) + host_x86_CALL(block, (void *)writememll); + else if (size == 8) + host_x86_CALL(block, (void *)writememql); + host_x86_POP(block, REG_EDI); + if (size == 8) + host_x86_ADD32_REG_IMM(block, REG_ESP, 8); + host_x86_POP(block, REG_ECX); + host_x86_POP(block, REG_EDX); + host_x86_POP(block, REG_EAX); + host_x86_MOVZX_REG_ABS_32_8(block, REG_ESI, &cpu_state.abrt); + host_x86_RET(block); + block_pos = (block_pos + 63) & ~63; +} + +static void build_loadstore_routines(codeblock_t *block) +{ + codegen_mem_load_byte = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 1, 0); + codegen_mem_load_word = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 2, 0); + codegen_mem_load_long = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4, 0); + codegen_mem_load_quad = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 8, 0); + codegen_mem_load_single = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 4, 1); + codegen_mem_load_double = &codeblock[block_current].data[block_pos]; + build_load_routine(block, 8, 1); + + codegen_mem_store_byte = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 1, 0); + codegen_mem_store_word = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 2, 0); + codegen_mem_store_long = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4, 0); + codegen_mem_store_quad = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 8, 0); + codegen_mem_store_single = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 4, 1); + codegen_mem_store_double = &codeblock[block_current].data[block_pos]; + build_store_routine(block, 8, 1); +} + +void codegen_backend_init() +{ + codeblock_t *block; + int c; +#if defined(__linux__) || defined(__APPLE__) + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif +pclog("sizeof(codeblock_t)=%i\n", sizeof(codeblock_t)); +pclog(" offsetof(codeblock_t, pc)=%i\n", offsetof(codeblock_t, pc)); +pclog(" offsetof(codeblock_t, _cs)=%i\n", offsetof(codeblock_t, _cs)); +pclog(" offsetof(codeblock_t, phys)=%i\n", offsetof(codeblock_t, phys)); +pclog(" offsetof(codeblock_t, phys_2)=%i\n", offsetof(codeblock_t, phys_2)); +pclog(" offsetof(codeblock_t, status)=%i\n", offsetof(codeblock_t, status)); +pclog(" offsetof(codeblock_t, flags)=%i\n", offsetof(codeblock_t, flags)); +pclog(" offsetof(codeblock_t, ins)=%i\n", offsetof(codeblock_t, ins)); +pclog(" offsetof(codeblock_t, TOP)=%i\n", offsetof(codeblock_t, TOP)); +pclog(" offsetof(codeblock_t, parent)=%i\n", offsetof(codeblock_t, parent)); +pclog(" offsetof(codeblock_t, left)=%i\n", offsetof(codeblock_t, left)); +pclog(" offsetof(codeblock_t, right)=%i\n", offsetof(codeblock_t, right)); +pclog(" offsetof(codeblock_t, data)=%i\n", offsetof(codeblock_t, data)); +pclog(" offsetof(codeblock_t, page_mask)=%i\n", offsetof(codeblock_t, page_mask)); +pclog(" offsetof(codeblock_t, page_mask2)=%i\n", offsetof(codeblock_t, page_mask2)); +pclog(" offsetof(codeblock_t, dirty_mask)=%i\n", offsetof(codeblock_t, dirty_mask)); +pclog(" offsetof(codeblock_t, dirty_mask2)=%i\n", offsetof(codeblock_t, dirty_mask2)); +pclog(" offsetof(codeblock_t, prev)=%i\n", offsetof(codeblock_t, prev)); +pclog(" offsetof(codeblock_t, next)=%i\n", offsetof(codeblock_t, next)); +pclog(" offsetof(codeblock_t, prev_2)=%i\n", offsetof(codeblock_t, prev_2)); +pclog(" offsetof(codeblock_t, next_2)=%i\n", offsetof(codeblock_t, next_2)); + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); + 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 *)); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].pc = BLOCK_PC_INVALID; + +// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); + + block_current = 0; + block_pos = 0; + block = &codeblock[block_current]; + block->head_mem_block = codegen_allocator_allocate(NULL, block_current); + block->data = codeblock_allocator_get_ptr(block->head_mem_block); + block_write_data = block->data; + build_loadstore_routines(block); + + codegen_gpf_rout = &codeblock[block_current].data[block_pos]; + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, 0); + host_x86_MOV32_STACK_IMM(block, STACK_ARG1, 0); + host_x86_CALL(block, (void *)x86gpf); + codegen_exit_rout = &codeblock[block_current].data[block_pos]; + host_x86_ADD32_REG_IMM(block, REG_ESP, 64); + host_x86_POP(block, REG_EDI); + host_x86_POP(block, REG_ESI); + host_x86_POP(block, REG_EBP); + host_x86_POP(block, REG_EDX); + host_x86_RET(block); + block_write_data = NULL; + + cpu_state.old_fp_control = 0; + asm( + "fstcw %0\n" + "stmxcsr %1\n" + : "=m" (cpu_state.old_fp_control2), + "=m" (cpu_state.old_fp_control) + ); + cpu_state.trunc_fp_control = cpu_state.old_fp_control | 0x6000; +} + +void codegen_set_rounding_mode(int mode) +{ + /*SSE*/ + cpu_state.new_fp_control = (cpu_state.old_fp_control & ~0x6000) | (mode << 13); + /*x87 - used for double -> i64 conversions*/ + cpu_state.new_fp_control2 = (cpu_state.old_fp_control2 & ~0x0c00) | (mode << 10); +} + +void codegen_backend_prologue(codeblock_t *block) +{ + block_pos = BLOCK_START; /*Entry code*/ + host_x86_PUSH(block, REG_EBX); + host_x86_PUSH(block, REG_EBP); + host_x86_PUSH(block, REG_ESI); + host_x86_PUSH(block, REG_EDI); + host_x86_SUB32_REG_IMM(block, REG_ESP, 64); + host_x86_MOV32_REG_IMM(block, REG_EBP, ((uintptr_t)&cpu_state) + 128); + if (block->flags & CODEBLOCK_HAS_FPU) + { + host_x86_MOV32_REG_ABS(block, REG_EAX, &cpu_state.TOP); + host_x86_SUB32_REG_IMM(block, REG_EAX, block->TOP); + host_x86_MOV32_BASE_OFFSET_REG(block, REG_ESP, IREG_TOP_diff_stack_offset, REG_EAX); + } +} + +void codegen_backend_epilogue(codeblock_t *block) +{ + host_x86_ADD32_REG_IMM(block, REG_ESP, 64); + host_x86_POP(block, REG_EDI); + host_x86_POP(block, REG_ESI); + host_x86_POP(block, REG_EBP); + host_x86_POP(block, REG_EDX); + host_x86_RET(block); +} + +#endif diff --git a/src/codegen_backend_x86.h b/src/codegen_backend_x86.h new file mode 100644 index 0000000..7f9f233 --- /dev/null +++ b/src/codegen_backend_x86.h @@ -0,0 +1,14 @@ +#include "codegen_backend_x86_defs.h" + +#define BLOCK_SIZE 0x10000 +#define BLOCK_MASK 0xffff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_MAX 0x3c0 + +#define CODEGEN_BACKEND_HAS_MOV_IMM diff --git a/src/codegen_backend_x86_defs.h b/src/codegen_backend_x86_defs.h new file mode 100644 index 0000000..8999ca3 --- /dev/null +++ b/src/codegen_backend_x86_defs.h @@ -0,0 +1,50 @@ +#ifndef _CODEGEN_BACKEND_X86_DEFS_H_ +#define _CODEGEN_BACKEND_X86_DEFS_H_ + +#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_XMM0 0 +#define REG_XMM1 1 +#define REG_XMM2 2 +#define REG_XMM3 3 +#define REG_XMM4 4 +#define REG_XMM5 5 +#define REG_XMM6 6 +#define REG_XMM7 7 + +#define REG_XMM_TEMP REG_XMM7 +#define REG_XMM_TEMP2 REG_XMM6 + +#define CODEGEN_HOST_REGS 3 +#define CODEGEN_HOST_FP_REGS 6 + +extern void *codegen_mem_load_byte; +extern void *codegen_mem_load_word; +extern void *codegen_mem_load_long; +extern void *codegen_mem_load_quad; +extern void *codegen_mem_load_single; +extern void *codegen_mem_load_double; + +extern void *codegen_mem_store_byte; +extern void *codegen_mem_store_word; +extern void *codegen_mem_store_long; +extern void *codegen_mem_store_quad; +extern void *codegen_mem_store_single; +extern void *codegen_mem_store_double; + +extern void *codegen_gpf_rout; +extern void *codegen_exit_rout; + +#define STACK_ARG0 (0) +#define STACK_ARG1 (4) +#define STACK_ARG2 (8) +#define STACK_ARG3 (12) + +#endif diff --git a/src/codegen_backend_x86_ops.c b/src/codegen_backend_x86_ops.c new file mode 100644 index 0000000..7c8a18d --- /dev/null +++ b/src/codegen_backend_x86_ops.c @@ -0,0 +1,1330 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" +#include "codegen_backend_x86_ops_helpers.h" + +#define RM_OP_ADD 0x00 +#define RM_OP_OR 0x08 +#define RM_OP_AND 0x20 +#define RM_OP_SUB 0x28 +#define RM_OP_XOR 0x30 +#define RM_OP_CMP 0x38 + +#define RM_OP_ROL 0x00 +#define RM_OP_ROR 0x08 +#define RM_OP_SHL 0x20 +#define RM_OP_SHR 0x28 +#define RM_OP_SAR 0x38 + +void host_x86_ADD32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x03, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x03); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x04, imm_data); /*ADD AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_ADD | dst_reg, imm_data); /*ADD dst_reg, imm_data*/ + } +} +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_ADD | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x05); /*ADD AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_ADD | dst_reg); /*ADD dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_ADD | dst_reg, imm_data & 0xff); /*ADD dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x05); /*ADD EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_ADD | dst_reg); /*ADD dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x00, 0xc0 | dst_reg | (src_reg << 3)); /*ADD dst_reg, src_reg*/ +} +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x01, 0xc0 | dst_reg | (src_reg << 3)); /*ADD dst_reg, src_reg*/ +} +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte2(block, 0x01, 0xc0 | dst_reg | (src_reg << 3)); /*ADD dst_reg, src_reg*/ +} + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x24, imm_data); /*AND AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_AND | dst_reg, imm_data); /*AND dst_reg, imm_data*/ + } +} +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_AND | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x66, 0x25); /*AND AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_AND | dst_reg); /*AND dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_AND | dst_reg, imm_data & 0xff); /*AND dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x25); /*AND EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_AND | dst_reg); /*AND dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x20, 0xc0 | dst_reg | (src_reg << 3)); /*AND dst_reg, src_reg_b*/ +} +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x21, 0xc0 | dst_reg | (src_reg << 3)); /*AND dst_reg, src_reg_b*/ +} +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x21, 0xc0 | dst_reg | (src_reg << 3)); /*AND dst_reg, src_reg_b*/ +} + +void host_x86_CALL(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xe8); /*CALL*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} + +void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x3d); /*CMP AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_CMP | dst_reg, imm_data & 0xff); /*CMP dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x3d); /*CMP EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_CMP | dst_reg); /*CMP dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x38, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} +void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} +void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x39, 0xc0 | src_reg_a | (src_reg_b << 3)); /*CMP src_reg_a, src_reg_b*/ +} + +void host_x86_INC32_ABS(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0xff, 0x05); /*INC p*/ + codegen_addlong(block, (uint32_t)p); +} + +void host_x86_JMP(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} +uint32_t *host_x86_JMP_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_x86_JNZ(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} +void host_x86_JZ(codeblock_t *block, void *p) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, (uintptr_t)p - (uintptr_t)&block_write_data[block_pos + 4]); +} + +uint8_t *host_x86_JNZ_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x75, 0); /*JNZ*/ + return &block_write_data[block_pos-1]; +} +uint8_t *host_x86_JS_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x78, 0); /*JS*/ + return &block_write_data[block_pos-1]; +} +uint8_t *host_x86_JZ_short(codeblock_t *block) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x74, 0); /*JZ*/ + return &block_write_data[block_pos-1]; +} + +uint32_t *host_x86_JNB_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x83); /*JNB*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNBE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x87); /*JNBE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNL_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8d); /*JNL*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNLE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8f); /*JNLE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNO_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x81); /*JNO*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNS_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x89); /*JNS*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JNZ_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x85); /*JNZ*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JB_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x82); /*JB*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JBE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x86); /*JBE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JL_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8c); /*JL*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JLE_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x8e); /*JLE*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JO_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x80); /*JO*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JS_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x88); /*JS*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} +uint32_t *host_x86_JZ_long(codeblock_t *block) +{ + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x0f, 0x84); /*JZ*/ + codegen_addlong(block, 0); + return (uint32_t *)&block_write_data[block_pos-4]; +} + +void host_x86_LAHF(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x9f); /*LAHF*/ +} + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint32_t offset) +{ + if (offset) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x8d, 0x80 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [offset+src_reg]*/ + codegen_addlong(block, offset); + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x8d, 0x00 | (dst_reg << 3) | src_reg); /*LEA dst_reg, [src_reg]*/ + } +} + +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b]*/ +} +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8d, 0x04 | (dst_reg << 3), (shift << 6) | (src_reg_b << 3) | src_reg_a); /*LEA dst_reg, [src_reg_a + src_reg_b * (1 << shift)]*/ +} + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte3(block, 0xc6, 0x45, offset); /*MOVB offset[EBP], imm_data*/ + codegen_addbyte(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte2(block, 0xc6, 0x05); /*MOVB p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addbyte(block, imm_data); + } +} +void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0x66, 0xc7, 0x05); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addword(block, imm_data); + } +} +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x45, offset); /*MOV offset[EBP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 10); + codegen_addbyte2(block, 0xc7, 0x05); /*MOV p, imm_data*/ + codegen_addlong(block, (uint32_t)p); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x88, 0x45 | (src_reg << 3), offset); /*MOVB offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x88); /*MOVB [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x89, 0x05 | (src_reg << 3)); /*MOV [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x45 | (src_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x89); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (src_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int idx_reg, int shift, int src_reg) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x88, 0x44 | (src_reg << 3), base_reg | (idx_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x88, 0x84 | (src_reg << 3), base_reg | (idx_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x88, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV B[base_reg + idx_reg], src_reg*/ +} +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV W[base_reg + idx_reg], src_reg*/ +} +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x04 | (src_reg << 3), base_reg | (idx_reg << 3)); /*MOV L[base_reg + idx_reg], src_reg*/ +} + +void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8a, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x8a); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x8b, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x8b, 0x05 | (dst_reg << 3)); /*MOV [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x45 | (dst_reg << 3), offset); /*MOV offset[EBP], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte(block, 0x8b); /*MOV [p], src_reg*/ + codegen_addbyte(block, 0x05 | (dst_reg << 3)); + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOV32_REG_ABS_INDEX_SHIFT(codeblock_t *block, int dst_reg, void *p, int idx_reg, int shift) +{ + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), (shift << 6) | (idx_reg << 3) | 0x05); /*MOV dst_reg, [p + idx_reg << shift]*/ + codegen_addlong(block, (uint32_t)p); +} + +void host_x86_MOV8_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int base_reg, int idx_reg, int shift) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x8a, 0x44 | (dst_reg << 3), base_reg | (idx_reg << 3) | (shift << 6), addr & 0xff); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x8a, 0x84 | (dst_reg << 3), base_reg | (idx_reg << 3) | (shift << 6)); /*MOV addr[base_reg + idx_reg << shift], src_reg*/ + codegen_addlong(block, addr); + } +} + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOV dst_reg, L[base_reg + idx_reg]*/ +} + +void host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV16_REG_BASE_OFFSET - offset %i\n", offset); +} +void host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x8b, 0x40 | base_reg | (dst_reg << 3), offset); + } + } + else + fatal("MOV32_REG_BASE_OFFSET - offset %i\n", offset); +} + +void host_x86_MOV16_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + } + } + else + fatal("MOV16_BASE_OFFSET_REG - offset %i\n", offset); +} +void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x89, 0x40 | base_reg | (src_reg << 3), 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x89, 0x40 | base_reg | (src_reg << 3), offset); + } + } + else + fatal("MOV32_BASE_OFFSET_REG - offset %i\n", offset); +} + +void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xc7, 0x40 | base_reg, 0x24, offset); + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x40 | base_reg, offset); + codegen_addlong(block, imm_data); + } + } + else + fatal("MOV32_BASE_OFFSET_IMM - offset %i\n", offset); +} + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xb0 + dst_reg, imm_data); /*MOV reg, imm_data*/ +} +void host_x86_MOV16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (!imm_data) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x66, 0xb8 + dst_reg); /*MOV reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (!imm_data) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (dst_reg << 3)); /*XOR dst_reg, dst_reg*/ + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xb8 + dst_reg); /*MOV reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x88, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x89, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x89, 0xc0 | dst_reg | (src_reg << 3)); +} + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data) +{ + if (!offset) + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0xc7, 0x04, 0x24); /*MOV [ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else if (offset >= -0x80 && offset < 0x80) + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xc7, 0x44, 0x24, offset & 0xff); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 11); + codegen_addbyte3(block, 0xc7, 0x84, 0x24); /*MOV offset[ESP], imm_data*/ + codegen_addlong(block, offset); + codegen_addlong(block, imm_data); + } +} + +void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} +void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xbe, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} +void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xbf, 0xc0 | (dst_reg << 3) | src_reg); /*MOVSX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x66); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | (dst_reg << 3), offset); /*MOV dest_reg, [EBP+offset]*/ + } + else + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x66, 0x0f, 0xb6, 0x05 | (dst_reg << 3)); /*MOVZX dst_reg, [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb6, 0x45 | (dst_reg << 3), offset); /*MOV dest_reg, [EBP+offset]*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x0f, 0xb6, 0x05 | (dst_reg << 3)); /*MOVZX dst_reg, [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb7, 0x45 | (dst_reg << 3), offset); /*MOV dest_reg, [EBP+offset]*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x0f, 0xb7, 0x05 | (dst_reg << 3)); /*MOVZX dst_reg, [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MOVZX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xb6, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0xb7, 0xc0 | (dst_reg << 3) | src_reg); /*MOVZX dst_reg, src_reg*/ +} + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb6, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOVZX dst_reg, B[base_reg + idx_reg]*/ +} +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xb7, 0x04 | (dst_reg << 3), base_reg | (idx_reg << 3)); /*MOVZX dst_reg, W[base_reg + idx_reg]*/ +} + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x08, 0xc0 | dst_reg | (src_reg << 3)); /*OR dst_reg, src_reg_b*/ +} +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x09, 0xc0 | dst_reg | (src_reg << 3)); /*OR dst_reg, src_reg_b*/ +} +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x09, 0xc0 | dst_reg | (src_reg << 3)); /*OR dst_reg, src_reg_b*/ +} + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x0c, imm_data); /*OR AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_OR | dst_reg, imm_data); /*OR dst_reg, imm_data*/ + } +} +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_OR | dst_reg, imm_data & 0xff); /*OR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x66, 0x0d); /*OR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_OR | dst_reg); /*OR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_OR | dst_reg, imm_data & 0xff); /*OR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x0d); /*OR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_OR | dst_reg); /*OR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_POP(codeblock_t *block, int src_reg) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x58 | src_reg); /*POP reg*/ +} + +void host_x86_PUSH(codeblock_t *block, int src_reg) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0x50 | src_reg); /*PUSH reg*/ +} + +void host_x86_RET(codeblock_t *block) +{ + codegen_alloc_bytes(block, 1); + codegen_addbyte(block, 0xc3); /*RET*/ +} + +void host_x86_ROL8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_ROL16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_ROL32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_ROL | dst_reg); /*SHL dst_reg, CL*/ +} + +void host_x86_ROL8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_ROL16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_ROL32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_ROL | dst_reg, shift); /*SHL dst_reg, shift*/ +} + +void host_x86_ROR8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_ROR16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_ROR32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_ROR | dst_reg); /*SHR dst_reg, CL*/ +} + +void host_x86_ROR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_ROR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_ROR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_ROR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +#define MODRM_MOD_REG(rm, reg) (0xc0 | reg | (rm << 3)) + +void host_x86_SAR8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} +void host_x86_SAR16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} +void host_x86_SAR32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SAR | dst_reg); /*SAR dst_reg, CL*/ +} + +void host_x86_SAR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} +void host_x86_SAR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} +void host_x86_SAR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SAR | dst_reg, shift); /*SAR dst_reg, shift*/ +} + +void host_x86_SHL8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_SHL16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} +void host_x86_SHL32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SHL | dst_reg); /*SHL dst_reg, CL*/ +} + +void host_x86_SHL8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_SHL16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} +void host_x86_SHL32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHL | dst_reg, shift); /*SHL dst_reg, shift*/ +} + +void host_x86_SHR8_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd2, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_SHR16_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0xd3, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} +void host_x86_SHR32_CL(codeblock_t *block, int dst_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xd3, 0xc0 | RM_OP_SHR | dst_reg); /*SHR dst_reg, CL*/ +} + +void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc0, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xc1, 0xc0 | RM_OP_SHR | dst_reg, shift); /*SHR dst_reg, shift*/ +} + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x2c, imm_data); /*SUB AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_SUB | dst_reg, imm_data); /*SUB dst_reg, imm_data*/ + } +} +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_SUB | dst_reg, imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x2d); /*SUB AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_SUB | dst_reg); /*SUB dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_SUB | dst_reg, imm_data & 0xff); /*SUB dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x2d); /*SUB EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_SUB | dst_reg); /*SUB dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x28, 0xc0 | dst_reg | (src_reg << 3)); /*SUB dst_reg, src_reg*/ +} +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x29, 0xc0 | dst_reg | (src_reg << 3)); /*SUB dst_reg, src_reg*/ +} +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x29, 0xc0 | dst_reg | (src_reg << 3)); /*SUB dst_reg, src_reg*/ +} + +void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x84, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x85, MODRM_MOD_REG(dst_host_reg, src_host_reg)); /*TEST dst_host_reg, src_host_reg*/ +} +void host_x86_TEST32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0xa9); /*TEST EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0xf7, 0xc0 | dst_reg); /*TEST dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x30, 0xc0 | dst_reg | (src_reg << 3)); /*XOR dst_reg, src_reg*/ +} +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x66, 0x31, 0xc0 | dst_reg | (src_reg << 3)); /*XOR dst_reg, src_reg*/ +} +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x31, 0xc0 | dst_reg | (src_reg << 3)); /*XOR dst_reg, src_reg*/ +} + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data) +{ + if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0x34, imm_data); /*XOR AL, imm_data*/ + } + else + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x80, 0xc0 | RM_OP_XOR | dst_reg, imm_data); /*XOR dst_reg, imm_data*/ + } +} +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x83, 0xc0 | RM_OP_XOR | dst_reg, imm_data & 0xff); /*XOR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte2(block, 0x66, 0x35); /*XOR AX, imm_data*/ + codegen_addword(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte3(block, 0x66, 0x81, 0xc0 | RM_OP_XOR | dst_reg); /*XOR dst_reg, imm_data*/ + codegen_addword(block, imm_data); + } +} +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data) +{ + if (is_imm8(imm_data)) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x83, 0xc0 | RM_OP_XOR | dst_reg, imm_data & 0xff); /*XOR dst_reg, imm_data*/ + } + else if (dst_reg == REG_EAX) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte(block, 0x35); /*XOR EAX, imm_data*/ + codegen_addlong(block, imm_data); + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0x81, 0xc0 | RM_OP_XOR | dst_reg); /*XOR dst_reg, imm_data*/ + codegen_addlong(block, imm_data); + } +} + +#endif diff --git a/src/codegen_backend_x86_ops.h b/src/codegen_backend_x86_ops.h new file mode 100644 index 0000000..a6ca19f --- /dev/null +++ b/src/codegen_backend_x86_ops.h @@ -0,0 +1,195 @@ +void host_x86_ADD32_REG_ABS(codeblock_t *block, int dst_reg, void *p); + +void host_x86_ADD8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_ADD16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_ADD32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_ADD8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADD16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADD32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_AND8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_AND16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_AND32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_AND8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_AND16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_AND32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CALL(codeblock_t *block, void *p); + +void host_x86_CMP16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_CMP32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_CMP8_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_CMP16_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); +void host_x86_CMP32_REG_REG(codeblock_t *block, int src_reg_a, int src_reg_b); + +void host_x86_INC32_ABS(codeblock_t *block, void *p); + +void host_x86_JMP(codeblock_t *block, void *p); +uint32_t *host_x86_JMP_short(codeblock_t *block); +uint32_t *host_x86_JMP_long(codeblock_t *block); + +void host_x86_JNZ(codeblock_t *block, void *p); +void host_x86_JZ(codeblock_t *block, void *p); + +uint8_t *host_x86_JNZ_short(codeblock_t *block); +uint8_t *host_x86_JS_short(codeblock_t *block); +uint8_t *host_x86_JZ_short(codeblock_t *block); + +uint32_t *host_x86_JNB_long(codeblock_t *block); +uint32_t *host_x86_JNBE_long(codeblock_t *block); +uint32_t *host_x86_JNL_long(codeblock_t *block); +uint32_t *host_x86_JNLE_long(codeblock_t *block); +uint32_t *host_x86_JNO_long(codeblock_t *block); +uint32_t *host_x86_JNS_long(codeblock_t *block); +uint32_t *host_x86_JNZ_long(codeblock_t *block); +uint32_t *host_x86_JB_long(codeblock_t *block); +uint32_t *host_x86_JBE_long(codeblock_t *block); +uint32_t *host_x86_JL_long(codeblock_t *block); +uint32_t *host_x86_JLE_long(codeblock_t *block); +uint32_t *host_x86_JO_long(codeblock_t *block); +uint32_t *host_x86_JS_long(codeblock_t *block); +uint32_t *host_x86_JZ_long(codeblock_t *block); + +void host_x86_LAHF(codeblock_t *block); + +void host_x86_LEA_REG_IMM(codeblock_t *block, int dst_reg, int src_reg_a, uint32_t offset); +void host_x86_LEA_REG_REG(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b); +void host_x86_LEA_REG_REG_SHIFT(codeblock_t *block, int dst_reg, int src_reg_a, int src_reg_b, int shift); + +void host_x86_MOV8_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); +void host_x86_MOV16_ABS_IMM(codeblock_t *block, void *p, uint16_t imm_data); +void host_x86_MOV32_ABS_IMM(codeblock_t *block, void *p, uint32_t imm_data); + +void host_x86_MOV8_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV16_ABS_REG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOV32_ABS_REG(codeblock_t *block, void *p, int src_reg); + +void host_x86_MOV8_ABS_REG_REG_SHIFT_REG(codeblock_t *block, uint32_t addr, int base_reg, int idx_reg, int shift, int src_reg); + +void host_x86_MOV8_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOV16_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOV32_BASE_INDEX_REG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); + +void host_x86_MOV16_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int dst_reg); +void host_x86_MOV32_BASE_OFFSET_REG(codeblock_t *block, int base_reg, int offset, int dst_reg); + +void host_x86_MOV32_BASE_OFFSET_IMM(codeblock_t *block, int base_reg, int offset, uint32_t imm_data); + +void host_x86_MOV8_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV16_REG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOV32_REG_ABS(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOV32_REG_ABS_INDEX_SHIFT(codeblock_t *block, int dst_reg, void *p, int idx_reg, int shift); + +void host_x86_MOV8_REG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_addr, uint32_t addr, int base_reg, int idx_reg, int shift); + +void host_x86_MOV32_REG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_MOV16_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); +void host_x86_MOV32_REG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); + +void host_x86_MOV8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_MOV16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_MOV32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_MOV8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOV32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +#define host_x86_MOV16_STACK_REG(block, offset, src_reg) host_x86_MOV16_BASE_OFFSET_REG(block, REG_ESP, offset, src_reg) + +void host_x86_MOV32_STACK_IMM(codeblock_t *block, int32_t offset, uint32_t imm_data); + +void host_x86_MOVSX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVSX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVSX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_REG_16_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_8(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVZX_REG_32_16(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVZX_REG_ABS_16_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVZX_REG_ABS_32_8(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVZX_REG_ABS_32_16(codeblock_t *block, int dst_reg, void *p); + +void host_x86_MOVZX_BASE_INDEX_32_8(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVZX_BASE_INDEX_32_16(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_OR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_OR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_OR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_OR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_OR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_OR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_POP(codeblock_t *block, int src_reg); + +void host_x86_PUSH(codeblock_t *block, int src_reg); + +void host_x86_RET(codeblock_t *block); + +void host_x86_ROL8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROL16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROL32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_ROL8_CL(codeblock_t *block, int dst_reg); +void host_x86_ROL16_CL(codeblock_t *block, int dst_reg); +void host_x86_ROL32_CL(codeblock_t *block, int dst_reg); + +void host_x86_ROR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_ROR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_ROR8_CL(codeblock_t *block, int dst_reg); +void host_x86_ROR16_CL(codeblock_t *block, int dst_reg); +void host_x86_ROR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SAR8_CL(codeblock_t *block, int dst_reg); +void host_x86_SAR16_CL(codeblock_t *block, int dst_reg); +void host_x86_SAR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SAR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SAR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SAR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SHL8_CL(codeblock_t *block, int dst_reg); +void host_x86_SHL16_CL(codeblock_t *block, int dst_reg); +void host_x86_SHL32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SHL8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHL16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHL32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SHR8_CL(codeblock_t *block, int dst_reg); +void host_x86_SHR16_CL(codeblock_t *block, int dst_reg); +void host_x86_SHR32_CL(codeblock_t *block, int dst_reg); + +void host_x86_SHR8_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHR16_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_SHR32_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_SUB8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_SUB16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_SUB32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); + +void host_x86_SUB8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUB16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUB32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_TEST8_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST16_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); +void host_x86_TEST32_REG(codeblock_t *block, int src_host_reg, int dst_host_reg); + +void host_x86_TEST32_REG_IMM(codeblock_t *block, int src_host_reg, uint32_t imm_data); + +void host_x86_XOR8_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_XOR16_REG_REG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_XOR32_REG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_XOR8_REG_IMM(codeblock_t *block, int dst_reg, uint8_t imm_data); +void host_x86_XOR16_REG_IMM(codeblock_t *block, int dst_reg, uint16_t imm_data); +void host_x86_XOR32_REG_IMM(codeblock_t *block, int dst_reg, uint32_t imm_data); diff --git a/src/codegen_backend_x86_ops_fpu.c b/src/codegen_backend_x86_ops_fpu.c new file mode 100644 index 0000000..1c3f990 --- /dev/null +++ b/src/codegen_backend_x86_ops_fpu.c @@ -0,0 +1,80 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops_fpu.h" +#include "codegen_backend_x86_ops_helpers.h" + +void host_x87_FILDq_BASE(codeblock_t *block, int base_reg) +{ + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xdf, 0x2c, 0x24); /*FILDq [ESP]*/ + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xdf, 0x28 | base_reg); /*FILDq [base_reg]*/ + } +} +void host_x87_FISTPq_BASE(codeblock_t *block, int base_reg) +{ + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xdf, 0x3c, 0x24); /*FISTPq [ESP]*/ + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xdf, 0x38 | base_reg); /*FISTPq [base_reg]*/ + } +} +void host_x87_FLDCW(codeblock_t *block, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xd9, 0x68 | REG_EBP, offset); /*FLDCW offset[EBP]*/ + } + else + { + codegen_alloc_bytes(block, 6); + codegen_addbyte2(block, 0xd9, 0x2d); /*FLDCW [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x87_FLDd_BASE(codeblock_t *block, int base_reg) +{ + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xdd, 0x04, 0x24); /*FILDq [ESP]*/ + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xdd, 0x08 | base_reg); /*FILDq [base_reg]*/ + } +} +void host_x87_FSTPd_BASE(codeblock_t *block, int base_reg) +{ + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0xdd, 0x1c, 0x24); /*FILDq [ESP]*/ + } + else + { + codegen_alloc_bytes(block, 2); + codegen_addbyte2(block, 0xdd, 0x18 | base_reg); /*FILDq [base_reg]*/ + } +} + +#endif diff --git a/src/codegen_backend_x86_ops_fpu.h b/src/codegen_backend_x86_ops_fpu.h new file mode 100644 index 0000000..3692715 --- /dev/null +++ b/src/codegen_backend_x86_ops_fpu.h @@ -0,0 +1,5 @@ +void host_x87_FILDq_BASE(codeblock_t *block, int base_reg); +void host_x87_FISTPq_BASE(codeblock_t *block, int base_reg); +void host_x87_FLDCW(codeblock_t *block, void *p); +void host_x87_FLDd_BASE(codeblock_t *block, int base_reg); +void host_x87_FSTPd_BASE(codeblock_t *block, int base_reg); diff --git a/src/codegen_backend_x86_ops_helpers.h b/src/codegen_backend_x86_ops_helpers.h new file mode 100644 index 0000000..9c100ec --- /dev/null +++ b/src/codegen_backend_x86_ops_helpers.h @@ -0,0 +1,84 @@ +#define JMP_LEN_BYTES 5 + +static inline void codegen_addbyte(codeblock_t *block, uint8_t val) +{ + if (block_pos >= BLOCK_MAX) + fatal("codegen_addbyte over! %i\n", block_pos); + block_write_data[block_pos++] = val; +} +static inline void codegen_addbyte2(codeblock_t *block, uint8_t vala, uint8_t valb) +{ + if (block_pos > (BLOCK_MAX-2)) + fatal("codegen_addbyte2 over! %i\n", block_pos); + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; +} +static inline void codegen_addbyte3(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc) +{ + if (block_pos > (BLOCK_MAX-3)) + fatal("codegen_addbyte3 over! %i\n", block_pos); + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; + block_write_data[block_pos++] = valc; +} +static inline void codegen_addbyte4(codeblock_t *block, uint8_t vala, uint8_t valb, uint8_t valc, uint8_t vald) +{ + if (block_pos > (BLOCK_MAX-4)) + fatal("codegen_addbyte4 over! %i\n", block_pos); + block_write_data[block_pos++] = vala; + block_write_data[block_pos++] = valb; + block_write_data[block_pos++] = valc; + block_write_data[block_pos++] = vald; +} + +static inline void codegen_addword(codeblock_t *block, uint16_t val) +{ + if (block_pos > (BLOCK_MAX-2)) + fatal("codegen_addword over! %i\n", block_pos); + *(uint16_t *)&block_write_data[block_pos] = val; + block_pos += 2; +} + +static inline void codegen_addlong(codeblock_t *block, uint32_t val) +{ + if (block_pos > (BLOCK_MAX-4)) + fatal("codegen_addlong over! %i\n", block_pos); + *(uint32_t *)&block_write_data[block_pos] = val; + block_pos += 4; +} + +static inline void codegen_addquad(codeblock_t *block, uint64_t val) +{ + if (block_pos > (BLOCK_MAX-8)) + fatal("codegen_addquad over! %i\n", block_pos); + *(uint64_t *)&block_write_data[block_pos] = val; + block_pos += 8; +} + +static void codegen_allocate_new_block(codeblock_t *block) +{ + /*Current block is full. Allocate a new block*/ + struct mem_block_t *new_block = codegen_allocator_allocate(block->head_mem_block, get_block_nr(block)); + uint8_t *new_ptr = codeblock_allocator_get_ptr(new_block); + + /*Add a jump instruction to the new block*/ + codegen_addbyte(block, 0xe9); /*JMP*/ + codegen_addlong(block, (uintptr_t)new_ptr - (uintptr_t)&block_write_data[block_pos + 4]); + + /*Set write address to start of new block*/ + block_pos = 0; + block_write_data = new_ptr; +} + +static inline void codegen_alloc_bytes(codeblock_t *block, int size) +{ + if (block_pos > ((BLOCK_MAX - size) - JMP_LEN_BYTES)) + codegen_allocate_new_block(block); +} + +static inline int is_imm8(uint32_t imm_data) +{ + if (imm_data <= 0x7f || imm_data >= 0xffffff80) + return 1; + return 0; +} diff --git a/src/codegen_backend_x86_ops_sse.c b/src/codegen_backend_x86_ops_sse.c new file mode 100644 index 0000000..50ec638 --- /dev/null +++ b/src/codegen_backend_x86_ops_sse.c @@ -0,0 +1,574 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops_sse.h" +#include "codegen_backend_x86_ops_helpers.h" + +void host_x86_ADDPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); /*ADDPS dst_reg, src_reg*/ +} +void host_x86_ADDSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x58, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_CMPPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg, int type) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xc2, 0xc0 | src_reg | (dst_reg << 3), type); /*CMPPS dst_reg, src_reg, type*/ +} + +void host_x86_COMISD_XREG_XREG(codeblock_t *block, int src_reg_a, int src_reg_b) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x2e, 0xc0 | src_reg_b | (src_reg_a << 3)); +} + +void host_x86_CVTDQ2PS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5b, 0xc0 | src_reg | (dst_reg << 3)); /*CVTDQ2PS dst_reg, src_reg*/ +} +void host_x86_CVTPS2DQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x5b, 0xc0 | src_reg | (dst_reg << 3)); /*CVTPS2DQ dst_reg, src_reg*/ +} + +void host_x86_CVTSD2SI_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x2d, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSD2SI dst_reg, src_reg*/ +} +void host_x86_CVTSD2SS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSD2SS dst_reg, src_reg*/ +} + +void host_x86_CVTSI2SD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x2a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSI2SD dst_reg, src_reg*/ +} +void host_x86_CVTSI2SS_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x2a, 0xc0 | src_reg | (dst_reg << 3)); /*CVTSI2SD dst_reg, src_reg*/ +} + +void host_x86_CVTSS2SD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5a, 0xc0 | src_reg | (dst_reg << 3)); +} +void host_x86_CVTSS2SD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5a, 0x04 | (dst_reg << 3)); /*CVTSS2SD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} + +void host_x86_DIVSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); /*DIVSD dst_reg, src_reg*/ +} +void host_x86_DIVSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x5e, 0xc0 | src_reg | (dst_reg << 3)); /*DIVSS dst_reg, src_reg*/ +} + +void host_x86_LDMXCSR(codeblock_t *block, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x0f, 0xae, 0x50 | REG_EBP, offset); /*LDMXCSR offset[EBP]*/ + } + else + { + codegen_alloc_bytes(block, 7); + codegen_addbyte3(block, 0x0f, 0xae, 0x15); /*LDMXCSR [p]*/ + codegen_addlong(block, (uint32_t)p); + } +} + +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXSD dst_reg, src_reg*/ +} + +void host_x86_MOVD_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x7e, 0x04 | (src_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVD_REG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x7e, 0xc0 | dst_reg | (src_reg << 3)); +} +void host_x86_MOVD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x6e, 0x04 | (dst_reg << 3)); /*MOVD XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x6e, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_MOVQ_ABS_XREG(codeblock_t *block, void *p, int src_reg) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x45 | (src_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x05 | (src_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + codegen_addbyte3(block, 0x44 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0x66, 0x0f, 0xd6); /*MOVQ addr[src_reg_a + src_reg_b << shift], XMMx*/ + codegen_addbyte2(block, 0x84 | (src_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} +void host_x86_MOVQ_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVQ XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVQ_BASE_OFFSET_XREG(codeblock_t *block, int base_reg, int offset, int src_reg) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x44 | (src_reg << 3)); /*MOVQ [ESP + offset], XMMx*/ + codegen_addbyte2(block, 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x40 | base_reg | (src_reg << 3)); /*MOVQ [base_reg + offset], XMMx*/ + codegen_addbyte(block, offset); + } + } + else + fatal("MOVQ_BASE_OFFSET_XREG - offset %i\n", offset); +} +void host_x86_MOVQ_STACK_OFFSET_XREG(codeblock_t *block, int offset, int src_reg) +{ + if (!offset) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x04 | (src_reg << 3)); /*MOVQ [ESP], src_reg*/ + codegen_addbyte(block, 0x24); + } + else if (offset >= -0x80 && offset < 0x80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x44 | (src_reg << 3)); /*MOVQ offset[ESP], src_reg*/ + codegen_addbyte2(block, 0x24, offset & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0xd6, 0x84 | (src_reg << 3)); /*MOVQ offset[ESP], src_reg*/ + codegen_addbyte(block, 0x24); + codegen_addlong(block, offset); + } + +} + +void host_x86_MOVQ_XREG_ABS(codeblock_t *block, int dst_reg, void *p) +{ + int offset = (uintptr_t)p - (((uintptr_t)&cpu_state) + 128); + + if (offset >= -128 && offset < 127) + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x45 | (dst_reg << 3)); /*MOVQ offset[EBP], src_reg*/ + codegen_addbyte(block, offset); + } + else + { + codegen_alloc_bytes(block, 8); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x05 | (dst_reg << 3)); /*MOVQ [p], src_reg*/ + codegen_addlong(block, (uint32_t)p); + } +} +void host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift) +{ + if (addr < 0x80 || addr >= 0xffffff80) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + codegen_addbyte3(block, 0x44 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6), addr & 0xff); + } + else + { + codegen_alloc_bytes(block, 9); + codegen_addbyte3(block, 0xf3, 0x0f, 0x7e); /*MOVQ XMMx, addr[src_reg_a + src_reg_b << shift]*/ + codegen_addbyte2(block, 0x84 | (dst_reg << 3), src_reg_a | (src_reg_b << 3) | (shift << 6)); + codegen_addlong(block, addr); + } +} +void host_x86_MOVQ_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x04 | (dst_reg << 3)); /*MOVQ XMMx, [base_reg + idx_reg]*/ + codegen_addbyte(block, base_reg | (idx_reg << 3)); +} +void host_x86_MOVQ_XREG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset) +{ + if (offset >= -128 && offset < 127) + { + if (base_reg == REG_ESP) + { + codegen_alloc_bytes(block, 6); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x44 | (dst_reg << 3)); /*MOVQ XMMx, [ESP + offset]*/ + codegen_addbyte2(block, 0x24, offset); + } + else + { + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0x40 | base_reg | (dst_reg << 3)); /*MOVQ XMMx, [base_reg + offset]*/ + codegen_addbyte(block, offset); + } + } + else + fatal("MOVQ_REG_BASE_OFFSET - offset %i\n", offset); +} +void host_x86_MOVQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x7e, 0xc0 | src_reg | (dst_reg << 3)); /*MOVQ dst_reg, src_reg*/ +} + +void host_x86_MAXPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5f, 0xc0 | src_reg | (dst_reg << 3)); /*MAXPS dst_reg, src_reg*/ +} +void host_x86_MINPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5d, 0xc0 | src_reg | (dst_reg << 3)); /*MINPS dst_reg, src_reg*/ +} + +void host_x86_MULPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); /*MULPS dst_reg, src_reg*/ +} +void host_x86_MULSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x59, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_PACKSSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x63, 0xc0 | src_reg | (dst_reg << 3)); /*PACKSSWB dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} +void host_x86_PACKSSDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x6b, 0xc0 | src_reg | (dst_reg << 3)); /*PACKSSDW dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} +void host_x86_PACKUSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 9); + codegen_addbyte4(block, 0x66, 0x0f, 0x67, 0xc0 | src_reg | (dst_reg << 3)); /*PACKUSWB dst_reg, src_reg*/ + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | dst_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0x88 (move bits 64-95 to 32-63)*/ + codegen_addbyte(block, 0x88); +} + +void host_x86_PADDB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfc, 0xc0 | src_reg | (dst_reg << 3)); /*PADDB dst_reg, src_reg*/ +} +void host_x86_PADDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfd, 0xc0 | src_reg | (dst_reg << 3)); /*PADDW dst_reg, src_reg*/ +} +void host_x86_PADDD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfe, 0xc0 | src_reg | (dst_reg << 3)); /*PADDD dst_reg, src_reg*/ +} +void host_x86_PADDSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xec, 0xc0 | src_reg | (dst_reg << 3)); /*PADDSB dst_reg, src_reg*/ +} +void host_x86_PADDSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xed, 0xc0 | src_reg | (dst_reg << 3)); /*PADDSW dst_reg, src_reg*/ +} +void host_x86_PADDUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdc, 0xc0 | src_reg | (dst_reg << 3)); /*PADDUSB dst_reg, src_reg*/ +} +void host_x86_PADDUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdd, 0xc0 | src_reg | (dst_reg << 3)); /*PADDUSW dst_reg, src_reg*/ +} + +void host_x86_PAND_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdb, 0xc0 | src_reg | (dst_reg << 3)); /*PAND dst_reg, src_reg*/ +} +void host_x86_PANDN_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xdf, 0xc0 | src_reg | (dst_reg << 3)); /*PANDN dst_reg, src_reg*/ +} +void host_x86_POR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xeb, 0xc0 | src_reg | (dst_reg << 3)); /*POR dst_reg, src_reg*/ +} +void host_x86_PXOR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xef, 0xc0 | src_reg | (dst_reg << 3)); /*PXOR dst_reg, src_reg*/ +} + +void host_x86_PCMPEQB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x74, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQB dst_reg, src_reg*/ +} +void host_x86_PCMPEQW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x75, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQW dst_reg, src_reg*/ +} +void host_x86_PCMPEQD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x76, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPEQD dst_reg, src_reg*/ +} +void host_x86_PCMPGTB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x64, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTB dst_reg, src_reg*/ +} +void host_x86_PCMPGTW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x65, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTW dst_reg, src_reg*/ +} +void host_x86_PCMPGTD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x66, 0xc0 | src_reg | (dst_reg << 3)); /*PCMPGTD dst_reg, src_reg*/ +} + +void host_x86_PMADDWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} +void host_x86_PMULHW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} +void host_x86_PMULLW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd5, 0xc0 | src_reg | (dst_reg << 3)); /*PMULLW dst_reg, src_reg*/ +} + +void host_x86_PSHUFD_XREG_XREG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t shuffle) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x70, 0xc0 | src_reg | (dst_reg << 3)); /*PSHUFD dst_reg, dst_reg, 0xee (move top 64-bits to low 64-bits)*/ + codegen_addbyte(block, shuffle); +} + +void host_x86_PSLLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x30 | dst_reg); /*PSLLW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSLLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x30 | dst_reg); /*PSLLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSLLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x30 | dst_reg); /*PSLLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x20 | dst_reg); /*PSRAW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x20 | dst_reg); /*PSRAD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRAQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x20 | dst_reg); /*PSRAD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x71, 0xc0 | 0x10 | dst_reg); /*PSRLW dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x72, 0xc0 | 0x10 | dst_reg); /*PSRLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} +void host_x86_PSRLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift) +{ + codegen_alloc_bytes(block, 5); + codegen_addbyte4(block, 0x66, 0x0f, 0x73, 0xc0 | 0x10 | dst_reg); /*PSRLD dst_reg, imm*/ + codegen_addbyte(block, shift); +} + +void host_x86_PSUBB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf8, 0xc0 | src_reg | (dst_reg << 3)); /*PADDB dst_reg, src_reg*/ +} +void host_x86_PSUBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xf9, 0xc0 | src_reg | (dst_reg << 3)); /*PADDW dst_reg, src_reg*/ +} +void host_x86_PSUBD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xfa, 0xc0 | src_reg | (dst_reg << 3)); /*PADDD dst_reg, src_reg*/ +} +void host_x86_PSUBSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe8, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBSB dst_reg, src_reg*/ +} +void host_x86_PSUBSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xe9, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBSW dst_reg, src_reg*/ +} +void host_x86_PSUBUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd8, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBUSB dst_reg, src_reg*/ +} +void host_x86_PSUBUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0xd9, 0xc0 | src_reg | (dst_reg << 3)); /*PSUBUSW dst_reg, src_reg*/ +} + +void host_x86_PUNPCKLBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x60, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLBW dst_reg, src_reg*/ +} +void host_x86_PUNPCKLWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x61, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLWD dst_reg, src_reg*/ +} +void host_x86_PUNPCKLDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0x66, 0x0f, 0x62, 0xc0 | src_reg | (dst_reg << 3)); /*PUNPCKLDQ dst_reg, src_reg*/ +} + +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSD dst_reg, src_reg*/ +} +void host_x86_SQRTSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf3, 0x0f, 0x51, 0xc0 | src_reg | (dst_reg << 3)); /*SQRTSS dst_reg, src_reg*/ +} + +void host_x86_SUBPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); /*SUBPS dst_reg, src_reg*/ +} +void host_x86_SUBSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 4); + codegen_addbyte4(block, 0xf2, 0x0f, 0x5c, 0xc0 | src_reg | (dst_reg << 3)); +} + +void host_x86_UNPCKLPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg) +{ + codegen_alloc_bytes(block, 3); + codegen_addbyte3(block, 0x0f, 0x14, 0xc0 | src_reg | (dst_reg << 3)); +} + +#endif diff --git a/src/codegen_backend_x86_ops_sse.h b/src/codegen_backend_x86_ops_sse.h new file mode 100644 index 0000000..e8afdcb --- /dev/null +++ b/src/codegen_backend_x86_ops_sse.h @@ -0,0 +1,111 @@ +void host_x86_ADDPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_ADDSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +#define CMPPS_EQ 0 +#define CMPPS_NLT 5 +#define CMPPS_NLE 6 +void host_x86_CMPPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg, int type); + +void host_x86_COMISD_XREG_XREG(codeblock_t *block, int src_reg_a, int src_reg_b); + +void host_x86_CVTDQ2PS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTPS2DQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CVTSD2SI_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_CVTSD2SS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CVTSI2SD_XREG_REG(codeblock_t *block, int dest_reg, int src_reg); +void host_x86_CVTSI2SS_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_CVTSS2SD_XREG_XREG(codeblock_t *block, int dest_reg, int src_reg); +void host_x86_CVTSS2SD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); + +void host_x86_DIVSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_DIVSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_LDMXCSR(codeblock_t *block, void *p); + +void host_x86_MAXSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVD_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOVD_REG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MOVD_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVD_XREG_REG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MOVQ_ABS_XREG(codeblock_t *block, void *p, int src_reg); +void host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(codeblock_t *block, uint32_t addr, int src_reg_a, int src_reg_b, int shift, int src_reg); +void host_x86_MOVQ_BASE_INDEX_XREG(codeblock_t *block, int base_reg, int idx_reg, int src_reg); +void host_x86_MOVQ_BASE_OFFSET_XREG(codeblock_t *block, int base_reg, int offset, int src_reg); +void host_x86_MOVQ_STACK_OFFSET_XREG(codeblock_t *block, int offset, int src_reg); + +void host_x86_MOVQ_XREG_ABS(codeblock_t *block, int dst_reg, void *p); +void host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(codeblock_t *block, int dst_reg, uint32_t addr, int src_reg_a, int src_reg_b, int shift); +void host_x86_MOVQ_XREG_BASE_INDEX(codeblock_t *block, int dst_reg, int base_reg, int idx_reg); +void host_x86_MOVQ_XREG_BASE_OFFSET(codeblock_t *block, int dst_reg, int base_reg, int offset); +void host_x86_MOVQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MAXPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MINPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_MULPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_MULSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PACKSSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PACKSSDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PACKUSWB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PADDB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PADDUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PAND_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PANDN_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_POR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PXOR_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PCMPEQB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPEQW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPEQD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PCMPGTD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PMADDWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PMULHW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PMULLW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PSLLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSLLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSLLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRAQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLW_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLD_XREG_IMM(codeblock_t *block, int dst_reg, int shift); +void host_x86_PSRLQ_XREG_IMM(codeblock_t *block, int dst_reg, int shift); + +void host_x86_PSHUFD_XREG_XREG_IMM(codeblock_t *block, int dst_reg, int src_reg, uint8_t shuffle); + +void host_x86_PSUBB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBUSB_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PSUBUSW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_PUNPCKLBW_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLWD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_PUNPCKLDQ_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_SQRTSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SQRTSS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_SUBPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); +void host_x86_SUBSD_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); + +void host_x86_UNPCKLPS_XREG_XREG(codeblock_t *block, int dst_reg, int src_reg); diff --git a/src/codegen_backend_x86_uops.c b/src/codegen_backend_x86_uops.c new file mode 100644 index 0000000..94092c3 --- /dev/null +++ b/src/codegen_backend_x86_uops.c @@ -0,0 +1,3165 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include "ibm.h" +#include "x86.h" +#include "x87.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_backend_x86_defs.h" +#include "codegen_backend_x86_ops.h" +#include "codegen_backend_x86_ops_fpu.h" +#include "codegen_backend_x86_ops_sse.h" +#include "codegen_ir_defs.h" + +/*void codegen_debug() +{ + pclog(" %04x:%04x : %08x %08x %08x %08x\n", CS, cpu_state.pc, AX, BX, CX, DX); +}*/ + +#define HOST_REG_IS_L(reg) (IREG_GET_SIZE(reg) == IREG_SIZE_L) +#define HOST_REG_IS_W(reg) (IREG_GET_SIZE(reg) == IREG_SIZE_W) +#define HOST_REG_IS_B(reg) (IREG_GET_SIZE(reg) == IREG_SIZE_B && IREG_GET_REG(reg) < 4) +#define HOST_REG_IS_BH(reg) (IREG_GET_SIZE(reg) == IREG_SIZE_BH && IREG_GET_REG(reg) < 4) + +#define HOST_REG_GET(reg) ((IREG_GET_SIZE(reg) == IREG_SIZE_BH) ? (IREG_GET_REG((reg) & 3) | 4) : (IREG_GET_REG(reg) & 7)) + +#define REG_IS_L(size) (size == IREG_SIZE_L) +#define REG_IS_W(size) (size == IREG_SIZE_W) +#define REG_IS_B(size) (size == IREG_SIZE_B || size == IREG_SIZE_BH) +#define REG_IS_BH(size) (size == IREG_SIZE_BH) +#define REG_IS_D(size) (size == IREG_SIZE_D) +#define REG_IS_Q(size) (size == IREG_SIZE_Q) + +static int codegen_ADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_LEA_REG_REG(block, dest_reg, src_reg_a, src_reg_b); + else + host_x86_ADD32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_ADD16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_ADD8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_ADD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_LEA_REG_IMM(block, dest_reg, src_reg, uop->imm_data); + else + host_x86_ADD32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ADD16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ADD8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ADD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_ADD_LSHIFT(codeblock_t *block, uop_t *uop) +{ + if (!uop->imm_data) + { + if (uop->dest_reg_a_real == uop->src_reg_a_real) + host_x86_ADD32_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_b_real); + else + host_x86_LEA_REG_REG(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); + } + else if (uop->imm_data < 4) + host_x86_LEA_REG_REG_SHIFT(block, uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real, uop->imm_data); +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_ADD_LSHIFT - shift out of range %i\n", uop->imm_data); +#endif + return 0; +} + +static int codegen_AND(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PAND_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_AND8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("AND %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_AND_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_AND32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_AND16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_AND8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("AND_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_ANDN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), /*src_reg_a = HOST_REG_GET(uop->src_reg_a_real), */src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PANDN_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ANDN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_CALL_FUNC(codeblock_t *block, uop_t *uop) +{ + host_x86_CALL(block, uop->p); + + return 0; +} + +static int codegen_CALL_FUNC_RESULT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_L(dest_size)) + fatal("CALL_FUNC_RESULT %02x\n", uop->dest_reg_a_real); +#endif + host_x86_CALL(block, uop->p); + host_x86_MOV32_REG_REG(block, dest_reg, REG_EAX); + + return 0; +} + +static int codegen_CALL_INSTRUCTION_FUNC(codeblock_t *block, uop_t *uop) +{ + host_x86_CALL(block, uop->p); + host_x86_TEST32_REG(block, REG_EAX, REG_EAX); + host_x86_JNZ(block, codegen_exit_rout); +// host_x86_CALL(block, codegen_debug); + + return 0; +} + +static int codegen_CMP_IMM_JZ(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JZ %02x\n", uop->src_reg_a_real); +#endif + host_x86_JZ(block, uop->p); + + return 0; +} + +static int codegen_CMP_IMM_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JNZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNZ_long(block); + + return 0; +} +static int codegen_CMP_IMM_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_CMP32_REG_IMM(block, src_reg, uop->imm_data); + } + else if (REG_IS_W(src_size)) + { + host_x86_CMP16_REG_IMM(block, src_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_IMM_JZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JZ_long(block); + + return 0; +} + +static int codegen_CMP_JB(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JB %02x\n", uop->src_reg_a_real); +#endif + jump_p = host_x86_JB_long(block); + *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); + + return 0; +} +static int codegen_CMP_JNBE(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + uint32_t *jump_p; + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNBE %02x\n", uop->src_reg_a_real); +#endif + jump_p = host_x86_JNBE_long(block); + *jump_p = (uintptr_t)uop->p - ((uintptr_t)jump_p + 4); + + return 0; +} + +static int codegen_CMP_JNB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNB_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNB_long(block); + + return 0; +} +static int codegen_CMP_JNBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNBE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNBE_long(block); + + return 0; +} +static int codegen_CMP_JNL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNL_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNL_long(block); + + return 0; +} +static int codegen_CMP_JNLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNLE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNLE_long(block); + + return 0; +} +static int codegen_CMP_JNO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNO_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNO_long(block); + + return 0; +} +static int codegen_CMP_JNZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JNZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNZ_long(block); + + return 0; +} +static int codegen_CMP_JB_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JB_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JB_long(block); + + return 0; +} +static int codegen_CMP_JBE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JBE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JBE_long(block); + + return 0; +} +static int codegen_CMP_JL_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JL_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JL_long(block); + + return 0; +} +static int codegen_CMP_JLE_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JLE_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JLE_long(block); + + return 0; +} +static int codegen_CMP_JO_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JO_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JO_long(block); + + return 0; +} +static int codegen_CMP_JZ_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + host_x86_CMP32_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + host_x86_CMP16_REG_REG(block, src_reg_a, src_reg_b); + } + else if (REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + host_x86_CMP8_REG_REG(block, src_reg_a, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("CMP_JZ_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JZ_long(block); + + return 0; +} + +static int codegen_FABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && dest_reg == src_reg_a) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, dest_reg); + host_x86_MAXSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FABS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FCHS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_PXOR_XREG_XREG(block, dest_reg, dest_reg); + host_x86_SUBSD_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FCHS %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_SQRTSD_XREG_XREG(block, dest_reg, src_reg_a); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FSQRT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_FTST(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a)) + { + host_x86_PXOR_XREG_XREG(block, REG_XMM_TEMP, REG_XMM_TEMP); + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, REG_XMM_TEMP); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FTST %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_FADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_ADDSD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FCOM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_W(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + if (dest_reg != REG_EAX) + host_x86_MOV32_REG_REG(block, REG_ECX, REG_EAX); + host_x86_XOR32_REG_REG(block, REG_EAX, REG_EAX); + host_x86_COMISD_XREG_XREG(block, src_reg_a, src_reg_b); + host_x86_LAHF(block); + host_x86_AND16_REG_IMM(block, REG_EAX, C0|C2|C3); + if (dest_reg != REG_EAX) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_EAX); + host_x86_MOV32_REG_REG(block, REG_EAX, REG_ECX); + } + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FCOM %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FDIV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_DIVSD_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_DIVSD_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FDIV %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_MULSD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_FSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b) && dest_reg == src_reg_a) + { + host_x86_SUBSD_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size_a) && REG_IS_D(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBSD_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_FSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_FP_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_long(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, 7); + host_x86_CALL(block, x86_int); + host_x86_JMP(block, codegen_exit_rout); + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + + return 0; +} + +static int codegen_MMX_ENTER(codeblock_t *block, uop_t *uop) +{ + uint32_t *branch_offset; + + host_x86_MOV32_REG_ABS(block, REG_ECX, &cr0); + host_x86_TEST32_REG_IMM(block, REG_ECX, 0xc); + branch_offset = host_x86_JZ_long(block); + host_x86_MOV32_ABS_IMM(block, &cpu_state.oldpc, uop->imm_data); + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, 7); + host_x86_CALL(block, x86_int); + host_x86_JMP(block, codegen_exit_rout); + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[0], 0x01010101); + host_x86_MOV32_ABS_IMM(block, &cpu_state.tag[4], 0x01010101); + host_x86_MOV32_ABS_IMM(block, &cpu_state.TOP, 0); + host_x86_MOV8_ABS_IMM(block, &cpu_state.ismmx, 1); + + return 0; +} + +static int codegen_JMP(codeblock_t *block, uop_t *uop) +{ + host_x86_JMP(block, uop->p); + + return 0; +} +static int codegen_JMP_DEST(codeblock_t *block, uop_t *uop) +{ + uop->p = host_x86_JMP_long(block); + + return 0; +} + +static int codegen_LOAD_FUNC_ARG0(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_W(src_size)) + { + host_x86_MOV16_STACK_REG(block, STACK_ARG0, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("codegen_LOAD_FUNC_ARG0 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG1(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG1 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG2(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG2 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_LOAD_FUNC_ARG3(codeblock_t *block, uop_t *uop) +{ +#ifdef RECOMPILER_DEBUG + fatal("codegen_LOAD_FUNC_ARG3 %02x\n", uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_LOAD_FUNC_ARG0_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_STACK_IMM(block, STACK_ARG0, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG1_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_STACK_IMM(block, STACK_ARG1, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG2_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_STACK_IMM(block, STACK_ARG2, uop->imm_data); + return 0; +} +static int codegen_LOAD_FUNC_ARG3_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_STACK_IMM(block, STACK_ARG3, uop->imm_data); + return 0; +} + +static int codegen_LOAD_SEG(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (!REG_IS_W(src_size)) + fatal("LOAD_SEG %02x %p\n", uop->src_reg_a_real, uop->p); +#endif + host_x86_MOV16_STACK_REG(block, STACK_ARG0, src_reg); + host_x86_MOV32_STACK_IMM(block, STACK_ARG1, (uint32_t)uop->p); + host_x86_CALL(block, loadseg); + host_x86_TEST32_REG(block, REG_EAX, REG_EAX); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_LOAD_ABS(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_LOAD_ABS - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + + return 0; +} +static int codegen_MEM_LOAD_REG(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (REG_IS_B(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_byte); + } + else if (REG_IS_W(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_word); + } + else if (REG_IS_L(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_long); + } + else if (REG_IS_Q(dest_size)) + { + host_x86_CALL(block, codegen_mem_load_quad); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_LOAD_REG - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_Q(dest_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } + + return 0; +} +static int codegen_MEM_LOAD_SINGLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_SINGLE - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CALL(block, codegen_mem_load_single); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + + return 0; +} + +static int codegen_MEM_LOAD_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); +#ifdef RECOMPILER_DEBUG + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (!REG_IS_D(dest_size)) + fatal("MEM_LOAD_DOUBLE - %02x\n", uop->dest_reg_a_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CALL(block, codegen_mem_load_double); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + + return 0; +} + +static int codegen_MEM_STORE_ABS(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_b_real); + int src_size = IREG_GET_SIZE(uop->src_reg_b_real); + + host_x86_LEA_REG_IMM(block, REG_ESI, seg_reg, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_STORE_ABS - %02x\n", uop->src_reg_b_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_REG(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + if (REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_byte); + } + else if (REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_word); + } + else if (REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, REG_ECX, src_reg); + host_x86_CALL(block, codegen_mem_store_long); + } + else if (REG_IS_Q(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_quad); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MEM_STORE_REG - %02x\n", uop->src_reg_b_real); +#endif + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_IMM_8(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV8_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_byte); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_16(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV16_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_word); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_IMM_32(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real); + + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + host_x86_MOV32_REG_IMM(block, REG_ECX, uop->imm_data); + host_x86_CALL(block, codegen_mem_store_long); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MEM_STORE_SINGLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_SINGLE - %02x\n", uop->src_reg_b_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_CVTSD2SS_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_single); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} +static int codegen_MEM_STORE_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int seg_reg = HOST_REG_GET(uop->src_reg_a_real), addr_reg = HOST_REG_GET(uop->src_reg_b_real), src_reg = HOST_REG_GET(uop->src_reg_c_real); +#ifdef RECOMPILER_DEBUG + int src_size = IREG_GET_SIZE(uop->src_reg_c_real); + + if (!REG_IS_D(src_size)) + fatal("MEM_STORE_DOUBLE - %02x\n", uop->src_reg_b_real); +#endif + host_x86_LEA_REG_REG(block, REG_ESI, seg_reg, addr_reg); + if (uop->imm_data) + host_x86_ADD32_REG_IMM(block, REG_ESI, uop->imm_data); + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg); + host_x86_CALL(block, codegen_mem_store_double); + host_x86_TEST32_REG(block, REG_ESI, REG_ESI); + host_x86_JNZ(block, codegen_exit_rout); + + return 0; +} + +static int codegen_MOV(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_D(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_IMM %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_PTR(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_REG_IMM(block, uop->dest_reg_a_real, (uint32_t)uop->p); + return 0; +} +static int codegen_MOV_REG_PTR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOV32_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOV_REG_PTR %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_8(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOVZX_REG_ABS_32_8(block, dest_reg, uop->p); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOVZX_REG_ABS_16_8(block, dest_reg, uop->p); + } + else if (REG_IS_B(dest_size)) + { + host_x86_MOV8_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOVZX_REG_PTR_8 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVZX_REG_PTR_16(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size)) + { + host_x86_MOVZX_REG_ABS_32_16(block, dest_reg, uop->p); + } + else if (REG_IS_W(dest_size)) + { + host_x86_MOV16_REG_ABS(block, dest_reg, uop->p); + } + else + fatal("MOVZX_REG_PTR_16 %02x\n", uop->dest_reg_a_real); + + return 0; +} +static int codegen_MOVSX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVSX_REG_32_16(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVSX_REG_32_8(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVSX_REG_16_8(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOVSX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOVZX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_L(src_size)) + { + host_x86_MOVD_XREG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_Q(src_size)) + { + host_x86_MOVD_REG_XREG(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVZX_REG_32_16(block, dest_reg, src_reg); + } + else if (REG_IS_L(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVZX_REG_32_8(block, dest_reg, src_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_B(src_size)) + { + host_x86_MOVZX_REG_16_8(block, dest_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOVZX %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_MOV_DOUBLE_INT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_D(dest_size) && REG_IS_L(src_size)) + { + host_x86_CVTSI2SD_XREG_REG(block, dest_reg, src_reg); + } + else if (REG_IS_D(dest_size) && REG_IS_W(src_size)) + { + host_x86_MOVSX_REG_32_16(block, REG_ECX, src_reg); + host_x86_CVTSI2SD_XREG_REG(block, dest_reg, REG_ECX); + } + else if (REG_IS_D(dest_size) && REG_IS_Q(src_size)) + { + /*There is no SSE instruction to convert a 64-bit integer to a floating point value. + Instead we have to bounce the integer through memory via x87.*/ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_ESP, 0, src_reg); + host_x87_FILDq_BASE(block, REG_ESP); + host_x87_FSTPd_BASE(block, REG_ESP); + host_x86_MOVQ_XREG_BASE_OFFSET(block, dest_reg, REG_ESP, 0); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_DOUBLE_INT %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_MOV_INT_DOUBLE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_D(src_size)) + { + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG_XREG(block, dest_reg, src_reg); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } + else if (REG_IS_W(dest_size) && REG_IS_D(src_size)) + { + host_x86_LDMXCSR(block, &cpu_state.new_fp_control); + host_x86_CVTSD2SI_REG_XREG(block, REG_ECX, src_reg); + host_x86_MOV16_REG_REG(block, dest_reg, REG_ECX); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_INT_DOUBLE %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_MOV_INT_DOUBLE_64(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), src_64_reg = HOST_REG_GET(uop->src_reg_b_real), tag_reg = HOST_REG_GET(uop->src_reg_c_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real), src_64_size = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_D(src_size) && REG_IS_Q(src_64_size)) + { + uint32_t *branch_offset; + + /*If TAG_UINT64 is set then the source is MM[]. Otherwise it is a double in ST()*/ + host_x86_MOVQ_XREG_XREG(block, dest_reg, src_64_reg); + host_x86_TEST8_REG(block, tag_reg, tag_reg); + branch_offset = host_x86_JS_long(block); + + /*There is no SSE instruction to convert a floating point value to a 64-bit integer. + Instead we have to bounce through memory via x87.*/ + host_x87_FLDCW(block, &cpu_state.new_fp_control2); + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_ESP, 0, src_reg); + host_x87_FLDd_BASE(block, REG_ESP); + host_x87_FISTPq_BASE(block, REG_ESP); + host_x86_MOVQ_XREG_BASE_OFFSET(block, dest_reg, REG_ESP, 0); + host_x87_FLDCW(block, &cpu_state.old_fp_control2); + + *branch_offset = (uint32_t)((uintptr_t)&block_write_data[block_pos] - (uintptr_t)branch_offset) - 4; + } +#ifdef RECOMPILER_DEBUG + else + fatal("MOV_INT_DOUBLE_64 %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_NOP(codeblock_t *block, uop_t *uop) +{ + return 0; +} + +static int codegen_OR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_POR_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_OR8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("OR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_OR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_L(dest_size) && dest_reg == src_reg) + { + host_x86_OR32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && dest_reg == src_reg) + { + host_x86_OR16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && dest_reg == src_reg) + { + host_x86_OR8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("OR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_PACKSSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKSSWB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKSSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PACKSSDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKSSDW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKSSDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PACKUSWB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PACKUSWB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PACKUSWB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PADDB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDUSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PADDUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PADDUSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PADDUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PCMPEQB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPEQW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPEQD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPEQD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPEQD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PCMPGTD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PCMPGTD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PCMPGTD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PF2ID(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_x86_LDMXCSR(block, &cpu_state.trunc_fp_control); + host_x86_CVTPS2DQ_XREG_XREG(block, dest_reg, src_reg_a); + host_x86_LDMXCSR(block, &cpu_state.old_fp_control); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PF2ID %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFADD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_ADDPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFADD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPEQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_EQ); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPEQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPGE(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_NLT); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPGE %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFCMPGT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_CMPPS_XREG_XREG(block, dest_reg, src_reg_b, CMPPS_NLE); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFCMPGT %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMAX(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MAXPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMAX %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMIN(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MINPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMIN %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFMUL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_MULPS_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFMUL %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PFRCP(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use RCPSS + iteration)*/ + host_x86_MOV32_REG_IMM(block, REG_ECX, 1); + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_CVTSI2SS_XREG_REG(block, dest_reg, REG_ECX); + host_x86_DIVSS_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + host_x86_UNPCKLPS_XREG_XREG(block, dest_reg, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFRCP %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFRSQRT(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + /*TODO: This could be improved (use RSQRTSS + iteration)*/ + host_x86_SQRTSS_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_MOV32_REG_IMM(block, REG_ECX, 1); + host_x86_CVTSI2SS_XREG_REG(block, dest_reg, REG_ECX); + host_x86_DIVSS_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + host_x86_UNPCKLPS_XREG_XREG(block, dest_reg, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFRSQRT %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} +static int codegen_PFSUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_SUBPS_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b)) + { + host_x86_MOVQ_XREG_XREG(block, REG_XMM_TEMP, src_reg_a); + host_x86_SUBPS_XREG_XREG(block, REG_XMM_TEMP, src_reg_b); + host_x86_MOVQ_XREG_XREG(block, dest_reg, REG_XMM_TEMP); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PFSUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PI2FD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a)) + { + host_x86_CVTDQ2PS_XREG_XREG(block, dest_reg, src_reg_a); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PI2FD %02x %02x\n", uop->dest_reg_a_real); +#endif + return 0; +} + +static int codegen_PMADDWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMADDWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PMULHW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMULHW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULHW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PMULLW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PMULLW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PMULLW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PSLLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSLLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSLLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSLLQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSLLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRAQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRAQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRAQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLW_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLW_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLW_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLD_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLD_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLD_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_PSRLQ_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real); + + if (REG_IS_Q(dest_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSRLQ_XREG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSRLQ_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_PSUBB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBUSB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBUSB_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBUSB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PSUBUSW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PSUBUSW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PSUBUSW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_PUNPCKHBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLBW_XREG_XREG(block, dest_reg, src_reg_b); + host_x86_PSHUFD_XREG_XREG_IMM(block, dest_reg, dest_reg, 0xee); /*0xee = move top 64-bits to low 64-bits*/ + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKHWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLWD_XREG_XREG(block, dest_reg, src_reg_b); + host_x86_PSHUFD_XREG_XREG_IMM(block, dest_reg, dest_reg, 0xee); /*0xee = move top 64-bits to low 64-bits*/ + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKHDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLDQ_XREG_XREG(block, dest_reg, src_reg_b); + host_x86_PSHUFD_XREG_XREG_IMM(block, dest_reg, dest_reg, 0xee); /*0xee = move top 64-bits to low 64-bits*/ + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKHDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLBW(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLBW_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLBW %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLWD(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLWD_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLWD %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_PUNPCKLDQ(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PUNPCKLDQ_XREG_XREG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("PUNPCKLDQ %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} + +static int codegen_ROL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROL32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROL16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROL8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROL32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROL16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROL8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_ROR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_ROR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_ROR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_ROR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("ROR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_SAR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SAR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SAR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SAR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SAR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SAR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SAR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SAR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SAR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SAR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHL(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHL32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHL16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHL8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHL %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHL_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHL32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHL16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHL8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHL_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real), shift_reg = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + host_x86_MOV32_REG_REG(block, REG_ECX, shift_reg); + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHR32_CL(block, dest_reg); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHR16_CL(block, dest_reg); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHR8_CL(block, dest_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHR %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} +static int codegen_SHR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SHR32_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SHR16_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SHR8_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SHR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_STORE_PTR_IMM(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV32_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} +static int codegen_STORE_PTR_IMM_8(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV8_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} +static int codegen_STORE_PTR_IMM_16(codeblock_t *block, uop_t *uop) +{ + host_x86_MOV16_ABS_IMM(block, uop->p, uop->imm_data); + return 0; +} + +static int codegen_SUB(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_a = HOST_REG_GET(uop->src_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b)) + { + if (uop->dest_reg_a_real != uop->src_reg_a_real) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg_a); + host_x86_SUB8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SUB %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_SUB_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg = HOST_REG_GET(uop->src_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV32_REG_REG(block, dest_reg, src_reg); + host_x86_SUB32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV16_REG_REG(block, dest_reg, src_reg); + host_x86_SUB16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size)) + { + if (dest_reg != src_reg) + host_x86_MOV8_REG_REG(block, dest_reg, src_reg); + host_x86_SUB8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("SUB_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +static int codegen_TEST_JNS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_TEST32_REG(block, src_reg, src_reg); + } + else if (REG_IS_W(src_size)) + { + host_x86_TEST16_REG(block, src_reg, src_reg); + } + else if (REG_IS_B(src_size)) + { + host_x86_TEST8_REG(block, src_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("TEST_JNS_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JNS_long(block); + + return 0; +} +static int codegen_TEST_JS_DEST(codeblock_t *block, uop_t *uop) +{ + int src_reg = HOST_REG_GET(uop->src_reg_a_real); + int src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(src_size)) + { + host_x86_TEST32_REG(block, src_reg, src_reg); + } + else if (REG_IS_W(src_size)) + { + host_x86_TEST16_REG(block, src_reg, src_reg); + } + else if (REG_IS_B(src_size)) + { + host_x86_TEST8_REG(block, src_reg, src_reg); + } +#ifdef RECOMPILER_DEBUG + else + fatal("TEST_JS_DEST %02x\n", uop->src_reg_a_real); +#endif + uop->p = host_x86_JS_long(block); + + return 0; +} + +static int codegen_XOR(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real), src_reg_b = HOST_REG_GET(uop->src_reg_b_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size_a = IREG_GET_SIZE(uop->src_reg_a_real), src_size_b = IREG_GET_SIZE(uop->src_reg_b_real); + + if (REG_IS_Q(dest_size) && REG_IS_Q(src_size_a) && REG_IS_Q(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_PXOR_XREG_XREG(block, dest_reg, src_reg_b); + } + else if (REG_IS_L(dest_size) && REG_IS_L(src_size_a) && REG_IS_L(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR32_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size_a) && REG_IS_W(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR16_REG_REG(block, dest_reg, src_reg_b); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size_a) && REG_IS_B(src_size_b) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR8_REG_REG(block, dest_reg, src_reg_b); + } +#ifdef RECOMPILER_DEBUG + else + fatal("XOR %02x %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real, uop->src_reg_b_real); +#endif + return 0; +} +static int codegen_XOR_IMM(codeblock_t *block, uop_t *uop) +{ + int dest_reg = HOST_REG_GET(uop->dest_reg_a_real); + int dest_size = IREG_GET_SIZE(uop->dest_reg_a_real), src_size = IREG_GET_SIZE(uop->src_reg_a_real); + + if (REG_IS_L(dest_size) && REG_IS_L(src_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR32_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_W(dest_size) && REG_IS_W(src_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR16_REG_IMM(block, dest_reg, uop->imm_data); + } + else if (REG_IS_B(dest_size) && REG_IS_B(src_size) && uop->dest_reg_a_real == uop->src_reg_a_real) + { + host_x86_XOR8_REG_IMM(block, dest_reg, uop->imm_data); + } +#ifdef RECOMPILER_DEBUG + else + fatal("XOR_IMM %02x %02x\n", uop->dest_reg_a_real, uop->src_reg_a_real); +#endif + return 0; +} + +#ifdef DEBUG_EXTRA +static int codegen_LOG_INSTR(codeblock_t *block, uop_t *uop) +{ + if (uop->imm_data > 256*256) + fatal("LOG_INSTR %08x\n", uop->imm_data); + host_x86_INC32_ABS(block, &instr_counts[uop->imm_data]); + return 0; +} +#endif + +const uOpFn uop_handlers[UOP_MAX] = +{ + [UOP_CALL_FUNC & UOP_MASK] = codegen_CALL_FUNC, + [UOP_CALL_FUNC_RESULT & UOP_MASK] = codegen_CALL_FUNC_RESULT, + [UOP_CALL_INSTRUCTION_FUNC & UOP_MASK] = codegen_CALL_INSTRUCTION_FUNC, + + [UOP_JMP & UOP_MASK] = codegen_JMP, + [UOP_JMP_DEST & UOP_MASK] = codegen_JMP_DEST, + + [UOP_LOAD_SEG & UOP_MASK] = codegen_LOAD_SEG, + + [UOP_LOAD_FUNC_ARG_0 & UOP_MASK] = codegen_LOAD_FUNC_ARG0, + [UOP_LOAD_FUNC_ARG_1 & UOP_MASK] = codegen_LOAD_FUNC_ARG1, + [UOP_LOAD_FUNC_ARG_2 & UOP_MASK] = codegen_LOAD_FUNC_ARG2, + [UOP_LOAD_FUNC_ARG_3 & UOP_MASK] = codegen_LOAD_FUNC_ARG3, + + [UOP_LOAD_FUNC_ARG_0_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG0_IMM, + [UOP_LOAD_FUNC_ARG_1_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG1_IMM, + [UOP_LOAD_FUNC_ARG_2_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG2_IMM, + [UOP_LOAD_FUNC_ARG_3_IMM & UOP_MASK] = codegen_LOAD_FUNC_ARG3_IMM, + + [UOP_STORE_P_IMM & UOP_MASK] = codegen_STORE_PTR_IMM, + [UOP_STORE_P_IMM_8 & UOP_MASK] = codegen_STORE_PTR_IMM_8, + [UOP_STORE_P_IMM_16 & UOP_MASK] = codegen_STORE_PTR_IMM_16, + + [UOP_MEM_LOAD_ABS & UOP_MASK] = codegen_MEM_LOAD_ABS, + [UOP_MEM_LOAD_REG & UOP_MASK] = codegen_MEM_LOAD_REG, + [UOP_MEM_LOAD_SINGLE & UOP_MASK] = codegen_MEM_LOAD_SINGLE, + [UOP_MEM_LOAD_DOUBLE & UOP_MASK] = codegen_MEM_LOAD_DOUBLE, + + [UOP_MEM_STORE_ABS & UOP_MASK] = codegen_MEM_STORE_ABS, + [UOP_MEM_STORE_REG & UOP_MASK] = codegen_MEM_STORE_REG, + [UOP_MEM_STORE_IMM_8 & UOP_MASK] = codegen_MEM_STORE_IMM_8, + [UOP_MEM_STORE_IMM_16 & UOP_MASK] = codegen_MEM_STORE_IMM_16, + [UOP_MEM_STORE_IMM_32 & UOP_MASK] = codegen_MEM_STORE_IMM_32, + [UOP_MEM_STORE_SINGLE & UOP_MASK] = codegen_MEM_STORE_SINGLE, + [UOP_MEM_STORE_DOUBLE & UOP_MASK] = codegen_MEM_STORE_DOUBLE, + + [UOP_MOV & UOP_MASK] = codegen_MOV, + [UOP_MOV_PTR & UOP_MASK] = codegen_MOV_PTR, + [UOP_MOV_IMM & UOP_MASK] = codegen_MOV_IMM, + [UOP_MOVSX & UOP_MASK] = codegen_MOVSX, + [UOP_MOVZX & UOP_MASK] = codegen_MOVZX, + [UOP_MOV_DOUBLE_INT & UOP_MASK] = codegen_MOV_DOUBLE_INT, + [UOP_MOV_INT_DOUBLE & UOP_MASK] = codegen_MOV_INT_DOUBLE, + [UOP_MOV_INT_DOUBLE_64 & UOP_MASK] = codegen_MOV_INT_DOUBLE_64, + [UOP_MOV_REG_PTR & UOP_MASK] = codegen_MOV_REG_PTR, + [UOP_MOVZX_REG_PTR_8 & UOP_MASK] = codegen_MOVZX_REG_PTR_8, + [UOP_MOVZX_REG_PTR_16 & UOP_MASK] = codegen_MOVZX_REG_PTR_16, + + [UOP_ADD & UOP_MASK] = codegen_ADD, + [UOP_ADD_IMM & UOP_MASK] = codegen_ADD_IMM, + [UOP_ADD_LSHIFT & UOP_MASK] = codegen_ADD_LSHIFT, + [UOP_AND & UOP_MASK] = codegen_AND, + [UOP_AND_IMM & UOP_MASK] = codegen_AND_IMM, + [UOP_ANDN & UOP_MASK] = codegen_ANDN, + [UOP_OR & UOP_MASK] = codegen_OR, + [UOP_OR_IMM & UOP_MASK] = codegen_OR_IMM, + [UOP_SUB & UOP_MASK] = codegen_SUB, + [UOP_SUB_IMM & UOP_MASK] = codegen_SUB_IMM, + [UOP_XOR & UOP_MASK] = codegen_XOR, + [UOP_XOR_IMM & UOP_MASK] = codegen_XOR_IMM, + + [UOP_SAR & UOP_MASK] = codegen_SAR, + [UOP_SAR_IMM & UOP_MASK] = codegen_SAR_IMM, + [UOP_SHL & UOP_MASK] = codegen_SHL, + [UOP_SHL_IMM & UOP_MASK] = codegen_SHL_IMM, + [UOP_SHR & UOP_MASK] = codegen_SHR, + [UOP_SHR_IMM & UOP_MASK] = codegen_SHR_IMM, + [UOP_ROL & UOP_MASK] = codegen_ROL, + [UOP_ROL_IMM & UOP_MASK] = codegen_ROL_IMM, + [UOP_ROR & UOP_MASK] = codegen_ROR, + [UOP_ROR_IMM & UOP_MASK] = codegen_ROR_IMM, + + [UOP_CMP_IMM_JZ & UOP_MASK] = codegen_CMP_IMM_JZ, + + [UOP_CMP_JB & UOP_MASK] = codegen_CMP_JB, + [UOP_CMP_JNBE & UOP_MASK] = codegen_CMP_JNBE, + + [UOP_CMP_JNB_DEST & UOP_MASK] = codegen_CMP_JNB_DEST, + [UOP_CMP_JNBE_DEST & UOP_MASK] = codegen_CMP_JNBE_DEST, + [UOP_CMP_JNL_DEST & UOP_MASK] = codegen_CMP_JNL_DEST, + [UOP_CMP_JNLE_DEST & UOP_MASK] = codegen_CMP_JNLE_DEST, + [UOP_CMP_JNO_DEST & UOP_MASK] = codegen_CMP_JNO_DEST, + [UOP_CMP_JNZ_DEST & UOP_MASK] = codegen_CMP_JNZ_DEST, + [UOP_CMP_JB_DEST & UOP_MASK] = codegen_CMP_JB_DEST, + [UOP_CMP_JBE_DEST & UOP_MASK] = codegen_CMP_JBE_DEST, + [UOP_CMP_JL_DEST & UOP_MASK] = codegen_CMP_JL_DEST, + [UOP_CMP_JLE_DEST & UOP_MASK] = codegen_CMP_JLE_DEST, + [UOP_CMP_JO_DEST & UOP_MASK] = codegen_CMP_JO_DEST, + [UOP_CMP_JZ_DEST & UOP_MASK] = codegen_CMP_JZ_DEST, + + [UOP_CMP_IMM_JNZ_DEST & UOP_MASK] = codegen_CMP_IMM_JNZ_DEST, + [UOP_CMP_IMM_JZ_DEST & UOP_MASK] = codegen_CMP_IMM_JZ_DEST, + + [UOP_TEST_JNS_DEST & UOP_MASK] = codegen_TEST_JNS_DEST, + [UOP_TEST_JS_DEST & UOP_MASK] = codegen_TEST_JS_DEST, + + [UOP_FP_ENTER & UOP_MASK] = codegen_FP_ENTER, + [UOP_MMX_ENTER & UOP_MASK] = codegen_MMX_ENTER, + + [UOP_FADD & UOP_MASK] = codegen_FADD, + [UOP_FDIV & UOP_MASK] = codegen_FDIV, + [UOP_FMUL & UOP_MASK] = codegen_FMUL, + [UOP_FSUB & UOP_MASK] = codegen_FSUB, + [UOP_FCOM & UOP_MASK] = codegen_FCOM, + + [UOP_FABS & UOP_MASK] = codegen_FABS, + [UOP_FCHS & UOP_MASK] = codegen_FCHS, + [UOP_FSQRT & UOP_MASK] = codegen_FSQRT, + [UOP_FTST & UOP_MASK] = codegen_FTST, + + [UOP_PACKSSWB & UOP_MASK] = codegen_PACKSSWB, + [UOP_PACKSSDW & UOP_MASK] = codegen_PACKSSDW, + [UOP_PACKUSWB & UOP_MASK] = codegen_PACKUSWB, + + [UOP_PADDB & UOP_MASK] = codegen_PADDB, + [UOP_PADDW & UOP_MASK] = codegen_PADDW, + [UOP_PADDD & UOP_MASK] = codegen_PADDD, + [UOP_PADDSB & UOP_MASK] = codegen_PADDSB, + [UOP_PADDSW & UOP_MASK] = codegen_PADDSW, + [UOP_PADDUSB & UOP_MASK] = codegen_PADDUSB, + [UOP_PADDUSW & UOP_MASK] = codegen_PADDUSW, + + [UOP_PCMPEQB & UOP_MASK] = codegen_PCMPEQB, + [UOP_PCMPEQW & UOP_MASK] = codegen_PCMPEQW, + [UOP_PCMPEQD & UOP_MASK] = codegen_PCMPEQD, + [UOP_PCMPGTB & UOP_MASK] = codegen_PCMPGTB, + [UOP_PCMPGTW & UOP_MASK] = codegen_PCMPGTW, + [UOP_PCMPGTD & UOP_MASK] = codegen_PCMPGTD, + + [UOP_PF2ID & UOP_MASK] = codegen_PF2ID, + [UOP_PFADD & UOP_MASK] = codegen_PFADD, + [UOP_PFCMPEQ & UOP_MASK] = codegen_PFCMPEQ, + [UOP_PFCMPGE & UOP_MASK] = codegen_PFCMPGE, + [UOP_PFCMPGT & UOP_MASK] = codegen_PFCMPGT, + [UOP_PFMAX & UOP_MASK] = codegen_PFMAX, + [UOP_PFMIN & UOP_MASK] = codegen_PFMIN, + [UOP_PFMUL & UOP_MASK] = codegen_PFMUL, + [UOP_PFRCP & UOP_MASK] = codegen_PFRCP, + [UOP_PFRSQRT & UOP_MASK] = codegen_PFRSQRT, + [UOP_PFSUB & UOP_MASK] = codegen_PFSUB, + [UOP_PI2FD & UOP_MASK] = codegen_PI2FD, + + [UOP_PMADDWD & UOP_MASK] = codegen_PMADDWD, + [UOP_PMULHW & UOP_MASK] = codegen_PMULHW, + [UOP_PMULLW & UOP_MASK] = codegen_PMULLW, + + [UOP_PSLLW_IMM & UOP_MASK] = codegen_PSLLW_IMM, + [UOP_PSLLD_IMM & UOP_MASK] = codegen_PSLLD_IMM, + [UOP_PSLLQ_IMM & UOP_MASK] = codegen_PSLLQ_IMM, + [UOP_PSRAW_IMM & UOP_MASK] = codegen_PSRAW_IMM, + [UOP_PSRAD_IMM & UOP_MASK] = codegen_PSRAD_IMM, + [UOP_PSRAQ_IMM & UOP_MASK] = codegen_PSRAQ_IMM, + [UOP_PSRLW_IMM & UOP_MASK] = codegen_PSRLW_IMM, + [UOP_PSRLD_IMM & UOP_MASK] = codegen_PSRLD_IMM, + [UOP_PSRLQ_IMM & UOP_MASK] = codegen_PSRLQ_IMM, + + [UOP_PSUBB & UOP_MASK] = codegen_PSUBB, + [UOP_PSUBW & UOP_MASK] = codegen_PSUBW, + [UOP_PSUBD & UOP_MASK] = codegen_PSUBD, + [UOP_PSUBSB & UOP_MASK] = codegen_PSUBSB, + [UOP_PSUBSW & UOP_MASK] = codegen_PSUBSW, + [UOP_PSUBUSB & UOP_MASK] = codegen_PSUBUSB, + [UOP_PSUBUSW & UOP_MASK] = codegen_PSUBUSW, + + [UOP_PUNPCKHBW & UOP_MASK] = codegen_PUNPCKHBW, + [UOP_PUNPCKHWD & UOP_MASK] = codegen_PUNPCKHWD, + [UOP_PUNPCKHDQ & UOP_MASK] = codegen_PUNPCKHDQ, + [UOP_PUNPCKLBW & UOP_MASK] = codegen_PUNPCKLBW, + [UOP_PUNPCKLWD & UOP_MASK] = codegen_PUNPCKLWD, + [UOP_PUNPCKLDQ & UOP_MASK] = codegen_PUNPCKLDQ, + + [UOP_NOP_BARRIER & UOP_MASK] = codegen_NOP, + +#ifdef DEBUG_EXTRA + [UOP_LOG_INSTR & UOP_MASK] = codegen_LOG_INSTR +#endif +}; + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV8_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV16_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOV32_REG_ABS(block, host_reg, p); +} +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p) +{ + codegen_direct_read_32(block, host_reg, p); +} +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_XREG_ABS(block, host_reg, p); +} +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p) +{ + host_x86_MOVQ_XREG_ABS(block, host_reg, p); +} +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOV8_REG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_EBP, REG_ECX, 0); +} +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_EBP, REG_ECX, 3); +} +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_XREG_ABS_REG_REG_SHIFT(block, host_reg, offset, REG_EBP, REG_ECX, 3); +} + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV8_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV16_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_XREG(block, p, host_reg); +} +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOVQ_ABS_XREG(block, p, host_reg); +} +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOV8_ABS_REG_REG_SHIFT_REG(block, offset, REG_EBP, REG_ECX, 0, host_reg); +} +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(block, offset, REG_EBP, REG_ECX, 3, host_reg); +} +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg) +{ + int offset = (uintptr_t)base - (((uintptr_t)&cpu_state) + 128); + + host_x86_MOV32_REG_BASE_OFFSET(block, REG_ECX, REG_ESP, IREG_TOP_diff_stack_offset); + host_x86_ADD32_REG_IMM(block, REG_ECX, reg_idx); + host_x86_AND32_REG_IMM(block, REG_ECX, 7); + host_x86_MOVQ_ABS_REG_REG_SHIFT_XREG(block, offset, REG_EBP, REG_ECX, 3, host_reg); +} + +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg) +{ + host_x86_MOV32_ABS_REG(block, p, host_reg); +} + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV16_REG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOV32_REG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + codegen_direct_read_32_stack(block, host_reg, stack_offset); +} +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOVQ_XREG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset) +{ + host_x86_MOVQ_XREG_BASE_OFFSET(block, host_reg, REG_ESP, stack_offset); +} + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOV32_BASE_OFFSET_REG(block, REG_ESP, stack_offset, host_reg); +} +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_ESP, stack_offset, host_reg); +} +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg) +{ + host_x86_MOVQ_BASE_OFFSET_XREG(block, REG_ESP, stack_offset, host_reg); +} + +void codegen_set_jump_dest(codeblock_t *block, void *p) +{ + *(uint32_t *)p = (uintptr_t)&block_write_data[block_pos] - ((uintptr_t)p + 4); +} + +void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data) +{ + host_x86_MOV8_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data) +{ + host_x86_MOV16_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data) +{ + host_x86_MOV32_ABS_IMM(block, p, imm_data); +} +void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data) +{ + host_x86_MOV32_BASE_OFFSET_IMM(block, REG_ESP, stack_offset, imm_data); +} + +#endif diff --git a/src/codegen_block.c b/src/codegen_block.c new file mode 100644 index 0000000..c8cdc7f --- /dev/null +++ b/src/codegen_block.c @@ -0,0 +1,920 @@ +#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_accumulate.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_reg.h" + +uint8_t *block_write_data = NULL; + +int codegen_flat_ds, codegen_flat_ss; +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 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; + +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; + +#ifdef DEBUG_EXTRA +uint32_t instr_counts[256*256]; +#endif + +static uint16_t block_free_list; +static void delete_block(codeblock_t *block); +static void delete_dirty_block(codeblock_t *block); + +/*Temporary list of code blocks that have recently been evicted. This allows for + some historical state to be kept when a block is the target of self-modifying + code. + + The size of this list is limited to DIRTY_LIST_MAX_SIZE blocks. When this is + exceeded the oldest entry will be moved to the free list.*/ +static uint16_t block_dirty_list_head, block_dirty_list_tail; +static int dirty_list_size = 0; +#define DIRTY_LIST_MAX_SIZE 64 + +static void block_free_list_add(codeblock_t *block) +{ +#ifndef RELEASE_BUILD + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("block_free_list_add: block=%p in dirty list\n", block); +#endif + if (block_free_list) + block->next = block_free_list; + else + block->next = 0; + block_free_list = get_block_nr(block); + block->flags = CODEBLOCK_IN_FREE_LIST; +// pclog("block_free_list_add: %p %p\n", block, block->next); +} + +static void block_dirty_list_add(codeblock_t *block) +{ +#ifndef RELEASE_BUILD + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("block_dirty_list_add: block=%p already in dirty list\n", block); +#endif +// pclog("block_dirty_list_add: block=%i size=%i %i head=%i tail=%i\n", get_block_nr(block), dirty_list_size, dirty_list_check_size(), block_dirty_list_head, block_dirty_list_tail); + if (block_dirty_list_head != BLOCK_INVALID) + { + codeblock_t *old_head = &codeblock[block_dirty_list_head]; + + block->next = block_dirty_list_head; + block->prev = BLOCK_INVALID; + block_dirty_list_head = old_head->prev = get_block_nr(block); +// pclog(" next=%p,%i prev=%i\n", old_head, block->next, old_head->prev); + } + else + { + /*List empty*/ + block->prev = block->next = BLOCK_INVALID; + block_dirty_list_head = block_dirty_list_tail = get_block_nr(block); + } + block->flags |= CODEBLOCK_IN_DIRTY_LIST; +// pclog(" block_dirty_list_add: %p flags = %x\n", block, block->flags); + dirty_list_size++; + if (dirty_list_size > DIRTY_LIST_MAX_SIZE) + { + /*Evict oldest block to the free list*/ + codeblock_t *evict_block = &codeblock[block_dirty_list_tail]; + +#ifndef RELEASE_BUILD + if (!(evict_block->flags & CODEBLOCK_IN_DIRTY_LIST)) + fatal("block_dirty_list_add: evict_block=%p %x %x not in dirty list\n", evict_block, evict_block->phys, evict_block->flags); + if (!block_dirty_list_tail) + fatal("block_dirty_list_add - !block_dirty_list_tail\n"); + if (evict_block->prev == BLOCK_INVALID) + fatal("block_dirty_list_add - evict_block->prev == BLOCK_INVALID\n"); +#endif + + block_dirty_list_tail = evict_block->prev; + codeblock[evict_block->prev].next = BLOCK_INVALID; + + dirty_list_size--; + evict_block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; +// pclog(" block_dirty_list_add: %p flags = %x\n", evict_block, evict_block->flags); + delete_dirty_block(evict_block); + } + +// pclog("block_free_list_add: %p %p\n", block, block->next); +} + +static void block_dirty_list_remove(codeblock_t *block) +{ + codeblock_t *prev_block = &codeblock[block->prev]; + codeblock_t *next_block = &codeblock[block->next]; + +#ifndef RELEASE_BUILD + if (!(block->flags & CODEBLOCK_IN_DIRTY_LIST)) + fatal("block_dirty_list_remove: block=%p not in dirty list\n", block); +#endif + + /*Is block head of list*/ + if (block->prev == BLOCK_INVALID) + block_dirty_list_head = block->next; + else + prev_block->next = block->next; + + /*Is block tail of list?*/ + if (block->next == BLOCK_INVALID) + block_dirty_list_tail = block->prev; + else + next_block->prev = block->prev; + + dirty_list_size--; +#ifndef RELEASE_BUILD + if (dirty_list_size < 0) + fatal("remove - dirty_list_size < 0!\n"); +#endif + block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; +// pclog(" block_dirty_list_remove: %p flags = %x\n", block, block->flags); +} + +int codegen_purge_purgable_list() +{ + if (purgable_page_list_head) + { + page_t *page = &pages[purgable_page_list_head]; + + if (page->code_present_mask & page->dirty_mask) + { + codegen_check_flush(page, page->dirty_mask, purgable_page_list_head << 12); + + if (block_free_list) + return 1; + } + } + return 0; +} + +static codeblock_t *block_free_list_get() +{ + codeblock_t *block = NULL; + + while (!block_free_list) + { + /*Free list is empty, check the dirty list*/ + if (block_dirty_list_tail) + { +#ifndef RELEASE_BUILD + if (dirty_list_size <= 0) + fatal("get - dirty_list_size <= 0!\n"); +#endif + /*Reuse oldest block*/ + block = &codeblock[block_dirty_list_tail]; + +// pclog("block_free_list_get: remove block=%p size=%i\n", block, dirty_list_size); + block_dirty_list_tail = block->prev; + if (block->prev == BLOCK_INVALID) + block_dirty_list_head = BLOCK_INVALID; + else + codeblock[block->prev].next = BLOCK_INVALID; + dirty_list_size--; + block->flags &= ~CODEBLOCK_IN_DIRTY_LIST; + delete_dirty_block(block); + block_free_list = get_block_nr(block); + break; + } + /*Free list is empty - free up a block*/ + if (!codegen_purge_purgable_list()) + codegen_delete_random_block(0); + } + + block = &codeblock[block_free_list]; + block_free_list = block->next; + block->flags &= ~CODEBLOCK_IN_FREE_LIST; +// pclog(" block_free_list_get: %p flags = %x\n", block, block->flags); + block->next = 0; +// pclog("block_free_list_get: %p %p\n", block, block_free_list); + return block; +} + +void codegen_init() +{ + int c; + + codegen_allocator_init(); + + codegen_backend_init(); + block_free_list = 0; + for (c = 0; c < BLOCK_SIZE; c++) + block_free_list_add(&codeblock[c]); + block_dirty_list_head = block_dirty_list_tail = 0; + dirty_list_size = 0; +#ifdef DEBUG_EXTRA + memset(instr_counts, 0, sizeof(instr_counts)); +#endif +} + +void codegen_close() +{ +#ifdef DEBUG_EXTRA + pclog("Instruction counts :\n"); + while (1) + { + int c; + uint32_t highest_num = 0, highest_idx = 0; + + for (c = 0; c < 256*256; c++) + { + if (instr_counts[c] > highest_num) + { + highest_num = instr_counts[c]; + highest_idx = c; + } + } + if (!highest_num) + break; + + instr_counts[highest_idx] = 0; + if (highest_idx > 256) + pclog(" %02x %02x = %u\n", highest_idx >> 8, highest_idx & 0xff, highest_num); + else + pclog(" %02x = %u\n", highest_idx & 0xff, highest_num); + } +#endif +} + +void codegen_reset() +{ + int c; + + for (c = 1; c < BLOCK_SIZE; c++) + { + codeblock_t *block = &codeblock[c]; + + if (block->pc != BLOCK_PC_INVALID) + { + block->phys = 0; + block->phys_2 = 0; + delete_block(block); + } + } + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(uint16_t)); + mem_reset_page_blocks(); + + block_free_list = 0; + for (c = 0; c < BLOCK_SIZE; c++) + { + codeblock[c].pc = BLOCK_PC_INVALID; + block_free_list_add(&codeblock[c]); + } +} + +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 add_to_block_list(codeblock_t *block) +{ + uint16_t block_prev_nr = pages[block->phys >> 12].block; + uint16_t block_nr = get_block_nr(block); +//pclog("Add to block list %p %08x %llx %x\n", block, block->phys, block->page_mask2, block->flags); + +#ifndef RELEASE_BUILD + if (!block->page_mask) + fatal("add_to_block_list - mask = 0 %llx %llx\n", block->page_mask,block->page_mask2); +#endif + if (block_prev_nr) + { + block->next = block_prev_nr; + codeblock[block_prev_nr].prev = block_nr; + pages[block->phys >> 12].block = block_nr; + } + else + { + block->next = BLOCK_INVALID; + pages[block->phys >> 12].block = block_nr; + } + + if (block->next) + { +#ifndef RELEASE_BUILD + if (codeblock[block->next].pc == BLOCK_PC_INVALID) + fatal("block->next->pc=BLOCK_PC_INVALID %p %p %x %x\n", (void *)&codeblock[block->next], (void *)codeblock, block_current, block_pos); +#endif + } + + if (block->page_mask2) + { + block->flags |= CODEBLOCK_HAS_PAGE2; + + block_prev_nr = pages[block->phys_2 >> 12].block_2; + + if (block_prev_nr) + { + block->next_2 = block_prev_nr; + codeblock[block_prev_nr].prev_2 = block_nr; + pages[block->phys_2 >> 12].block_2 = block_nr; + } + else + { + block->next_2 = BLOCK_INVALID; + pages[block->phys_2 >> 12].block_2 = block_nr; + } + } +// pclog(" add_to_block_list: %p flags = %x\n", block, block->flags); +} + +static void remove_from_block_list(codeblock_t *block, uint32_t pc) +{ + if (!block->page_mask) + return; +#ifndef RELEASE_BUILD + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("remove_from_block_list: in dirty list\n"); +#endif + if (block->prev) + { + codeblock[block->prev].next = block->next; + if (block->next) + codeblock[block->next].prev = block->prev; + } + else + { + pages[block->phys >> 12].block = block->next; + if (block->next) + codeblock[block->next].prev = BLOCK_INVALID; + else + mem_flush_write_page(block->phys, 0); + } + + if (!(block->flags & CODEBLOCK_HAS_PAGE2)) + { +#ifndef RELEASE_BUILD + if (block->prev_2 || block->next_2) + fatal("Invalid block_2 %x %p %08x\n", block->flags, block, block->phys); +#endif + return; + } + block->flags &= ~CODEBLOCK_HAS_PAGE2; +// pclog(" remove_from_block_list: %p flags = %x\n", block, block->flags); + + if (block->prev_2) + { + codeblock[block->prev_2].next_2 = block->next_2; + if (block->next_2) + codeblock[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) + codeblock[block->next_2].prev_2 = BLOCK_INVALID; + else + mem_flush_write_page(block->phys_2, 0); + } +} + +static void invalidate_block(codeblock_t *block) +{ + uint32_t old_pc = block->pc; + +#ifndef RELEASE_BUILD + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + fatal("invalidate_block: already in dirty list\n"); + if (block->pc == BLOCK_PC_INVALID) + fatal("Invalidating deleted block\n"); +#endif + remove_from_block_list(block, old_pc); + block_dirty_list_add(block); + if (block->head_mem_block) + codegen_allocator_free(block->head_mem_block); + block->head_mem_block = NULL; +} + +static void delete_block(codeblock_t *block) +{ + uint32_t old_pc = block->pc; + + if (block == &codeblock[codeblock_hash[HASH(block->phys)]]) + codeblock_hash[HASH(block->phys)] = BLOCK_INVALID; + +#ifndef RELEASE_BUILD + if (block->pc == BLOCK_PC_INVALID) + fatal("Deleting deleted block\n"); +#endif + block->pc = BLOCK_PC_INVALID; + + codeblock_tree_delete(block); + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block_dirty_list_remove(block); + else + remove_from_block_list(block, old_pc); + if (block->head_mem_block) + codegen_allocator_free(block->head_mem_block); + block->head_mem_block = NULL; + block_free_list_add(block); +} + +static void delete_dirty_block(codeblock_t *block) +{ + if (block == &codeblock[codeblock_hash[HASH(block->phys)]]) + codeblock_hash[HASH(block->phys)] = BLOCK_INVALID; + +#ifndef RELEASE_BUILD + if (block->pc == BLOCK_PC_INVALID) + fatal("Deleting deleted block\n"); +#endif + block->pc = BLOCK_PC_INVALID; + + codeblock_tree_delete(block); + block_free_list_add(block); +} + +void codegen_delete_block(codeblock_t *block) +{ + if (block->pc != BLOCK_PC_INVALID) + delete_block(block); +} + +void codegen_delete_random_block(int required_mem_block) +{ + int block_nr = rand() & BLOCK_MASK; + + while (1) + { + if (block_nr && block_nr != block_current) + { + codeblock_t *block = &codeblock[block_nr]; + + if (block->pc != BLOCK_PC_INVALID && (!required_mem_block || block->head_mem_block)) + { + delete_block(block); + return; + } + } + block_nr = (block_nr + 1) & BLOCK_MASK; + } +} + +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) +{ + uint16_t block_nr = page->block; + int remove_from_evict_list = 0; + int c; + + while (block_nr) + { + codeblock_t *block = &codeblock[block_nr]; + uint16_t next_block = block->next; + + if (*block->dirty_mask & block->page_mask) + { +// pclog("Delete block from codegen_check_flush %08x %08x %016llx %016llx %016llx %02x\n", phys_addr, block->pc, *block->dirty_mask, block->page_mask, *block->dirty_mask & block->page_mask, block->flags); + invalidate_block(block); + cpu_recomp_evicted++; + } +#ifndef RELEASE_BUILD + if (block_nr == next_block) + fatal("Broken 1\n"); +#endif + block_nr = next_block; + } + + block_nr = page->block_2; + + while (block_nr) + { + codeblock_t *block = &codeblock[block_nr]; + uint16_t next_block = block->next_2; + + if (*block->dirty_mask2 & block->page_mask2) + { +// pclog("Delete block from codegen_check_flush2 %08x %08x\n", phys_addr, block->pc);*/ + invalidate_block(block); + cpu_recomp_evicted++; + } +#ifndef RELEASE_BUILD + if (block_nr == next_block) + fatal("Broken 2\n"); +#endif + block_nr = next_block; + } + + if (page->code_present_mask & page->dirty_mask) + remove_from_evict_list = 1; + page->code_present_mask &= ~page->dirty_mask; + page->dirty_mask = 0; + + for (c = 0; c < 64; c++) + { + if (page->byte_code_present_mask[c] & page->byte_dirty_mask[c]) + remove_from_evict_list = 0; + page->byte_code_present_mask[c] &= ~page->byte_dirty_mask[c]; + page->byte_dirty_mask[c] = 0; + } + if (remove_from_evict_list) + page_remove_from_evict_list(page); +} + +void codegen_block_init(uint32_t phys_addr) +{ + codeblock_t *block; + page_t *page = &pages[phys_addr >> 12]; + + if (!page->block) + mem_flush_write_page(phys_addr, cs+cpu_state.pc); + block = block_free_list_get(); +#ifndef RELEASE_BUILD + if (!block) + fatal("codegen_block_init: block_free_list_get() returned NULL\n"); +#endif + block_current = get_block_nr(block); + + block_num = HASH(phys_addr); + codeblock_hash[block_num] = block_current; + + block->ins = 0; + block->pc = cs + cpu_state.pc; + block->_cs = cs; + block->phys = phys_addr; + block->dirty_mask = &page->dirty_mask; + block->dirty_mask2 = NULL; + block->next = block->prev = BLOCK_INVALID; + block->next_2 = block->prev_2 = BLOCK_INVALID; + block->page_mask = block->page_mask2 = 0; + block->flags = CODEBLOCK_STATIC_TOP; +// pclog(" block_init: %p flags = %x\n", block, block->flags); + block->status = cpu_cur_status; + + recomp_page = block->phys & ~0xfff; +// pclog("codegen_block_init: %08x\n", block->pc); + codeblock_tree_add(block); +} + +static ir_data_t *ir_data; + +ir_data_t *codegen_get_ir_data() +{ + return ir_data; +} + +void codegen_block_start_recompile(codeblock_t *block) +{ + page_t *page = &pages[block->phys >> 12]; + + if (!page->block) + mem_flush_write_page(block->phys, cs+cpu_state.pc); + + block_num = HASH(block->phys); + block_current = get_block_nr(block);//block->pnt; +#ifndef RELEASE_BUILD + if (block->pc != cs + cpu_state.pc || (block->flags & CODEBLOCK_WAS_RECOMPILED)) + fatal("Recompile to used block!\n"); +#endif + block->head_mem_block = codegen_allocator_allocate(NULL, block_current); + block->data = codeblock_allocator_get_ptr(block->head_mem_block); + + block->status = cpu_cur_status; + + block->page_mask = block->page_mask2 = 0; + block->ins = 0; + + cpu_block_end = 0; + +// 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 = block->phys & ~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; + + cpu_state.seg_ds.checked = cpu_state.seg_es.checked = cpu_state.seg_fs.checked = cpu_state.seg_gs.checked = (cr0 & 1) ? 0 : 1; + + block->TOP = cpu_state.TOP & 7; + block->flags |= CODEBLOCK_WAS_RECOMPILED; + + codegen_flat_ds = !(cpu_cur_status & CPU_STATUS_NOTFLATDS); + codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); + + if (block->flags & CODEBLOCK_BYTE_MASK) + { + block->dirty_mask = &page->byte_dirty_mask[(block->phys >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK]; + block->dirty_mask2 = NULL; + } + + ir_data = codegen_ir_init(); + ir_data->block = block; + codegen_reg_reset(); + codegen_accumulate_reset(); + codegen_generate_reset(); +} + + +void codegen_block_remove() +{ + codeblock_t *block = &codeblock[block_current]; + + delete_block(block); + cpu_recomp_removed++; + + recomp_page = -1; +} + +void codegen_block_generate_end_mask_recompile() +{ + codeblock_t *block = &codeblock[block_current]; + page_t *p; +//pclog("gen_end_mask: %08x %08x %016llx %016llx\n", block->pc, codegen_endpc, block->page_mask,block->page_mask2); + + p = &pages[block->phys >> 12]; + if (block->flags & CODEBLOCK_BYTE_MASK) + { + int offset = (block->phys >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + + p->byte_code_present_mask[offset] |= block->page_mask; + } + else + p->code_present_mask |= block->page_mask; + + if ((*(block->dirty_mask) & block->page_mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + + block->phys_2 = -1; + block->next_2 = block->prev_2 = BLOCK_INVALID; + if (block->page_mask2) + { + block->phys_2 = get_phys_noabrt(codegen_endpc); + if (block->phys_2 != -1) + { + page_t *page_2 = &pages[block->phys_2 >> 12]; + + if (block->flags & CODEBLOCK_BYTE_MASK) + { + int offset = (block->phys_2 >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + + page_2->byte_code_present_mask[offset] |= block->page_mask2; + block->dirty_mask2 = &page_2->byte_dirty_mask[offset]; + } + else + { + page_2->code_present_mask |= block->page_mask2; + block->dirty_mask2 = &page_2->dirty_mask; + } + if (((*block->dirty_mask2) & block->page_mask2) && !page_in_evict_list(page_2)) + page_add_to_evict_list(page_2); + + if (!pages[block->phys_2 >> 12].block_2) + mem_flush_write_page(block->phys_2, codegen_endpc); + +#ifndef RELEASE_BUILD + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { +// pclog(" next_2->pc=%08x\n", block->next_2->pc); + if (codeblock[block->next_2].pc == BLOCK_PC_INVALID) + fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)&codeblock[block->next_2]); + } +#endif + } + else + { + /*Second page not present. page_mask2 is most likely set only because + the recompiler didn't know how long the last instruction was, so + clear it*/ + block->page_mask2 = 0; + } + } + +// pclog("block_end: %08x %08x %016llx\n", block->pc, codegen_endpc, block->page_mask); + recomp_page = -1; +} + +void codegen_block_generate_end_mask_mark() +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t start_pc; + uint32_t end_pc; + page_t *p; + +#ifndef RELEASE_BUILD + if (block->flags & CODEBLOCK_BYTE_MASK) + fatal("codegen_block_generate_end_mask2() - BYTE_MASK\n"); +#endif + block->page_mask = 0; + start_pc = (block->pc & 0xfff) & ~63; + if ((block->pc ^ codegen_endpc) & ~0xfff) + end_pc = 0xfff & ~63; + else + end_pc = (codegen_endpc & 0xfff) & ~63; + if (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); + } + + p = &pages[block->phys >> 12]; + p->code_present_mask |= block->page_mask; + if ((p->dirty_mask & block->page_mask) && !page_in_evict_list(p)) + page_add_to_evict_list(p); + + block->phys_2 = -1; + block->page_mask2 = 0; + block->next_2 = block->prev_2 = BLOCK_INVALID; + if ((block->pc ^ codegen_endpc) & ~0xfff) + { + block->phys_2 = get_phys_noabrt(codegen_endpc); + if (block->phys_2 != -1) + { + page_t *page_2 = &pages[block->phys_2 >> 12]; + + start_pc = 0; + end_pc = (codegen_endpc & 0xfff) >> PAGE_MASK_SHIFT; + for (; start_pc <= end_pc; start_pc++) + block->page_mask2 |= ((uint64_t)1 << start_pc); + + page_2->code_present_mask |= block->page_mask2; + if ((page_2->dirty_mask & block->page_mask2) && !page_in_evict_list(page_2)) + page_add_to_evict_list(page_2); + + if (!pages[block->phys_2 >> 12].block_2) + mem_flush_write_page(block->phys_2, codegen_endpc); +#ifndef RELEASE_BUILD + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { +// pclog(" next_2->pc=%08x\n", block->next_2->pc); + if (codeblock[block->next_2].pc == BLOCK_PC_INVALID) + fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)&codeblock[block->next_2]); + } +#endif + block->dirty_mask2 = &page_2->dirty_mask; + } + else + { + /*Second page not present. page_mask2 is most likely set only because + the recompiler didn't know how long the last instruction was, so + clear it*/ + block->page_mask2 = 0; + } + } + +// pclog("block_end: %08x %08x %016llx\n", block->pc, codegen_endpc, block->page_mask); + recomp_page = -1; +} + +void codegen_block_end() +{ + codeblock_t *block = &codeblock[block_current]; + + codegen_block_generate_end_mask_mark(); + add_to_block_list(block); +} + +void codegen_block_end_recompile(codeblock_t *block) +{ + codegen_timing_block_end(); + codegen_accumulate(ACCREG_cycles, -codegen_block_cycles); + + if (block->flags & CODEBLOCK_IN_DIRTY_LIST) + block_dirty_list_remove(block); + else + remove_from_block_list(block, block->pc); + block->next = block->prev = BLOCK_INVALID; + block->next_2 = block->prev_2 = BLOCK_INVALID; + codegen_block_generate_end_mask_recompile(); + add_to_block_list(block); +// pclog("End block %i\n", block_num); + + if (!(block->flags & CODEBLOCK_HAS_FPU)) + block->flags &= ~CODEBLOCK_STATIC_TOP; + + codegen_accumulate_flush(ir_data); + codegen_ir_compile(ir_data, block); +} + +void codegen_flush() +{ + return; +} + +void codegen_mark_code_present_multibyte(codeblock_t *block, uint32_t start_pc, int len) +{ + if (len) + { + uint32_t end_pc = start_pc + (len-1); + + if (block->flags & CODEBLOCK_BYTE_MASK) + { + uint32_t start_pc_masked = start_pc & PAGE_MASK_MASK; + uint32_t end_pc_masked = end_pc & PAGE_MASK_MASK; + + if ((start_pc ^ block->pc) & ~0x3f) /*Starts in second page*/ + { + for (; start_pc_masked <= end_pc_masked; start_pc_masked++) + block->page_mask2 |= ((uint64_t)1 << start_pc_masked); + } + else if (((start_pc + (len-1)) ^ block->pc) & ~0x3f) /*Crosses both pages*/ + { + for (; start_pc_masked <= 63; start_pc_masked++) + block->page_mask |= ((uint64_t)1 << start_pc_masked); + for (start_pc_masked = 0; start_pc_masked <= end_pc_masked; start_pc_masked++) + block->page_mask2 |= ((uint64_t)1 << start_pc_masked); + } + else /*First page only*/ + { + for (; start_pc_masked <= end_pc_masked; start_pc_masked++) + block->page_mask |= ((uint64_t)1 << start_pc_masked); + } + } + else + { + uint32_t start_pc_shifted = start_pc >> PAGE_MASK_SHIFT; + uint32_t end_pc_shifted = end_pc >> PAGE_MASK_SHIFT; + start_pc_shifted &= PAGE_MASK_MASK; + end_pc_shifted &= PAGE_MASK_MASK; + + if ((start_pc ^ block->pc) & ~0xfff) /*Starts in second page*/ + { + for (; start_pc_shifted <= end_pc_shifted; start_pc_shifted++) + block->page_mask2 |= ((uint64_t)1 << start_pc_shifted); + } + else if (((start_pc + (len-1)) ^ block->pc) & ~0xfff) /*Crosses both pages*/ + { + for (; start_pc_shifted <= 63; start_pc_shifted++) + block->page_mask |= ((uint64_t)1 << start_pc_shifted); + for (start_pc_shifted = 0; start_pc_shifted <= end_pc_shifted; start_pc_shifted++) + block->page_mask2 |= ((uint64_t)1 << start_pc_shifted); + } + else /*First page only*/ + { + for (; start_pc_shifted <= end_pc_shifted; start_pc_shifted++) + block->page_mask |= ((uint64_t)1 << start_pc_shifted); + } + } + } +} diff --git a/src/codegen_ir.c b/src/codegen_ir.c new file mode 100644 index 0000000..e42ac49 --- /dev/null +++ b/src/codegen_ir.c @@ -0,0 +1,214 @@ +#include "ibm.h" +#include "codegen.h" +#include "codegen_allocator.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_reg.h" + +extern int has_ea; +static ir_data_t ir_block; + +static int codegen_unroll_start, codegen_unroll_count; +static int codegen_unroll_first_instruction; + +ir_data_t *codegen_ir_init() +{ + ir_block.wr_pos = 0; +// pclog("codegen_ir_init %04x:%04x\n", CS,cpu_state.pc); + + codegen_unroll_count = 0; + + return &ir_block; +} + +void codegen_ir_set_unroll(int count, int start, int first_instruction) +{ + codegen_unroll_count = count; + codegen_unroll_start = start; + codegen_unroll_first_instruction = first_instruction; +} + +static void duplicate_uop(ir_data_t *ir, uop_t *uop, int offset) +{ + uop_t *new_uop = uop_alloc(ir, uop->type); + +// pclog(" uop type %08x\n", uop->type); + if (!ir_reg_is_invalid(uop->src_reg_a)) + new_uop->src_reg_a = codegen_reg_read(uop->src_reg_a.reg); + if (!ir_reg_is_invalid(uop->src_reg_b)) + new_uop->src_reg_b = codegen_reg_read(uop->src_reg_b.reg); + if (!ir_reg_is_invalid(uop->src_reg_c)) + new_uop->src_reg_c = codegen_reg_read(uop->src_reg_c.reg); + if (!ir_reg_is_invalid(uop->dest_reg_a)) + new_uop->dest_reg_a = codegen_reg_write(uop->dest_reg_a.reg, ir->wr_pos-1); + + new_uop->type = uop->type; + new_uop->imm_data = uop->imm_data; + new_uop->p = uop->p; + new_uop->pc = uop->pc; + + if (uop->jump_dest_uop != -1) + { + new_uop->jump_dest_uop = uop->jump_dest_uop + offset; + } +} + +void codegen_ir_compile(ir_data_t *ir, codeblock_t *block) +{ + int jump_target_at_end = -1; + int c; + + if (codegen_unroll_count) + { + int unroll_count; + int unroll_end; + + codegen_set_loop_start(ir, codegen_unroll_first_instruction); + unroll_end = ir->wr_pos; + + for (unroll_count = 1; unroll_count < codegen_unroll_count; unroll_count++) + { + int offset = ir->wr_pos - codegen_unroll_start; +// pclog("Unroll from %i to %i, offset %i - iteration %i\n", codegen_unroll_start, ir->wr_pos, offset, unroll_count); + for (c = codegen_unroll_start; c < unroll_end; c++) + { +// pclog(" Duplicate uop %i\n", c); + duplicate_uop(ir, &ir->uops[c], offset); + } + } + } + + codegen_reg_mark_as_required(); + codegen_reg_process_dead_list(ir); + block_write_data = codeblock_allocator_get_ptr(block->head_mem_block); + block_pos = 0; + codegen_backend_prologue(block); + + for (c = 0; c < ir->wr_pos; c++) + { + uop_t *uop = &ir->uops[c]; + +// pclog("uOP %i : %08x\n", c, uop->type); + + if (uop->type & UOP_TYPE_BARRIER) + codegen_reg_flush_invalidate(ir, block); + + if (uop->type & UOP_TYPE_JUMP_DEST) + { + uop_t *uop_dest = uop; + + while (uop_dest->jump_list_next != -1) + { + uop_dest = &ir->uops[uop_dest->jump_list_next]; + codegen_set_jump_dest(block, uop_dest->p); + } + } + + if ((uop->type & UOP_MASK) == UOP_INVALID) + continue; + +#ifdef CODEGEN_BACKEND_HAS_MOV_IMM + if ((uop->type & UOP_MASK) == (UOP_MOV_IMM & UOP_MASK) && reg_is_native_size(uop->dest_reg_a) && !codegen_reg_is_loaded(uop->dest_reg_a) && reg_version[IREG_GET_REG(uop->dest_reg_a.reg)][uop->dest_reg_a.version].refcount <= 0) + { + /*Special case for UOP_MOV_IMM - if destination not already in host register + and won't be used again then just store directly to memory*/ + codegen_reg_write_imm(block, uop->dest_reg_a, uop->imm_data); + } + else +#endif + if ((uop->type & UOP_MASK) == (UOP_MOV & UOP_MASK) && reg_version[IREG_GET_REG(uop->src_reg_a.reg)][uop->src_reg_a.version].refcount <= 1 && + reg_is_native_size(uop->src_reg_a) && reg_is_native_size(uop->dest_reg_a)) + { + /*Special case for UOP_MOV - if source register won't be used again then + just rename it to dest register instead of moving*/ + codegen_reg_alloc_register(invalid_ir_reg, uop->src_reg_a, invalid_ir_reg, invalid_ir_reg); + uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL); + codegen_reg_rename(block, uop->src_reg_a, uop->dest_reg_a); + if (uop->type & UOP_TYPE_ORDER_BARRIER) + codegen_reg_flush(ir, block); + } + else + { + if (uop->type & UOP_TYPE_PARAMS_REGS) + { + codegen_reg_alloc_register(uop->dest_reg_a, uop->src_reg_a, uop->src_reg_b, uop->src_reg_c); + if (uop->src_reg_a.reg != IREG_INVALID) + { + uop->src_reg_a_real = codegen_reg_alloc_read_reg(block, uop->src_reg_a, NULL); + } + if (uop->src_reg_b.reg != IREG_INVALID) + { + uop->src_reg_b_real = codegen_reg_alloc_read_reg(block, uop->src_reg_b, NULL); + } + if (uop->src_reg_c.reg != IREG_INVALID) + { + uop->src_reg_c_real = codegen_reg_alloc_read_reg(block, uop->src_reg_c, NULL); + } + } + + if (uop->type & UOP_TYPE_ORDER_BARRIER) + codegen_reg_flush(ir, block); + + if (uop->type & UOP_TYPE_PARAMS_REGS) + { + if (uop->dest_reg_a.reg != IREG_INVALID) + { + uop->dest_reg_a_real = codegen_reg_alloc_write_reg(block, uop->dest_reg_a); + } + } +#ifndef RELEASE_BUILD + if (!uop_handlers[uop->type & UOP_MASK]) + fatal("!uop_handlers[uop->type & UOP_MASK] %08x\n", uop->type); +#endif + uop_handlers[uop->type & UOP_MASK](block, uop); + } + + if (uop->type & UOP_TYPE_JUMP) + { + if (uop->jump_dest_uop == ir->wr_pos) + { + if (jump_target_at_end == -1) + jump_target_at_end = c; + else + { + uop_t *uop_dest = &ir->uops[jump_target_at_end]; + + while (uop_dest->jump_list_next != -1) + uop_dest = &ir->uops[uop_dest->jump_list_next]; + + uop_dest->jump_list_next = c; + } + } + else + { + uop_t *uop_dest = &ir->uops[uop->jump_dest_uop]; + + while (uop_dest->jump_list_next != -1) + uop_dest = &ir->uops[uop_dest->jump_list_next]; + + uop_dest->jump_list_next = c; + ir->uops[uop->jump_dest_uop].type |= UOP_TYPE_JUMP_DEST; + } + } + } + + codegen_reg_flush_invalidate(ir, block); + + if (jump_target_at_end != -1) + { + uop_t *uop_dest = &ir->uops[jump_target_at_end]; + + while (1) + { + codegen_set_jump_dest(block, uop_dest->p); + if (uop_dest->jump_list_next == -1) + break; + uop_dest = &ir->uops[uop_dest->jump_list_next]; + } + } + + codegen_backend_epilogue(block); + block_write_data = NULL; +// if (has_ea) +// fatal("IR compilation complete\n"); +} diff --git a/src/codegen_ir.h b/src/codegen_ir.h new file mode 100644 index 0000000..6274816 --- /dev/null +++ b/src/codegen_ir.h @@ -0,0 +1,6 @@ +#include "codegen_ir_defs.h" + +ir_data_t *codegen_ir_init(); + +void codegen_ir_set_unroll(int count, int start, int first_instruction); +void codegen_ir_compile(ir_data_t *ir, codeblock_t *block); diff --git a/src/codegen_ir_defs.h b/src/codegen_ir_defs.h new file mode 100644 index 0000000..b1f4b3c --- /dev/null +++ b/src/codegen_ir_defs.h @@ -0,0 +1,817 @@ +#ifndef _CODEGEN_IR_DEFS_ +#define _CODEGEN_IR_DEFS_ + +#include "codegen_reg.h" + +#define UOP_REG(reg, size, version) ((reg) | (size) | (version << 8)) + +/*uOP is a barrier. All previous uOPs must have completed before this one executes. + All registers must have been written back or discarded. + This should be used when calling external functions that may change any emulated + registers.*/ +#define UOP_TYPE_BARRIER (1 << 31) + +/*uOP is a barrier. All previous uOPs must have completed before this one executes. + All registers must have been written back, but do not have to be discarded. + This should be used when calling functions that preserve registers, but can cause + the code block to exit (eg memory load/store functions).*/ +#define UOP_TYPE_ORDER_BARRIER (1 << 27) + +/*uOP uses source and dest registers*/ +#define UOP_TYPE_PARAMS_REGS (1 << 28) +/*uOP uses pointer*/ +#define UOP_TYPE_PARAMS_POINTER (1 << 29) +/*uOP uses immediate data*/ +#define UOP_TYPE_PARAMS_IMM (1 << 30) + +/*uOP is a jump, with the destination uOP in uop->jump_dest_uop. The compiler must + set jump_dest in the destination uOP to the address of the branch offset to be + written when known.*/ +#define UOP_TYPE_JUMP (1 << 26) +/*uOP is the destination of a jump, and must set the destination offset of the jump + at compile time.*/ +#define UOP_TYPE_JUMP_DEST (1 << 25) + + +#define UOP_LOAD_FUNC_ARG_0 (UOP_TYPE_PARAMS_REGS | 0x00) +#define UOP_LOAD_FUNC_ARG_1 (UOP_TYPE_PARAMS_REGS | 0x01) +#define UOP_LOAD_FUNC_ARG_2 (UOP_TYPE_PARAMS_REGS | 0x02) +#define UOP_LOAD_FUNC_ARG_3 (UOP_TYPE_PARAMS_REGS | 0x03) +#define UOP_LOAD_FUNC_ARG_0_IMM (UOP_TYPE_PARAMS_IMM | 0x08 | UOP_TYPE_BARRIER) +#define UOP_LOAD_FUNC_ARG_1_IMM (UOP_TYPE_PARAMS_IMM | 0x09 | UOP_TYPE_BARRIER) +#define UOP_LOAD_FUNC_ARG_2_IMM (UOP_TYPE_PARAMS_IMM | 0x0a | UOP_TYPE_BARRIER) +#define UOP_LOAD_FUNC_ARG_3_IMM (UOP_TYPE_PARAMS_IMM | 0x0b | UOP_TYPE_BARRIER) +#define UOP_CALL_FUNC (UOP_TYPE_PARAMS_POINTER | 0x10 | UOP_TYPE_BARRIER) +/*UOP_CALL_INSTRUCTION_FUNC - call instruction handler at p, check return value and exit block if non-zero*/ +#define UOP_CALL_INSTRUCTION_FUNC (UOP_TYPE_PARAMS_POINTER | 0x11 | UOP_TYPE_BARRIER) +#define UOP_STORE_P_IMM (UOP_TYPE_PARAMS_IMM | 0x12) +#define UOP_STORE_P_IMM_8 (UOP_TYPE_PARAMS_IMM | 0x13) +/*UOP_LOAD_SEG - load segment in src_reg_a to segment p via loadseg(), check return value and exit block if non-zero*/ +#define UOP_LOAD_SEG (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x14 | UOP_TYPE_BARRIER) +/*UOP_JMP - jump to ptr*/ +#define UOP_JMP (UOP_TYPE_PARAMS_POINTER | 0x15 | UOP_TYPE_ORDER_BARRIER) +/*UOP_CALL_FUNC - call instruction handler at p, dest_reg = return value*/ +#define UOP_CALL_FUNC_RESULT (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x16 | UOP_TYPE_BARRIER) +/*UOP_JMP_DEST - jump to ptr*/ +#define UOP_JMP_DEST (UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x17 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +#define UOP_NOP_BARRIER (UOP_TYPE_BARRIER | 0x18) +#define UOP_STORE_P_IMM_16 (UOP_TYPE_PARAMS_IMM | 0x19) + +#ifdef DEBUG_EXTRA +/*UOP_LOG_INSTR - log non-recompiled instruction in imm_data*/ +#define UOP_LOG_INSTR (UOP_TYPE_PARAMS_IMM | 0x1f) +#endif + +/*UOP_MOV_PTR - dest_reg = p*/ +#define UOP_MOV_PTR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x20) +/*UOP_MOV_IMM - dest_reg = imm_data*/ +#define UOP_MOV_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x21) +/*UOP_MOV - dest_reg = src_reg_a*/ +#define UOP_MOV (UOP_TYPE_PARAMS_REGS | 0x22) +/*UOP_MOVZX - dest_reg = zero_extend(src_reg_a)*/ +#define UOP_MOVZX (UOP_TYPE_PARAMS_REGS | 0x23) +/*UOP_MOVSX - dest_reg = sign_extend(src_reg_a)*/ +#define UOP_MOVSX (UOP_TYPE_PARAMS_REGS | 0x24) +/*UOP_MOV_DOUBLE_INT - dest_reg = (double)src_reg_a*/ +#define UOP_MOV_DOUBLE_INT (UOP_TYPE_PARAMS_REGS | 0x25) +/*UOP_MOV_INT_DOUBLE - dest_reg = (int)src_reg_a. New rounding control in src_reg_b, old rounding control in src_reg_c*/ +#define UOP_MOV_INT_DOUBLE (UOP_TYPE_PARAMS_REGS | 0x26) +/*UOP_MOV_INT_DOUBLE_64 - dest_reg = (int)src_reg_a. New rounding control in src_reg_b, old rounding control in src_reg_c*/ +#define UOP_MOV_INT_DOUBLE_64 (UOP_TYPE_PARAMS_REGS | 0x27) +/*UOP_MOV_REG_PTR - dest_reg = *p*/ +#define UOP_MOV_REG_PTR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x28) +/*UOP_MOVZX_REG_PTR_8 - dest_reg = *(uint8_t *)p*/ +#define UOP_MOVZX_REG_PTR_8 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x29) +/*UOP_MOVZX_REG_PTR_16 - dest_reg = *(uint16_t *)p*/ +#define UOP_MOVZX_REG_PTR_16 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x2a) +/*UOP_ADD - dest_reg = src_reg_a + src_reg_b*/ +#define UOP_ADD (UOP_TYPE_PARAMS_REGS | 0x30) +/*UOP_ADD_IMM - dest_reg = src_reg_a + immediate*/ +#define UOP_ADD_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x31) +/*UOP_AND - dest_reg = src_reg_a & src_reg_b*/ +#define UOP_AND (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x32) +/*UOP_AND_IMM - dest_reg = src_reg_a & immediate*/ +#define UOP_AND_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x33) +/*UOP_ADD_LSHIFT - dest_reg = src_reg_a + (src_reg_b << imm_data) + Intended for EA calcluations, imm_data must be between 0 and 3*/ +#define UOP_ADD_LSHIFT (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x34) +/*UOP_OR - dest_reg = src_reg_a | src_reg_b*/ +#define UOP_OR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x35) +/*UOP_OR_IMM - dest_reg = src_reg_a | immediate*/ +#define UOP_OR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x36) +/*UOP_SUB - dest_reg = src_reg_a - src_reg_b*/ +#define UOP_SUB (UOP_TYPE_PARAMS_REGS | 0x37) +/*UOP_SUB_IMM - dest_reg = src_reg_a - immediate*/ +#define UOP_SUB_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x38) +/*UOP_XOR - dest_reg = src_reg_a ^ src_reg_b*/ +#define UOP_XOR (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x39) +/*UOP_XOR_IMM - dest_reg = src_reg_a ^ immediate*/ +#define UOP_XOR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x3a) +/*UOP_ANDN - dest_reg = ~src_reg_a & src_reg_b*/ +#define UOP_ANDN (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x3b) +/*UOP_MEM_LOAD_ABS - dest_reg = src_reg_a:[immediate]*/ +#define UOP_MEM_LOAD_ABS (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x40 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_LOAD_REG - dest_reg = src_reg_a:[src_reg_b]*/ +#define UOP_MEM_LOAD_REG (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x41 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_ABS - src_reg_a:[immediate] = src_reg_b*/ +#define UOP_MEM_STORE_ABS (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x42 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_REG - src_reg_a:[src_reg_b] = src_reg_c*/ +#define UOP_MEM_STORE_REG (UOP_TYPE_PARAMS_REGS | 0x43 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_8 - byte src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_8 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x44 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_16 - word src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_16 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x45 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_IMM_32 - long src_reg_a:[src_reg_b] = imm_data*/ +#define UOP_MEM_STORE_IMM_32 (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x46 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_LOAD_SINGLE - dest_reg = (float)src_reg_a:[src_reg_b]*/ +#define UOP_MEM_LOAD_SINGLE (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x47 | UOP_TYPE_ORDER_BARRIER) +/*UOP_CMP_IMM_JZ - if (src_reg_a == imm_data) then jump to ptr*/ +#define UOP_CMP_IMM_JZ (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x48 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_LOAD_DOUBLE - dest_reg = (double)src_reg_a:[src_reg_b]*/ +#define UOP_MEM_LOAD_DOUBLE (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x49 | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_SINGLE - src_reg_a:[src_reg_b] = src_reg_c*/ +#define UOP_MEM_STORE_SINGLE (UOP_TYPE_PARAMS_REGS | 0x4a | UOP_TYPE_ORDER_BARRIER) +/*UOP_MEM_STORE_DOUBLE - src_reg_a:[src_reg_b] = src_reg_c*/ +#define UOP_MEM_STORE_DOUBLE (UOP_TYPE_PARAMS_REGS | 0x4b | UOP_TYPE_ORDER_BARRIER) +/*UOP_CMP_JB - if (src_reg_a < src_reg_b) then jump to ptr*/ +#define UOP_CMP_JB (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x4c | UOP_TYPE_ORDER_BARRIER) +/*UOP_CMP_JNBE - if (src_reg_a > src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNBE (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_POINTER | 0x4d | UOP_TYPE_ORDER_BARRIER) + +/*UOP_SAR - dest_reg = src_reg_a >> src_reg_b*/ +#define UOP_SAR (UOP_TYPE_PARAMS_REGS | 0x50) +/*UOP_SAR_IMM - dest_reg = src_reg_a >> immediate*/ +#define UOP_SAR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x51) +/*UOP_SHL - dest_reg = src_reg_a << src_reg_b*/ +#define UOP_SHL (UOP_TYPE_PARAMS_REGS | 0x52) +/*UOP_SHL_IMM - dest_reg = src_reg_a << immediate*/ +#define UOP_SHL_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x53) +/*UOP_SHR - dest_reg = src_reg_a >> src_reg_b*/ +#define UOP_SHR (UOP_TYPE_PARAMS_REGS | 0x54) +/*UOP_SHR_IMM - dest_reg = src_reg_a >> immediate*/ +#define UOP_SHR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x55) +/*UOP_ROL - dest_reg = src_reg_a rotate<< src_reg_b*/ +#define UOP_ROL (UOP_TYPE_PARAMS_REGS | 0x56) +/*UOP_ROL_IMM - dest_reg = src_reg_a rotate<< immediate*/ +#define UOP_ROL_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x57) +/*UOP_ROR - dest_reg = src_reg_a rotate>> src_reg_b*/ +#define UOP_ROR (UOP_TYPE_PARAMS_REGS | 0x58) +/*UOP_ROR_IMM - dest_reg = src_reg_a rotate>> immediate*/ +#define UOP_ROR_IMM (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | 0x59) + +/*UOP_CMP_IMM_JZ_DEST - if (src_reg_a == imm_data) then jump to ptr*/ +#define UOP_CMP_IMM_JZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x60 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_IMM_JNZ_DEST - if (src_reg_a != imm_data) then jump to ptr*/ +#define UOP_CMP_IMM_JNZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x61 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) + +/*UOP_CMP_JB_DEST - if (src_reg_a < src_reg_b) then jump to ptr*/ +#define UOP_CMP_JB_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x62 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNB_DEST - if (src_reg_a >= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNB_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x63 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JO_DEST - if (src_reg_a < src_reg_b) then jump to ptr*/ +#define UOP_CMP_JO_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x64 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNO_DEST - if (src_reg_a >= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNO_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x65 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JZ_DEST - if (src_reg_a == src_reg_b) then jump to ptr*/ +#define UOP_CMP_JZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x66 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNZ_DEST - if (src_reg_a != src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNZ_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x67 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JL_DEST - if (signed)(src_reg_a < src_reg_b) then jump to ptr*/ +#define UOP_CMP_JL_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x68 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNL_DEST - if (signed)(src_reg_a >= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNL_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x69 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JBE_DEST - if (src_reg_a <= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JBE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6a | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNBE_DEST - if (src_reg_a > src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNBE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6b | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JLE_DEST - if (signed)(src_reg_a <= src_reg_b) then jump to ptr*/ +#define UOP_CMP_JLE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6c | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_CMP_JNLE_DEST - if (signed)(src_reg_a > src_reg_b) then jump to ptr*/ +#define UOP_CMP_JNLE_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x6d | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) + + +/*UOP_TEST_JNS_DEST - if (src_reg_a positive) then jump to ptr*/ +#define UOP_TEST_JNS_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x70 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) +/*UOP_TEST_JS_DEST - if (src_reg_a positive) then jump to ptr*/ +#define UOP_TEST_JS_DEST (UOP_TYPE_PARAMS_REGS | UOP_TYPE_PARAMS_IMM | UOP_TYPE_PARAMS_POINTER | 0x71 | UOP_TYPE_ORDER_BARRIER | UOP_TYPE_JUMP) + +/*UOP_FP_ENTER - must be called before any FPU register accessed*/ +#define UOP_FP_ENTER (UOP_TYPE_PARAMS_IMM | 0x80 | UOP_TYPE_BARRIER) +/*UOP_FADD - (floating point) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_FADD (UOP_TYPE_PARAMS_REGS | 0x81) +/*UOP_FSUB - (floating point) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_FSUB (UOP_TYPE_PARAMS_REGS | 0x82) +/*UOP_FMUL - (floating point) dest_reg = src_reg_a * src_reg_b*/ +#define UOP_FMUL (UOP_TYPE_PARAMS_REGS | 0x83) +/*UOP_FDIV - (floating point) dest_reg = src_reg_a / src_reg_b*/ +#define UOP_FDIV (UOP_TYPE_PARAMS_REGS | 0x84) +/*UOP_FCOM - dest_reg = flags from compare(src_reg_a, src_reg_b)*/ +#define UOP_FCOM (UOP_TYPE_PARAMS_REGS | 0x85) +/*UOP_FABS - dest_reg = fabs(src_reg_a)*/ +#define UOP_FABS (UOP_TYPE_PARAMS_REGS | 0x86) +/*UOP_FCHS - dest_reg = fabs(src_reg_a)*/ +#define UOP_FCHS (UOP_TYPE_PARAMS_REGS | 0x87) +/*UOP_FTST - dest_reg = flags from compare(src_reg_a, 0)*/ +#define UOP_FTST (UOP_TYPE_PARAMS_REGS | 0x88) +/*UOP_FSQRT - dest_reg = fsqrt(src_reg_a)*/ +#define UOP_FSQRT (UOP_TYPE_PARAMS_REGS | 0x89) + +/*UOP_MMX_ENTER - must be called before any MMX registers accessed*/ +#define UOP_MMX_ENTER (UOP_TYPE_PARAMS_IMM | 0x90 | UOP_TYPE_BARRIER) +/*UOP_PADDB - (packed byte) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDB (UOP_TYPE_PARAMS_REGS | 0x91) +/*UOP_PADDW - (packed word) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDW (UOP_TYPE_PARAMS_REGS | 0x92) +/*UOP_PADDD - (packed long) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDD (UOP_TYPE_PARAMS_REGS | 0x93) +/*UOP_PADDSB - (packed byte with signed saturation) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDSB (UOP_TYPE_PARAMS_REGS | 0x94) +/*UOP_PADDSW - (packed word with signed saturation) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDSW (UOP_TYPE_PARAMS_REGS | 0x95) +/*UOP_PADDUSB - (packed byte with unsigned saturation) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDUSB (UOP_TYPE_PARAMS_REGS | 0x96) +/*UOP_PADDUSW - (packed word with unsigned saturation) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PADDUSW (UOP_TYPE_PARAMS_REGS | 0x97) +/*UOP_PSUBB - (packed byte) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBB (UOP_TYPE_PARAMS_REGS | 0x98) +/*UOP_PSUBW - (packed word) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBW (UOP_TYPE_PARAMS_REGS | 0x99) +/*UOP_PSUBD - (packed long) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBD (UOP_TYPE_PARAMS_REGS | 0x9a) +/*UOP_PSUBSB - (packed byte with signed saturation) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBSB (UOP_TYPE_PARAMS_REGS | 0x9b) +/*UOP_PSUBSW - (packed word with signed saturation) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBSW (UOP_TYPE_PARAMS_REGS | 0x9c) +/*UOP_PSUBUSB - (packed byte with unsigned saturation) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBUSB (UOP_TYPE_PARAMS_REGS | 0x9d) +/*UOP_PSUBUSW - (packed word with unsigned saturation) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PSUBUSW (UOP_TYPE_PARAMS_REGS | 0x9e) +/*UOP_PSLLW_IMM - (packed word) dest_reg = src_reg_a << immediate*/ +#define UOP_PSLLW_IMM (UOP_TYPE_PARAMS_REGS | 0x9f) +/*UOP_PSLLD_IMM - (packed long) dest_reg = src_reg_a << immediate*/ +#define UOP_PSLLD_IMM (UOP_TYPE_PARAMS_REGS | 0xa0) +/*UOP_PSLLQ_IMM - (packed quad) dest_reg = src_reg_a << immediate*/ +#define UOP_PSLLQ_IMM (UOP_TYPE_PARAMS_REGS | 0xa1) +/*UOP_PSRAW_IMM - (packed word) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRAW_IMM (UOP_TYPE_PARAMS_REGS | 0xa2) +/*UOP_PSRAD_IMM - (packed long) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRAD_IMM (UOP_TYPE_PARAMS_REGS | 0xa3) +/*UOP_PSRAQ_IMM - (packed quad) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRAQ_IMM (UOP_TYPE_PARAMS_REGS | 0xa4) +/*UOP_PSRLW_IMM - (packed word) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRLW_IMM (UOP_TYPE_PARAMS_REGS | 0xa5) +/*UOP_PSRLD_IMM - (packed long) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRLD_IMM (UOP_TYPE_PARAMS_REGS | 0xa6) +/*UOP_PSRLQ_IMM - (packed quad) dest_reg = src_reg_a >> immediate*/ +#define UOP_PSRLQ_IMM (UOP_TYPE_PARAMS_REGS | 0xa7) +/*UOP_PCMPEQB - (packed byte) dest_reg = (src_reg_a == src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPEQB (UOP_TYPE_PARAMS_REGS | 0xa8) +/*UOP_PCMPEQW - (packed word) dest_reg = (src_reg_a == src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPEQW (UOP_TYPE_PARAMS_REGS | 0xa9) +/*UOP_PCMPEQD - (packed long) dest_reg = (src_reg_a == src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPEQD (UOP_TYPE_PARAMS_REGS | 0xaa) +/*UOP_PCMPGTB - (packed signed byte) dest_reg = (src_reg_a > src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPGTB (UOP_TYPE_PARAMS_REGS | 0xab) +/*UOP_PCMPGTW - (packed signed word) dest_reg = (src_reg_a > src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPGTW (UOP_TYPE_PARAMS_REGS | 0xac) +/*UOP_PCMPGTD - (packed signed long) dest_reg = (src_reg_a > src_reg_b) ? ~0 : 0*/ +#define UOP_PCMPGTD (UOP_TYPE_PARAMS_REGS | 0xad) +/*UOP_PUNPCKLBW - (packed byte) dest_reg = interleave low src_reg_a/src_reg_b*/ +#define UOP_PUNPCKLBW (UOP_TYPE_PARAMS_REGS | 0xae) +/*UOP_PUNPCKLWD - (packed word) dest_reg = interleave low src_reg_a/src_reg_b*/ +#define UOP_PUNPCKLWD (UOP_TYPE_PARAMS_REGS | 0xaf) +/*UOP_PUNPCKLDQ - (packed long) dest_reg = interleave low src_reg_a/src_reg_b*/ +#define UOP_PUNPCKLDQ (UOP_TYPE_PARAMS_REGS | 0xb0) +/*UOP_PUNPCKHBW - (packed byte) dest_reg = interleave high src_reg_a/src_reg_b*/ +#define UOP_PUNPCKHBW (UOP_TYPE_PARAMS_REGS | 0xb1) +/*UOP_PUNPCKHWD - (packed word) dest_reg = interleave high src_reg_a/src_reg_b*/ +#define UOP_PUNPCKHWD (UOP_TYPE_PARAMS_REGS | 0xb2) +/*UOP_PUNPCKHDQ - (packed long) dest_reg = interleave high src_reg_a/src_reg_b*/ +#define UOP_PUNPCKHDQ (UOP_TYPE_PARAMS_REGS | 0xb3) +/*UOP_PACKSSWB - dest_reg = interleave src_reg_a/src_reg_b, converting words to bytes with signed saturation*/ +#define UOP_PACKSSWB (UOP_TYPE_PARAMS_REGS | 0xb4) +/*UOP_PACKSSDW - dest_reg = interleave src_reg_a/src_reg_b, converting longs to words with signed saturation*/ +#define UOP_PACKSSDW (UOP_TYPE_PARAMS_REGS | 0xb5) +/*UOP_PACKUSWB - dest_reg = interleave src_reg_a/src_reg_b, converting words to bytes with unsigned saturation*/ +#define UOP_PACKUSWB (UOP_TYPE_PARAMS_REGS | 0xb6) +/*UOP_PMULLW - (packed word) dest_reg = (src_reg_a * src_reg_b) & 0xffff*/ +#define UOP_PMULLW (UOP_TYPE_PARAMS_REGS | 0xb7) +/*UOP_PMULHW - (packed word) dest_reg = (src_reg_a * src_reg_b) >> 16*/ +#define UOP_PMULHW (UOP_TYPE_PARAMS_REGS | 0xb8) +/*UOP_PMADDWD - (packed word) dest_reg = (src_reg_a * src_reg_b) >> 16*/ +#define UOP_PMADDWD (UOP_TYPE_PARAMS_REGS | 0xb9) + +/*UOP_PFADD - (packed float) dest_reg = src_reg_a + src_reg_b*/ +#define UOP_PFADD (UOP_TYPE_PARAMS_REGS | 0xba) +/*UOP_PFSUB - (packed float) dest_reg = src_reg_a - src_reg_b*/ +#define UOP_PFSUB (UOP_TYPE_PARAMS_REGS | 0xbb) +/*UOP_PFMUL - (packed float) dest_reg = src_reg_a * src_reg_b*/ +#define UOP_PFMUL (UOP_TYPE_PARAMS_REGS | 0xbc) +/*UOP_PFMAX - (packed float) dest_reg = MAX(src_reg_a, src_reg_b)*/ +#define UOP_PFMAX (UOP_TYPE_PARAMS_REGS | 0xbd) +/*UOP_PFMIN - (packed float) dest_reg = MIN(src_reg_a, src_reg_b)*/ +#define UOP_PFMIN (UOP_TYPE_PARAMS_REGS | 0xbe) +/*UOP_PFCMPEQ - (packed float) dest_reg = (src_reg_a == src_reg_b) ? ~0 : 0*/ +#define UOP_PFCMPEQ (UOP_TYPE_PARAMS_REGS | 0xbf) +/*UOP_PFCMPGE - (packed float) dest_reg = (src_reg_a >= src_reg_b) ? ~0 : 0*/ +#define UOP_PFCMPGE (UOP_TYPE_PARAMS_REGS | 0xc0) +/*UOP_PFCMPGT - (packed float) dest_reg = (src_reg_a > src_reg_b) ? ~0 : 0*/ +#define UOP_PFCMPGT (UOP_TYPE_PARAMS_REGS | 0xc1) +/*UOP_PF2ID - (packed long)dest_reg = (packed float)src_reg_a*/ +#define UOP_PF2ID (UOP_TYPE_PARAMS_REGS | 0xc2) +/*UOP_PI2FD - (packed float)dest_reg = (packed long)src_reg_a*/ +#define UOP_PI2FD (UOP_TYPE_PARAMS_REGS | 0xc3) +/*UOP_PFRCP - (packed float) dest_reg[0] = dest_reg[1] = 1.0 / src_reg[0]*/ +#define UOP_PFRCP (UOP_TYPE_PARAMS_REGS | 0xc4) +/*UOP_PFRSQRT - (packed float) dest_reg[0] = dest_reg[1] = 1.0 / sqrt(src_reg[0])*/ +#define UOP_PFRSQRT (UOP_TYPE_PARAMS_REGS | 0xc5) + +#define UOP_MAX 0xc6 + +#define UOP_INVALID 0xff + +#define UOP_MASK 0xffff + +typedef struct uop_t +{ + uint32_t type; + ir_reg_t dest_reg_a; + ir_reg_t src_reg_a; + ir_reg_t src_reg_b; + ir_reg_t src_reg_c; + uint32_t imm_data; + void *p; + ir_host_reg_t dest_reg_a_real; + ir_host_reg_t src_reg_a_real, src_reg_b_real, src_reg_c_real; + int jump_dest_uop; + int jump_list_next; + void *jump_dest; + uint32_t pc; +} uop_t; + +#define UOP_NR_MAX 4096 + +typedef struct ir_data_t +{ + uop_t uops[UOP_NR_MAX]; + int wr_pos; + struct codeblock_t *block; +} ir_data_t; + +static inline uop_t *uop_alloc(ir_data_t *ir, uint32_t uop_type) +{ + uop_t *uop; + + if (ir->wr_pos >= UOP_NR_MAX) + fatal("Exceeded uOP max\n"); + + uop = &ir->uops[ir->wr_pos++]; + + uop->dest_reg_a = invalid_ir_reg; + uop->src_reg_a = invalid_ir_reg; + uop->src_reg_b = invalid_ir_reg; + uop->src_reg_c = invalid_ir_reg; + + uop->pc = cpu_state.oldpc; + + uop->jump_dest_uop = -1; + uop->jump_list_next = -1; + + if (uop_type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER)) + codegen_reg_mark_as_required(); + + return uop; +} + +static inline void uop_set_jump_dest(ir_data_t *ir, int jump_uop) +{ + uop_t *uop = &ir->uops[jump_uop]; + + uop->jump_dest_uop = ir->wr_pos; +} + +static inline int uop_gen(uint32_t uop_type, ir_data_t *ir) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + + return ir->wr_pos-1; +} + +static inline int uop_gen_reg_src1(uint32_t uop_type, ir_data_t *ir, int src_reg_a) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + + return ir->wr_pos-1; +} + +static inline void uop_gen_reg_src1_arg(uint32_t uop_type, ir_data_t *ir, int arg, int src_reg_a) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); +} + +static inline int uop_gen_reg_src1_imm(uint32_t uop_type, ir_data_t *ir, int src_reg, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg); + uop->imm_data = imm; + + return ir->wr_pos-1; +} + +static inline void uop_gen_reg_dst_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_dst_pointer(uint32_t uop_type, ir_data_t *ir, int dest_reg, void *p) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->p = p; +} + +static inline void uop_gen_reg_dst_src1(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); +} + +static inline void uop_gen_reg_dst_src1_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_dst_src2(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); +} + +static inline void uop_gen_reg_dst_src2_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_dst_src3(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg_a, int src_reg_b, int src_reg_c) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->src_reg_c = codegen_reg_read(src_reg_c); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); +} + +static inline void uop_gen_reg_dst_src_imm(uint32_t uop_type, ir_data_t *ir, int dest_reg, int src_reg, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg); + uop->dest_reg_a = codegen_reg_write(dest_reg, ir->wr_pos - 1); + uop->imm_data = imm; +} + +static inline int uop_gen_reg_src2(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + + return ir->wr_pos-1; +} + +static inline void uop_gen_reg_src2_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->imm_data = imm; +} + +static inline void uop_gen_reg_src3(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->src_reg_c = codegen_reg_read(src_reg_c); +} + +static inline void uop_gen_reg_src3_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, int src_reg_c, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->src_reg_c = codegen_reg_read(src_reg_c); + uop->imm_data = imm; +} + +static inline void uop_gen_imm(uint32_t uop_type, ir_data_t *ir, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->imm_data = imm; +} + +static inline void uop_gen_pointer(uint32_t uop_type, ir_data_t *ir, void *p) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->p = p; +} + +static inline void uop_gen_pointer_imm(uint32_t uop_type, ir_data_t *ir, void *p, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->p = p; + uop->imm_data = imm; +} + +static inline void uop_gen_reg_src_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->p = p; +} + +static inline void uop_gen_reg_src_pointer_imm(uint32_t uop_type, ir_data_t *ir, int src_reg_a, void *p, uint32_t imm) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->p = p; + uop->imm_data = imm; +} + +static inline void uop_gen_reg_src2_pointer(uint32_t uop_type, ir_data_t *ir, int src_reg_a, int src_reg_b, void *p) +{ + uop_t *uop = uop_alloc(ir, uop_type); + + uop->type = uop_type; + uop->src_reg_a = codegen_reg_read(src_reg_a); + uop->src_reg_b = codegen_reg_read(src_reg_b); + uop->p = p; +} + +#define uop_LOAD_FUNC_ARG_REG(ir, arg, reg) uop_gen_reg_src1(UOP_LOAD_FUNC_ARG_0 + arg, ir, reg) + +#define uop_LOAD_FUNC_ARG_IMM(ir, arg, imm) uop_gen_imm(UOP_LOAD_FUNC_ARG_0_IMM + arg, ir, imm) + +#define uop_ADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_ADD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_ADD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_ADD_IMM, ir, dst_reg, src_reg, imm) +#define uop_ADD_LSHIFT(ir, dst_reg, src_reg_a, src_reg_b, shift) uop_gen_reg_dst_src2_imm(UOP_ADD_LSHIFT, ir, dst_reg, src_reg_a, src_reg_b, shift) +#define uop_AND(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_AND, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_AND_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_AND_IMM, ir, dst_reg, src_reg, imm) +#define uop_ANDN(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_ANDN, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_OR(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_OR, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_OR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_OR_IMM, ir, dst_reg, src_reg, imm) +#define uop_SUB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_SUB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_SUB_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SUB_IMM, ir, dst_reg, src_reg, imm) +#define uop_XOR(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_XOR, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_XOR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_XOR_IMM, ir, dst_reg, src_reg, imm) + +#define uop_SAR(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_SAR, ir, dst_reg, src_reg, shift_reg) +#define uop_SAR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SAR_IMM, ir, dst_reg, src_reg, imm) +#define uop_SHL(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_SHL, ir, dst_reg, src_reg, shift_reg) +#define uop_SHL_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SHL_IMM, ir, dst_reg, src_reg, imm) +#define uop_SHR(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_SHR, ir, dst_reg, src_reg, shift_reg) +#define uop_SHR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_SHR_IMM, ir, dst_reg, src_reg, imm) +#define uop_ROL(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_ROL, ir, dst_reg, src_reg, shift_reg) +#define uop_ROL_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_ROL_IMM, ir, dst_reg, src_reg, imm) +#define uop_ROR(ir, dst_reg, src_reg, shift_reg) uop_gen_reg_dst_src2(UOP_ROR, ir, dst_reg, src_reg, shift_reg) +#define uop_ROR_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_ROR_IMM, ir, dst_reg, src_reg, imm) + +#define uop_CALL_FUNC(ir, p) uop_gen_pointer(UOP_CALL_FUNC, ir, p) +#define uop_CALL_FUNC_RESULT(ir, dst_reg, p) uop_gen_reg_dst_pointer(UOP_CALL_FUNC_RESULT, ir, dst_reg, p) +#define uop_CALL_INSTRUCTION_FUNC(ir, p) uop_gen_pointer(UOP_CALL_INSTRUCTION_FUNC, ir, p) + +#define uop_CMP_IMM_JZ(ir, src_reg, imm, p) uop_gen_reg_src_pointer_imm(UOP_CMP_IMM_JZ, ir, src_reg, p, imm) + +#define uop_CMP_IMM_JNZ_DEST(ir, src_reg, imm) uop_gen_reg_src1_imm(UOP_CMP_IMM_JNZ_DEST, ir, src_reg, imm) +#define uop_CMP_IMM_JZ_DEST(ir, src_reg, imm) uop_gen_reg_src1_imm(UOP_CMP_IMM_JZ_DEST, ir, src_reg, imm) + +#define uop_CMP_JB(ir, src_reg_a, src_reg_b, p) uop_gen_reg_src2_pointer(UOP_CMP_JB, ir, src_reg_a, src_reg_b, p) +#define uop_CMP_JNBE(ir, src_reg_a, src_reg_b, p) uop_gen_reg_src2_pointer(UOP_CMP_JNBE, ir, src_reg_a, src_reg_b, p) + +#define uop_CMP_JNB_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNB_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNBE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNBE_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNL_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNL_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNLE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNLE_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNO_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNO_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JNZ_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JNZ_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JB_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JB_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JBE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JBE_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JL_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JL_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JLE_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JLE_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JO_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JO_DEST, ir, src_reg_a, src_reg_b) +#define uop_CMP_JZ_DEST(ir, src_reg_a, src_reg_b) uop_gen_reg_src2(UOP_CMP_JZ_DEST, ir, src_reg_a, src_reg_b) + +#define uop_FADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FADD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FCOM(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FCOM, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FDIV(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FDIV, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FMUL(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FMUL, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_FSUB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_FSUB, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_FABS(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FABS, ir, dst_reg, src_reg) +#define uop_FCHS(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FCHS, ir, dst_reg, src_reg) +#define uop_FSQRT(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FSQRT, ir, dst_reg, src_reg) +#define uop_FTST(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_FTST, ir, dst_reg, src_reg) + +#define uop_FP_ENTER(ir) do { if (!codegen_fpu_entered) uop_gen_imm(UOP_FP_ENTER, ir, cpu_state.oldpc); codegen_fpu_entered = 1; codegen_mmx_entered = 0; } while (0) +#define uop_MMX_ENTER(ir) do { if (!codegen_mmx_entered) uop_gen_imm(UOP_MMX_ENTER, ir, cpu_state.oldpc); codegen_mmx_entered = 1; codegen_fpu_entered = 0; } while (0) + +#define uop_JMP(ir, p) uop_gen_pointer(UOP_JMP, ir, p) +#define uop_JMP_DEST(ir) uop_gen(UOP_JMP_DEST, ir) + +#define uop_LOAD_SEG(ir, p, src_reg) uop_gen_reg_src_pointer(UOP_LOAD_SEG, ir, src_reg, p) + +#define uop_MEM_LOAD_ABS(ir, dst_reg, seg_reg, imm) uop_gen_reg_dst_src_imm(UOP_MEM_LOAD_ABS, ir, dst_reg, seg_reg, imm) +#define uop_MEM_LOAD_REG(ir, dst_reg, seg_reg, addr_reg) uop_gen_reg_dst_src2_imm(UOP_MEM_LOAD_REG, ir, dst_reg, seg_reg, addr_reg, 0) +#define uop_MEM_LOAD_REG_OFFSET(ir, dst_reg, seg_reg, addr_reg, offset) uop_gen_reg_dst_src2_imm(UOP_MEM_LOAD_REG, ir, dst_reg, seg_reg, addr_reg, offset) +#define uop_MEM_LOAD_SINGLE(ir, dst_reg, seg_reg, addr_reg) uop_gen_reg_dst_src2_imm(UOP_MEM_LOAD_SINGLE, ir, dst_reg, seg_reg, addr_reg, 0) +#define uop_MEM_LOAD_DOUBLE(ir, dst_reg, seg_reg, addr_reg) uop_gen_reg_dst_src2_imm(UOP_MEM_LOAD_DOUBLE, ir, dst_reg, seg_reg, addr_reg, 0) +#define uop_MEM_STORE_ABS(ir, seg_reg, imm, src_reg) uop_gen_reg_src2_imm(UOP_MEM_STORE_ABS, ir, seg_reg, src_reg, imm) +#define uop_MEM_STORE_REG(ir, seg_reg, addr_reg, src_reg) uop_gen_reg_src3_imm(UOP_MEM_STORE_REG, ir, seg_reg, addr_reg, src_reg, 0) +#define uop_MEM_STORE_REG_OFFSET(ir, seg_reg, addr_reg, offset, src_reg) uop_gen_reg_src3_imm(UOP_MEM_STORE_REG, ir, seg_reg, addr_reg, src_reg, offset) +#define uop_MEM_STORE_IMM_8(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_8, ir, seg_reg, addr_reg, imm) +#define uop_MEM_STORE_IMM_16(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_16, ir, seg_reg, addr_reg, imm) +#define uop_MEM_STORE_IMM_32(ir, seg_reg, addr_reg, imm) uop_gen_reg_src2_imm(UOP_MEM_STORE_IMM_32, ir, seg_reg, addr_reg, imm) +#define uop_MEM_STORE_SINGLE(ir, seg_reg, addr_reg, src_reg) uop_gen_reg_src3_imm(UOP_MEM_STORE_SINGLE, ir, seg_reg, addr_reg, src_reg, 0) +#define uop_MEM_STORE_DOUBLE(ir, seg_reg, addr_reg, src_reg) uop_gen_reg_src3_imm(UOP_MEM_STORE_DOUBLE, ir, seg_reg, addr_reg, src_reg, 0) + +#define uop_MOV(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOV, ir, dst_reg, src_reg) +#define uop_MOV_IMM(ir, reg, imm) uop_gen_reg_dst_imm(UOP_MOV_IMM, ir, reg, imm) +#define uop_MOV_PTR(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOV_PTR, ir, reg, p) +#define uop_MOV_REG_PTR(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOV_REG_PTR, ir, reg, p) +#define uop_MOVZX_REG_PTR_8(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOVZX_REG_PTR_8, ir, reg, p) +#define uop_MOVZX_REG_PTR_16(ir, reg, p) uop_gen_reg_dst_pointer(UOP_MOVZX_REG_PTR_16, ir, reg, p) +#define uop_MOVSX(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOVSX, ir, dst_reg, src_reg) +#define uop_MOVZX(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOVZX, ir, dst_reg, src_reg) +#define uop_MOV_DOUBLE_INT(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_MOV_DOUBLE_INT, ir, dst_reg, src_reg) +#define uop_MOV_INT_DOUBLE(ir, dst_reg, src_reg/*, nrc, orc*/) uop_gen_reg_dst_src1(UOP_MOV_INT_DOUBLE, ir, dst_reg, src_reg/*, nrc, orc*/) +#define uop_MOV_INT_DOUBLE_64(ir, dst_reg, src_reg_d, src_reg_q, tag) uop_gen_reg_dst_src3(UOP_MOV_INT_DOUBLE_64, ir, dst_reg, src_reg_d, src_reg_q, tag) + +#define uop_NOP_BARRIER(ir) uop_gen(UOP_NOP_BARRIER, ir) + +#define uop_PACKSSWB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PACKSSWB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PACKSSDW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PACKSSDW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PACKUSWB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PACKUSWB, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PADDB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDSB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDSB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDSW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDSW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDUSB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDUSB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PADDUSW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PADDUSW, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PCMPEQB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPEQB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPEQW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPEQW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPEQD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPEQD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPGTB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPGTB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPGTW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPGTW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PCMPGTD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PCMPGTD, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PF2ID(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_PF2ID, ir, dst_reg, src_reg) +#define uop_PFADD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFADD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFCMPEQ(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFCMPEQ, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFCMPGE(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFCMPGE, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFCMPGT(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFCMPGT, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFMAX(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFMAX, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFMIN(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFMIN, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFMUL(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFMUL, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PFRCP(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_PFRCP, ir, dst_reg, src_reg) +#define uop_PFRSQRT(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_PFRSQRT, ir, dst_reg, src_reg) +#define uop_PFSUB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PFSUB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PI2FD(ir, dst_reg, src_reg) uop_gen_reg_dst_src1(UOP_PI2FD, ir, dst_reg, src_reg) + +#define uop_PMADDWD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PMADDWD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PMULHW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PMULHW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PMULLW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PMULLW, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PSLLW_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSLLW_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSLLD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSLLD_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSLLQ_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSLLQ_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRAW_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRAW_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRAD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRAD_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRAQ_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRAQ_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRLW_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRLW_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRLD_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRLD_IMM, ir, dst_reg, src_reg, imm) +#define uop_PSRLQ_IMM(ir, dst_reg, src_reg, imm) uop_gen_reg_dst_src_imm(UOP_PSRLQ_IMM, ir, dst_reg, src_reg, imm) + +#define uop_PSUBB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBSB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBSB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBSW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBSW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBUSB(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBUSB, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PSUBUSW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PSUBUSW, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_PUNPCKHBW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKHBW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKHWD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKHWD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKHDQ(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKHDQ, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKLBW(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKLBW, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKLWD(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKLWD, ir, dst_reg, src_reg_a, src_reg_b) +#define uop_PUNPCKLDQ(ir, dst_reg, src_reg_a, src_reg_b) uop_gen_reg_dst_src2(UOP_PUNPCKLDQ, ir, dst_reg, src_reg_a, src_reg_b) + +#define uop_STORE_PTR_IMM(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM, ir, p, imm) +#define uop_STORE_PTR_IMM_8(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_8, ir, p, imm) +#define uop_STORE_PTR_IMM_16(ir, p, imm) uop_gen_pointer_imm(UOP_STORE_P_IMM_16, ir, p, imm) + +#define uop_TEST_JNS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JNS_DEST, ir, src_reg) +#define uop_TEST_JS_DEST(ir, src_reg) uop_gen_reg_src1(UOP_TEST_JS_DEST, ir, src_reg) + +#ifdef DEBUG_EXTRA +#define uop_LOG_INSTR(ir, imm) uop_gen_imm(UOP_LOG_INSTR, ir, imm) +#endif + +void codegen_direct_read_8(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_16(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_32(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_64(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_pointer(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_double(codeblock_t *block, int host_reg, void *p); +void codegen_direct_read_st_8(codeblock_t *block, int host_reg, void *base, int reg_idx); +void codegen_direct_read_st_64(codeblock_t *block, int host_reg, void *base, int reg_idx); +void codegen_direct_read_st_double(codeblock_t *block, int host_reg, void *base, int reg_idx); + +void codegen_direct_write_8(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_16(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_32(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_64(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_pointer(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_ptr(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_double(codeblock_t *block, void *p, int host_reg); +void codegen_direct_write_st_8(codeblock_t *block, void *base, int reg_idx, int host_reg); +void codegen_direct_write_st_64(codeblock_t *block, void *base, int reg_idx, int host_reg); +void codegen_direct_write_st_double(codeblock_t *block, void *base, int reg_idx, int host_reg); + +void codegen_direct_read_16_stack(codeblock_t *block, int host_reg, int stack_offset); +void codegen_direct_read_32_stack(codeblock_t *block, int host_reg, int stack_offset); +void codegen_direct_read_64_stack(codeblock_t *block, int host_reg, int stack_offset); +void codegen_direct_read_pointer_stack(codeblock_t *block, int host_reg, int stack_offset); +void codegen_direct_read_double_stack(codeblock_t *block, int host_reg, int stack_offset); + +void codegen_direct_write_32_stack(codeblock_t *block, int stack_offset, int host_reg); +void codegen_direct_write_64_stack(codeblock_t *block, int stack_offset, int host_reg); +void codegen_direct_write_pointer_stack(codeblock_t *block, int stack_offset, int host_reg); +void codegen_direct_write_double_stack(codeblock_t *block, int stack_offset, int host_reg); + +void codegen_set_jump_dest(codeblock_t *block, void *p); + +void codegen_direct_write_8_imm(codeblock_t *block, void *p, uint8_t imm_data); +void codegen_direct_write_16_imm(codeblock_t *block, void *p, uint16_t imm_data); +void codegen_direct_write_32_imm(codeblock_t *block, void *p, uint32_t imm_data); +void codegen_direct_write_32_imm_stack(codeblock_t *block, int stack_offset, uint32_t imm_data); + +#endif diff --git a/src/codegen_ops.c b/src/codegen_ops.c index e4fb0c4..5c63795 100644 --- a/src/codegen_ops.c +++ b/src/codegen_ops.c @@ -1,129 +1,150 @@ #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_ir.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_3dnow.h" #include "codegen_ops_arith.h" -#include "codegen_ops_fpu.h" +#include "codegen_ops_branch.h" +#include "codegen_ops_fpu_arith.h" +#include "codegen_ops_fpu_constant.h" +#include "codegen_ops_fpu_loadstore.h" +#include "codegen_ops_fpu_misc.h" #include "codegen_ops_jump.h" #include "codegen_ops_logic.h" #include "codegen_ops_misc.h" -#include "codegen_ops_mmx.h" +#include "codegen_ops_mmx_arith.h" +#include "codegen_ops_mmx_cmp.h" +#include "codegen_ops_mmx_loadstore.h" +#include "codegen_ops_mmx_logic.h" +#include "codegen_ops_mmx_pack.h" +#include "codegen_ops_mmx_shift.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 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, ropPOP_ES_16, 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, ropPOP_DS_16, +/*10*/ ropADC_b_rmw, ropADC_w_rmw, ropADC_b_rm, ropADC_w_rm, ropADC_AL_imm, ropADC_AX_imm, ropPUSH_SS_16, NULL, ropSBB_b_rmw, ropSBB_w_rmw, ropSBB_b_rm, ropSBB_w_rm, ropSBB_AL_imm, ropSBB_AX_imm, ropPUSH_DS_16, ropPOP_DS_16, /*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, +/*40*/ ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropINC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, ropDEC_r16, +/*50*/ ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPUSH_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, ropPOP_r16, +/*60*/ ropPUSHA_16, ropPOPA_16, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_16, NULL, ropPUSH_imm_16_8,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO_8, ropJNO_8, ropJB_8, ropJNB_8, ropJE_8, ropJNE_8, ropJBE_8, ropJNBE_8, ropJS_8, ropJNS_8, ropJP_8, ropJNP_8, ropJL_8, ropJNL_8, ropJLE_8, ropJNLE_8, -/*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, ropMOV_w_seg, ropLEA_w, ropMOV_seg_w, 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, +/*80*/ rop80, rop81_w, rop80, rop83_w, ropTEST_b_rm, ropTEST_w_rm, ropXCHG_8, ropXCHG_16, ropMOV_b_r, ropMOV_w_r, ropMOV_r_b, ropMOV_r_w, ropMOV_w_seg, ropLEA_16, ropMOV_seg_w, ropPOP_W, +/*90*/ ropNOP, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropXCHG_AX, ropCBW, ropCWD, NULL, NULL, ropPUSHF, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_abs, ropMOV_AX_abs, ropMOV_abs_AL, ropMOV_abs_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, ropLES, ropLDS, 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, ropCLI, ropSTI, ropCLD, ropSTD, ropFE, ropFF_16, +/*c0*/ ropC0, ropC1_w, ropRET_imm_16, ropRET_16, ropLES_16, ropLDS_16, ropMOV_b_imm, ropMOV_w_imm, NULL, ropLEAVE_16, ropRETF_imm_16, ropRETF_16, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_w, ropD2, ropD3_w, NULL, NULL, NULL, ropXLAT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropLOOPNE, ropLOOPE, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, ropJMP_far_16, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, ropCMC, ropF6, ropF7_16, ropCLC, ropSTC, ropCLI, ropSTI, ropCLD, ropSTD, ropINCDEC, ropFF_16, /*32-bit data*/ -/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/* 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, ropPOP_ES_32, 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, ropPOP_DS_32, +/*10*/ ropADC_b_rmw, ropADC_l_rmw, ropADC_b_rm, ropADC_l_rm, ropADC_AL_imm, ropADC_EAX_imm, ropPUSH_SS_32, NULL, ropSBB_b_rmw, ropSBB_l_rmw, ropSBB_b_rm, ropSBB_l_rm, ropSBB_AL_imm, ropSBB_EAX_imm, ropPUSH_DS_32, ropPOP_DS_32, /*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, +/*40*/ ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropINC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, ropDEC_r32, +/*50*/ ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPUSH_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, ropPOP_r32, +/*60*/ ropPUSHA_32, ropPOPA_32, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_32, NULL, ropPUSH_imm_32_8,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO_8, ropJNO_8, ropJB_8, ropJNB_8, ropJE_8, ropJNE_8, ropJBE_8, ropJNBE_8, ropJS_8, ropJNS_8, ropJP_8, ropJNP_8, ropJL_8, ropJNL_8, ropJLE_8, ropJNLE_8, -/*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, ropMOV_w_seg, ropLEA_l, ropMOV_seg_w, 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, +/*80*/ rop80, rop81_l, rop80, rop83_l, ropTEST_b_rm, ropTEST_l_rm, ropXCHG_8, ropXCHG_32, ropMOV_b_r, ropMOV_l_r, ropMOV_r_b, ropMOV_r_l, ropMOV_l_seg, ropLEA_32, ropMOV_seg_w, ropPOP_L, +/*90*/ ropNOP, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropXCHG_EAX, ropCWDE, ropCDQ, NULL, NULL, ropPUSHFD, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_abs, ropMOV_EAX_abs, ropMOV_abs_AL, ropMOV_abs_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, ropLES, ropLDS, 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, ropCLI, ropSTI, ropCLD, ropSTD, ropFE, ropFF_32 +/*c0*/ ropC0, ropC1_l, ropRET_imm_32, ropRET_32, ropLES_32, ropLDS_32, ropMOV_b_imm, ropMOV_l_imm, NULL, ropLEAVE_32, ropRETF_imm_32, ropRETF_32, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_l, ropD2, ropD3_l, NULL, NULL, NULL, ropXLAT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropLOOPNE, ropLOOPE, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, ropJMP_far_32, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, ropCMC, ropF6, ropF7_32, ropCLC, ropSTC, ropCLI, ropSTI, ropCLD, ropSTD, ropINCDEC, 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 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_r_d, ropMOVQ_r_q, +/*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_d_r, ropMOVQ_q_r, + +/*80*/ ropJO_16, ropJNO_16, ropJB_16, ropJNB_16, ropJE_16, ropJNE_16, ropJBE_16, ropJNBE_16, ropJS_16, ropJNS_16, ropJP_16, ropJNP_16, ropJL_16, ropJNL_16, ropJLE_16, ropJNLE_16, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropPUSH_FS_16, ropPOP_FS_16, NULL, NULL, ropSHLD_16_imm, NULL, NULL, NULL, ropPUSH_GS_16, ropPOP_GS_16, NULL, NULL, ropSHRD_16_imm, NULL, NULL, NULL, +/*b0*/ NULL, NULL, ropLSS_16, NULL, ropLFS_16, ropLGS_16, ropMOVZX_16_8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_16_8, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, +/*e0*/ NULL, NULL, NULL, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, +/*f0*/ NULL, NULL, NULL, NULL, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, 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_r_d, ropMOVQ_r_q, +/*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_d_r, ropMOVQ_q_r, + +/*80*/ ropJO_32, ropJNO_32, ropJB_32, ropJNB_32, ropJE_32, ropJNE_32, ropJBE_32, ropJNBE_32, ropJS_32, ropJNS_32, ropJP_32, ropJNP_32, ropJL_32, ropJNL_32, ropJLE_32, ropJNLE_32, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropPUSH_FS_32, ropPOP_FS_32, NULL, NULL, ropSHLD_32_imm, NULL, NULL, NULL, ropPUSH_GS_32, ropPOP_GS_32, NULL, NULL, ropSHRD_32_imm, NULL, NULL, NULL, +/*b0*/ NULL, NULL, ropLSS_32, NULL, ropLFS_32, ropLGS_32, ropMOVZX_32_8, ropMOVZX_32_16, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_32_8, ropMOVSX_32_16, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, +/*e0*/ NULL, NULL, NULL, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, +/*f0*/ NULL, NULL, NULL, NULL, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL, +}; + +RecompOpFn recomp_opcodes_3DNOW[256] = +{ +/* 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, ropPI2FD, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPF2ID, 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, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 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*/ ropPUSH_FS_16, ropPOP_FS_16, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_GS_16, ropPOP_GS_16, NULL, NULL, NULL, NULL, NULL, NULL, -/*b0*/ NULL, NULL, ropLSS, NULL, ropLFS, ropLGS, ropMOVZX_w_b, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_w_b, NULL, +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropPFCMPGE, NULL, NULL, NULL, ropPFMIN, NULL, ropPFRCP, ropPFRSQRT, NULL, NULL, ropPFSUB, NULL, NULL, NULL, ropPFADD, NULL, +/*a0*/ ropPFCMPGT, NULL, NULL, NULL, ropPFMAX, NULL, ropPFRCPIT, ropPFRSQIT1, NULL, NULL, ropPFSUBR, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropPFCMPEQ, NULL, NULL, NULL, ropPFMUL, NULL, ropPFRCPIT, 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*/ -/*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*/ ropPUSH_FS_32, ropPOP_FS_32, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_GS_32, ropPOP_GS_32, NULL, NULL, NULL, NULL, NULL, NULL, -/*b0*/ NULL, NULL, ropLSS, NULL, ropLFS, ropLGS, 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 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, @@ -145,7 +166,7 @@ RecompOpFn recomp_opcodes_d8[512] = /*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 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, @@ -170,93 +191,93 @@ RecompOpFn recomp_opcodes_d8[512] = 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 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, +/*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, 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, +/*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, 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, +/*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, 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*/ ropFCHS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLD1, ropFLDL2T, ropFLDL2E, ropFLDPI, ropFLDEG2, ropFLDLN2, ropFLDZ, NULL, -/*f0*/ 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, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ ropFCHS, ropFABS, NULL, NULL, ropFTST, NULL, NULL, NULL, ropFLD1, NULL, NULL, NULL, NULL, NULL, ropFLDZ, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSQRT, 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 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, +/*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, 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, +/*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, 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, +/*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, 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*/ ropFCHS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLD1, ropFLDL2T, ropFLDL2E, ropFLDPI, ropFLDEG2, ropFLDLN2, ropFLDZ, NULL, -/*f0*/ 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, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ ropFCHS, ropFABS, NULL, NULL, ropFTST, NULL, NULL, NULL, ropFLD1, NULL, NULL, NULL, NULL, NULL, ropFLDZ, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSQRT, 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, +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*10*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*20*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*30*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, -/*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, +/*40*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*50*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*60*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*70*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, -/*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, +/*80*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*90*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*a0*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*b0*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, /*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, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFUCOMPP, 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, +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*10*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*20*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*30*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, -/*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, +/*40*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*50*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*60*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*70*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, -/*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, +/*80*/ ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIADDl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, ropFIMULl, +/*90*/ ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, ropFICOMPl, +/*a0*/ ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, ropFISUBRl, +/*b0*/ ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, ropFIDIVRl, /*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, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFUCOMPP, 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, }; @@ -264,7 +285,7 @@ RecompOpFn recomp_opcodes_da[512] = 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 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, @@ -286,8 +307,8 @@ RecompOpFn recomp_opcodes_db[512] = /*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, +/* 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, @@ -311,7 +332,7 @@ RecompOpFn recomp_opcodes_db[512] = 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 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, @@ -333,7 +354,7 @@ RecompOpFn recomp_opcodes_dc[512] = /*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 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, @@ -358,68 +379,68 @@ RecompOpFn recomp_opcodes_dc[512] = 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 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, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, /*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, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, /*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, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, -/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*c0*/ ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, 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, +/*e0*/ ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, /*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 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, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, /*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, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, /*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, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, ropFSTSW, -/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*c0*/ ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, ropFFREE, 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, +/*e0*/ ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOM, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, ropFUCOMP, /*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, +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*10*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*20*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*30*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, -/*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, +/*40*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*50*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*60*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*70*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, -/*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, +/*80*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*90*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*a0*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*b0*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, /*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, ropFCOMPP, NULL, NULL, NULL, NULL, NULL, NULL, @@ -427,21 +448,21 @@ RecompOpFn recomp_opcodes_de[512] = /*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, +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*10*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*20*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*30*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, -/*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, +/*40*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*50*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*60*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*70*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, -/*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, +/*80*/ ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIADDw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, ropFIMULw, +/*90*/ ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, ropFICOMPw, +/*a0*/ ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, ropFISUBRw, +/*b0*/ ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, ropFIDIVRw, /*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, ropFCOMPP, NULL, NULL, NULL, NULL, NULL, NULL, @@ -452,7 +473,7 @@ RecompOpFn recomp_opcodes_de[512] = 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 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, @@ -474,7 +495,7 @@ RecompOpFn recomp_opcodes_df[512] = /*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 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, diff --git a/src/codegen_ops.h b/src/codegen_ops.h index 3f0d1be..64f3547 100644 --- a/src/codegen_ops.h +++ b/src/codegen_ops.h @@ -1,7 +1,15 @@ -typedef uint32_t (*RecompOpFn)(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block); +#ifndef _CODEGEN_OPS_H_ +#define _CODEGEN_OPS_H_ + +#include "codegen.h" + +struct ir_data_t; + +typedef uint32_t (*RecompOpFn)(codeblock_t *block, struct ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); extern RecompOpFn recomp_opcodes[512]; extern RecompOpFn recomp_opcodes_0f[512]; +extern RecompOpFn recomp_opcodes_3DNOW[256]; extern RecompOpFn recomp_opcodes_d8[512]; extern RecompOpFn recomp_opcodes_d9[512]; extern RecompOpFn recomp_opcodes_da[512]; @@ -10,6 +18,8 @@ extern RecompOpFn recomp_opcodes_dc[512]; extern RecompOpFn recomp_opcodes_dd[512]; extern RecompOpFn recomp_opcodes_de[512]; extern RecompOpFn recomp_opcodes_df[512]; +/*extern RecompOpFn recomp_opcodes_REPE[512]; +extern RecompOpFn recomp_opcodes_REPNE[512];*/ #define REG_EAX 0 #define REG_ECX 1 @@ -35,3 +45,5 @@ extern RecompOpFn recomp_opcodes_df[512]; #define REG_DH 6 #define REG_BL 3 #define REG_BH 7 + +#endif diff --git a/src/codegen_ops_3dnow.c b/src/codegen_ops_3dnow.c new file mode 100644 index 0000000..7a2af83 --- /dev/null +++ b/src/codegen_ops_3dnow.c @@ -0,0 +1,208 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_3dnow.h" +#include "codegen_ops_helpers.h" + +#define ropParith(func) \ +uint32_t rop ## func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + int src_reg = fetchdat & 7; \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } \ + else \ + { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + codegen_mark_code_present(block, cs+op_pc+1, 1); \ + return op_pc + 2; \ +} + +ropParith(PFADD) +ropParith(PFCMPEQ) +ropParith(PFCMPGE) +ropParith(PFCMPGT) +ropParith(PFMAX) +ropParith(PFMIN) +ropParith(PFMUL) +ropParith(PFSUB) + +uint32_t ropPF2ID(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PF2ID(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PF2ID(ir, IREG_MM(dest_reg), IREG_temp0_Q); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +uint32_t ropPFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PFSUB(ir, IREG_MM(dest_reg), IREG_MM(src_reg), IREG_MM(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PFSUB(ir, IREG_MM(dest_reg), IREG_temp0_Q, IREG_MM(dest_reg)); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +uint32_t ropPI2FD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PI2FD(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PI2FD(ir, IREG_MM(dest_reg), IREG_temp0_Q); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +uint32_t ropPFRCPIT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_MM(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropPFRCP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PFRCP(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PFRCP(ir, IREG_MM(dest_reg), IREG_temp0_Q); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropPFRSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_PFRSQRT(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_PFRSQRT(ir, IREG_MM(dest_reg), IREG_temp0_Q); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +uint32_t ropPFRSQIT1(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MMX_ENTER(ir); + + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} diff --git a/src/codegen_ops_3dnow.h b/src/codegen_ops_3dnow.h new file mode 100644 index 0000000..3b124ae --- /dev/null +++ b/src/codegen_ops_3dnow.h @@ -0,0 +1,15 @@ +uint32_t ropPF2ID(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFCMPEQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFCMPGE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFCMPGT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFMAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFMIN(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFRCP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFRCPIT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFRSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFRSQIT1(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPI2FD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_arith.c b/src/codegen_ops_arith.c new file mode 100644 index 0000000..2127c57 --- /dev/null +++ b/src/codegen_ops_arith.c @@ -0,0 +1,2517 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_arith.h" +#include "codegen_ops_helpers.h" + +static inline void get_cf(ir_data_t *ir, int dest_reg) +{ + uop_CALL_FUNC_RESULT(ir, dest_reg, CF_SET); +} + +uint32_t ropADC_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_ADD_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_ADD(ir, IREG_AL, IREG_AL, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropADC_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_ADD_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_ADD(ir, IREG_AX, IREG_AX, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropADC_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + fetchdat = fastreadl(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + uop_ADD_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + uop_ADD(ir, IREG_EAX, IREG_EAX, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropADC_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp2_B, IREG_temp0_B, IREG_8(src_reg)); + uop_ADD(ir, IREG_temp2_B, IREG_temp2_B, IREG_temp1_B); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp2_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp2_W, IREG_temp0_W, IREG_16(src_reg)); + uop_ADD(ir, IREG_temp2_W, IREG_temp2_W, IREG_temp1_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp2_W); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_flags_op2, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_flags_op2); + } + + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADC_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp2, IREG_temp0, IREG_32(src_reg)); + uop_ADD(ir, IREG_temp2, IREG_temp2, IREG_temp1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_temp2); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropADD_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_ADD_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropADD_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_ADD_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropADD_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_ADD(ir, IREG_EAX, IREG_EAX, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + uop_ADD_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + codegen_mark_code_present(block, cs+op_pc, 4); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + codegen_flags_changed = 1; + return op_pc + 4; +} +uint32_t ropADD_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp1_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp1_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_flags_op2, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_flags_op2); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropADD_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ADD(ir, IREG_temp1, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropCMP_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_SUB_IMM(ir, IREG_flags_res_B, IREG_AL, imm_data); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropCMP_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_AX, imm_data); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropCMP_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + fetchdat = fastreadl(cs + op_pc); + + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + uop_SUB_IMM(ir, IREG_flags_res, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropCMP_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_SUB(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_flags_res_B, IREG_temp0_B, IREG_8(src_reg)); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_SUB(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_flags_res_W, IREG_temp0_W, IREG_16(src_reg)); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_flags_res, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + uop_SUB(ir, IREG_flags_res, IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropCMP_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_flags_res, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_flags_res, IREG_temp0, IREG_32(src_reg)); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropSBB_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_SUB_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_SUB(ir, IREG_AL, IREG_AL, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropSBB_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_SUB_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_SUB(ir, IREG_AX, IREG_AX, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropSBB_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + fetchdat = fastreadl(cs + op_pc); + + get_cf(ir, IREG_temp0); + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + uop_SUB_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + uop_SUB(ir, IREG_EAX, IREG_EAX, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropSBB_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp2_B, IREG_temp0_B, IREG_8(src_reg)); + uop_SUB(ir, IREG_temp2_B, IREG_temp2_B, IREG_temp1_B); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp2_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp2_W, IREG_temp0_W, IREG_16(src_reg)); + uop_SUB(ir, IREG_temp2_W, IREG_temp2_W, IREG_temp1_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp2_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_flags_op2, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_flags_op2); + } + + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSBB_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + get_cf(ir, IREG_temp1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp2, IREG_temp0, IREG_32(src_reg)); + uop_SUB(ir, IREG_temp2, IREG_temp2, IREG_temp1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp2); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_temp2); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropSUB_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AL); + uop_SUB_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropSUB_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_MOVZX(ir, IREG_flags_op1, IREG_AX); + uop_SUB_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op2, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropSUB_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV(ir, IREG_flags_op1, IREG_EAX); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_SUB(ir, IREG_EAX, IREG_EAX, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_SUB_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + uop_MOV_IMM(ir, IREG_flags_op2, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + return op_pc + 4; +} +uint32_t ropSUB_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp1_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp1_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_flags_op2, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_flags_op2); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropSUB_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_SUB(ir, IREG_temp1, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t rop80(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int skip_immediate = 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint8_t imm = fastreadb(cs + op_pc + 1); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_8(block, ir, IREG_temp0_B, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_ADD_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + else + uop_OR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_ADD_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_ADD(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_SUB_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + else + uop_AND_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_SUB_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + else + uop_XOR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + } + else + { + uop_SUB_IMM(ir, IREG_flags_res_B, IREG_8(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint8_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadb(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_ADD_IMM(ir, IREG_temp1_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_temp0_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp2); + uop_ADD_IMM(ir, IREG_temp1_B, IREG_temp0_B, imm); + uop_ADD(ir, IREG_temp1_B, IREG_temp1_B, IREG_temp2_B); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp2); + uop_SUB_IMM(ir, IREG_temp1_B, IREG_temp0_B, imm); + uop_SUB(ir, IREG_temp1_B, IREG_temp1_B, IREG_temp2_B); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_temp0_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + break; + + case 0x28: /*SUB*/ + uop_SUB_IMM(ir, IREG_temp1_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_temp0_B, IREG_temp0_B, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res_B, IREG_temp0_B, imm); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + if (!skip_immediate) + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t rop81_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int skip_immediate = 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint16_t imm = fastreadw(cs + op_pc + 1); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_16(block, ir, IREG_temp0_W, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_ADD_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + else + uop_OR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_ADD_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_SUB_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + else + uop_AND_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_SUB_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + else + uop_XOR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + } + else + { + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint16_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadw(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_16(block, ir, IREG_temp2_W, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_ADD(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2_W); + else + uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2_W); + else + uop_OR_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp3); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_ADD(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2_W); + else + uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_ADD(ir, IREG_temp1_W, IREG_temp1_W, IREG_temp3_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp3); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_SUB(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2_W); + else + uop_SUB_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_SUB(ir, IREG_temp1_W, IREG_temp1_W, IREG_temp3_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2_W); + else + uop_AND_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x28: /*SUB*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_SUB(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2_W); + else + uop_SUB_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2_W); + else + uop_XOR_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_MOVZX(ir, IREG_flags_op2, IREG_temp2_W); + uop_SUB(ir, IREG_flags_res_W, IREG_temp0_W, IREG_temp2_W); + } + else + { + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_temp0_W, imm); + } + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + if (!skip_immediate) + codegen_mark_code_present(block, cs+op_pc+1, 2); + return op_pc + 3; +} +uint32_t rop81_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int skip_immediate = 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint32_t imm = fastreadl(cs + op_pc + 1); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_ADD_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + else + uop_OR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_ADD_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_SUB_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + else + uop_AND_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_SUB_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + else + uop_XOR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_SUB(ir, IREG_flags_res, IREG_32(dest_reg), IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + } + else + { + uop_SUB_IMM(ir, IREG_flags_res, IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint32_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadl(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + skip_immediate = 1; + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp2, cs+op_pc+1); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_ADD(ir, IREG_temp1, IREG_temp0, IREG_temp2); + else + uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x08: /*OR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_OR(ir, IREG_temp0, IREG_temp0, IREG_temp2); + else + uop_OR_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp3); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_ADD(ir, IREG_temp1, IREG_temp0, IREG_temp2); + else + uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_ADD(ir, IREG_temp1, IREG_temp1, IREG_temp3); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp3); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_SUB(ir, IREG_temp1, IREG_temp0, IREG_temp2); + else + uop_SUB_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_SUB(ir, IREG_temp1, IREG_temp1, IREG_temp3); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x20: /*AND*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_AND(ir, IREG_temp0, IREG_temp0, IREG_temp2); + else + uop_AND_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x28: /*SUB*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_SUB(ir, IREG_temp1, IREG_temp0, IREG_temp2); + else + uop_SUB_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + else + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x30: /*XOR*/ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + uop_XOR(ir, IREG_temp0, IREG_temp0, IREG_temp2); + else + uop_XOR_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x38: /*CMP*/ + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_SUB(ir, IREG_flags_res, IREG_temp0, IREG_temp2); + } + else + { + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res, IREG_temp0, imm); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + if (!skip_immediate) + codegen_mark_code_present(block, cs+op_pc+1, 4); + return op_pc + 5; +} + +uint32_t rop83_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint16_t imm = (int16_t)(int8_t)fastreadb(cs + op_pc + 1); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_ADD_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_ADD_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_ADD(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SUB_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SUB_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_16(dest_reg), imm); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint16_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = (int16_t)(int8_t)fastreadb(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp2); + uop_ADD_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_ADD(ir, IREG_temp1_W, IREG_temp1_W, IREG_temp2_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp2); + uop_SUB_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_SUB(ir, IREG_temp1_W, IREG_temp1_W, IREG_temp2_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x28: /*SUB*/ + uop_SUB_IMM(ir, IREG_temp1_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_temp0_W, IREG_temp0_W, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + break; + + case 0x38: /*CMP*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res_W, IREG_temp0_W, imm); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uint32_t imm = (int32_t)(int8_t)fastreadb(cs + op_pc + 1); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_ADD_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_ADD_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_ADD(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SUB*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*CMP*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SUB_IMM(ir, IREG_flags_res, IREG_32(dest_reg), imm); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + uint32_t imm; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x38) == 0x38) /*CMP*/ + codegen_check_seg_read(block, ir, target_seg); + else + codegen_check_seg_write(block, ir, target_seg); + imm = (int32_t)(int8_t)fastreadb(cs + op_pc + 1); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADD32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x08: /*OR*/ + uop_OR_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x10: /*ADC*/ + get_cf(ir, IREG_temp2); + uop_ADD_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_ADD(ir, IREG_temp1, IREG_temp1, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ADC32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x18: /*SBB*/ + get_cf(ir, IREG_temp2); + uop_SUB_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_SUB(ir, IREG_temp1, IREG_temp1, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SBC32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x20: /*AND*/ + uop_AND_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x28: /*SUB*/ + uop_SUB_IMM(ir, IREG_temp1, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x30: /*XOR*/ + uop_XOR_IMM(ir, IREG_temp0, IREG_temp0, imm); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + break; + + case 0x38: /*CMP*/ + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_SUB_IMM(ir, IREG_flags_res, IREG_temp0, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} + +static void rebuild_c(ir_data_t *ir) +{ + int needs_rebuild = 1; + + if (codegen_flags_changed) + { + switch (cpu_state.flags_op) + { + case FLAGS_INC8: case FLAGS_INC16: case FLAGS_INC32: + case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: + needs_rebuild = 0; + break; + } + } + + if (needs_rebuild) + { + uop_CALL_FUNC(ir, flags_rebuild_c); + } +} + +uint32_t ropINC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + rebuild_c(ir); + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(opcode & 7)); + uop_ADD_IMM(ir, IREG_16(opcode & 7), IREG_16(opcode & 7), 1); + uop_MOVZX(ir, IREG_flags_res, IREG_16(opcode & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC16); + codegen_flags_changed = 1; + + return op_pc; +} +uint32_t ropINC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + rebuild_c(ir); + + uop_MOV(ir, IREG_flags_op1, IREG_32(opcode & 7)); + uop_ADD_IMM(ir, IREG_32(opcode & 7), IREG_32(opcode & 7), 1); + uop_MOV(ir, IREG_flags_res, IREG_32(opcode & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC32); + codegen_flags_changed = 1; + + return op_pc; +} + +uint32_t ropDEC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + rebuild_c(ir); + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(opcode & 7)); + uop_SUB_IMM(ir, IREG_16(opcode & 7), IREG_16(opcode & 7), 1); + uop_MOVZX(ir, IREG_flags_res, IREG_16(opcode & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC16); + codegen_flags_changed = 1; + + return op_pc; +} +uint32_t ropDEC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + rebuild_c(ir); + + uop_MOV(ir, IREG_flags_op1, IREG_32(opcode & 7)); + uop_SUB_IMM(ir, IREG_32(opcode & 7), IREG_32(opcode & 7), 1); + uop_MOV(ir, IREG_flags_res, IREG_32(opcode & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC32); + codegen_flags_changed = 1; + + return op_pc; +} + +uint32_t ropINCDEC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + codegen_mark_code_present(block, cs+op_pc, 1); + rebuild_c(ir); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op1, IREG_8(fetchdat & 7)); + if (fetchdat & 0x38) + { + uop_SUB_IMM(ir, IREG_8(fetchdat & 7), IREG_8(fetchdat & 7), 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC8); + } + else + { + uop_ADD_IMM(ir, IREG_8(fetchdat & 7), IREG_8(fetchdat & 7), 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC8); + } + uop_MOVZX(ir, IREG_flags_res, IREG_8(fetchdat & 7)); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + + if (fetchdat & 0x38) + { + uop_SUB_IMM(ir, IREG_temp1_B, IREG_temp0_B, 1); + } + else + { + uop_ADD_IMM(ir, IREG_temp1_B, IREG_temp0_B, 1); + } + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + if (fetchdat & 0x38) + { + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC8); + } + else + { + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC8); + } + } + + return op_pc+1; +} diff --git a/src/codegen_ops_arith.h b/src/codegen_ops_arith.h index 57c5e8e..1338102 100644 --- a/src/codegen_ops_arith.h +++ b/src/codegen_ops_arith.h @@ -1,1028 +1,64 @@ -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((uintptr_t)flags_rebuild_c); - - host_reg = LOAD_REG_W(opcode & 7); - - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_W(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); - STORE_REG_W_RELEASE(host_reg); - - codegen_flags_changed = 1; +uint32_t ropADC_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADC_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - 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; +uint32_t ropADD_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropADD_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - CALL_FUNC((uintptr_t)flags_rebuild_c); - - host_reg = LOAD_REG_L(opcode & 7); - - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); - STORE_REG_L_RELEASE(host_reg); +uint32_t ropCMP_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMP_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - codegen_flags_changed = 1; +uint32_t ropSBB_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSBB_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - 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((uintptr_t)flags_rebuild_c); +uint32_t ropSUB_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSUB_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - host_reg = LOAD_REG_W(opcode & 7); - - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_W(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC16); - STORE_HOST_REG_ADDR_WL((uintptr_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((uintptr_t)flags_rebuild_c); - - host_reg = LOAD_REG_L(opcode & 7); - - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC32); - STORE_HOST_REG_ADDR((uintptr_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; \ - x86seg *target_seg; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - { \ - dst_reg = LOAD_REG_B(fetchdat & 7); \ - } \ - else \ - { \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - SAVE_EA(); \ - MEM_CHECK_WRITE(target_seg); \ - dst_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); \ - } \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ - src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); \ - op ## _HOST_REG_B(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ - if (writeback) \ - { \ - if ((fetchdat & 0xc0) == 0xc0) \ - STORE_REG_B_RELEASE(dst_reg); \ - else \ - { \ - LOAD_EA(); \ - MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, 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; \ - x86seg *target_seg; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - { \ - dst_reg = LOAD_REG_W(fetchdat & 7); \ - } \ - else \ - { \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - SAVE_EA(); \ - MEM_CHECK_WRITE_W(target_seg); \ - dst_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); \ - } \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ - src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); \ - op ## _HOST_REG_W(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ - if (writeback) \ - { \ - if ((fetchdat & 0xc0) == 0xc0) \ - STORE_REG_W_RELEASE(dst_reg); \ - else \ - { \ - LOAD_EA(); \ - MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, 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; \ - x86seg *target_seg; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - { \ - dst_reg = LOAD_REG_L(fetchdat & 7); \ - } \ - else \ - { \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - SAVE_EA(); \ - MEM_CHECK_WRITE_L(target_seg); \ - dst_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); \ - } \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ - src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); \ - op ## _HOST_REG_L(dst_reg, src_reg); \ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ - if (writeback) \ - { \ - if ((fetchdat & 0xc0) == 0xc0) \ - STORE_REG_L_RELEASE(dst_reg); \ - else \ - { \ - LOAD_EA(); \ - MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, 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)&cpu_state.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_ ## op ## 8); \ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); \ - 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); \ - \ - 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)&cpu_state.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_ ## op ## 16); \ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); \ - 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); \ - \ - 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)&cpu_state.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_ ## op ## 32); \ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); \ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); \ - 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); \ - \ - 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)&cpu_state.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_SUB8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); - dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR_BL((uintptr_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)&cpu_state.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_SUB16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); - dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR_WL((uintptr_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)&cpu_state.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_SUB32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); - dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR((uintptr_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)&cpu_state.oldpc, op_old_pc); - MEM_LOAD_ADDR_EA_B(target_seg); - dst_reg = 0; - } - - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); - src_reg = LOAD_REG_B((fetchdat >> 3) & 7); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); - dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR_BL((uintptr_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)&cpu_state.oldpc, op_old_pc); - MEM_LOAD_ADDR_EA_W(target_seg); - dst_reg = 0; - } \ - - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - src_reg = LOAD_REG_W((fetchdat >> 3) & 7); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); - dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR_WL((uintptr_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)&cpu_state.oldpc, op_old_pc); - MEM_LOAD_ADDR_EA_L(target_seg); - dst_reg = 0; - } - - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - src_reg = LOAD_REG_L((fetchdat >> 3) & 7); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); - dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); - RELEASE_REG(dst_reg); - RELEASE_REG(src_reg); - - codegen_flags_changed = 1; - return op_pc + 1; -} +uint32_t rop80(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t rop81_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t rop81_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t rop83_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t rop83_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -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); +uint32_t ropDEC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropDEC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); - STORE_REG_B_RELEASE(host_reg); +uint32_t ropINC_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropINC_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - 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((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); - STORE_HOST_REG_ADDR_WL((uintptr_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((uintptr_t)&cpu_state.flags_op1, host_reg); - fetchdat = fastreadl(cs + op_pc); - ADD_HOST_REG_IMM(host_reg, fetchdat); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); - STORE_HOST_REG_ADDR((uintptr_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((uintptr_t)&cpu_state.flags_op1, host_reg); - host_reg = CMP_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); - STORE_HOST_REG_ADDR_BL((uintptr_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((uintptr_t)&cpu_state.flags_op1, host_reg); - host_reg = CMP_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - STORE_HOST_REG_ADDR_WL((uintptr_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((uintptr_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((uintptr_t)&cpu_state.flags_op2, fetchdat); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - STORE_HOST_REG_ADDR((uintptr_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((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); - STORE_HOST_REG_ADDR_BL((uintptr_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((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - STORE_HOST_REG_ADDR_WL((uintptr_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((uintptr_t)&cpu_state.flags_op1, host_reg); - fetchdat = fastreadl(cs + op_pc); - SUB_HOST_REG_IMM(host_reg, fetchdat); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - STORE_HOST_REG_ADDR((uintptr_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; - x86seg *target_seg = NULL; - - if ((fetchdat & 0x30) == 0x10) - return 0; - - if ((fetchdat & 0xc0) != 0xc0) - { - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - if ((fetchdat & 0x38) == 0x38) - { - MEM_LOAD_ADDR_EA_B(target_seg); - host_reg = 0; - } - else - { - SAVE_EA(); - MEM_CHECK_WRITE(target_seg); - host_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); - } - imm = fastreadb(cs + op_pc + 1); - } - else - { - host_reg = LOAD_REG_B(fetchdat & 7); - imm = (fetchdat >> 8) & 0xff; - } - - switch (fetchdat & 0x38) - { - case 0x00: /*ADD*/ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_B(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD8); - break; - case 0x08: /*OR*/ - OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); - break; - case 0x20: /*AND*/ - AND_HOST_REG_IMM(host_reg, imm | 0xffffff00); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); - break; - case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_B(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); - break; - case 0x30: /*XOR*/ - XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); - break; - case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); - host_reg = CMP_HOST_REG_IMM_B(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); - break; - } - - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0x38) != 0x38) - { - if ((fetchdat & 0xc0) != 0xc0) - { - LOAD_EA(); - MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, host_reg); - } - else - { - 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; - x86seg *target_seg = NULL; - - if ((fetchdat & 0x30) == 0x10) - return 0; - - if ((fetchdat & 0xc0) != 0xc0) - { - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - if ((fetchdat & 0x38) == 0x38) - { - MEM_LOAD_ADDR_EA_W(target_seg); - host_reg = 0; - } - else - { - SAVE_EA(); - MEM_CHECK_WRITE_W(target_seg); - host_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); - } - imm = fastreadw(cs + op_pc + 1); - } - else - { - host_reg = LOAD_REG_W(fetchdat & 7); - imm = (fetchdat >> 8) & 0xffff; - } - - switch (fetchdat & 0x38) - { - case 0x00: /*ADD*/ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); - break; - case 0x08: /*OR*/ - OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - break; - case 0x20: /*AND*/ - AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - break; - case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - break; - case 0x30: /*XOR*/ - XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - break; - case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - break; - } - - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0x38) != 0x38) - { - if ((fetchdat & 0xc0) != 0xc0) - { - LOAD_EA(); - MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); - } - else - { - 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; - x86seg *target_seg = NULL; - - if ((fetchdat & 0x30) == 0x10) - return 0; - - if ((fetchdat & 0xc0) != 0xc0) - { - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - if ((fetchdat & 0x38) == 0x38) - { - MEM_LOAD_ADDR_EA_L(target_seg); - host_reg = 0; - } - else - { - SAVE_EA(); - MEM_CHECK_WRITE(target_seg); - host_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); - } - } - else - { - host_reg = LOAD_REG_L(fetchdat & 7); - } - imm = fastreadl(cs + op_pc + 1); - - switch (fetchdat & 0x38) - { - case 0x00: /*ADD*/ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); - break; - case 0x08: /*OR*/ - OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - break; - case 0x20: /*AND*/ - AND_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - break; - case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - break; - case 0x30: /*XOR*/ - XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - break; - case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - break; - } - - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0x38) != 0x38) - { - if ((fetchdat & 0xc0) != 0xc0) - { - LOAD_EA(); - MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); - } - else - { - 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; - x86seg *target_seg = NULL; - - if ((fetchdat & 0x30) == 0x10) - return 0; - - if ((fetchdat & 0xc0) != 0xc0) - { - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - if ((fetchdat & 0x38) == 0x38) - { - MEM_LOAD_ADDR_EA_W(target_seg); - host_reg = 0; - } - else - { - SAVE_EA(); - MEM_CHECK_WRITE_W(target_seg); - host_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); - } - imm = fastreadb(cs + op_pc + 1); - } - else - { - 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((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); - break; - case 0x08: /*OR*/ - OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - break; - case 0x20: /*AND*/ - AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - break; - case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - break; - case 0x30: /*XOR*/ - XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); - break; - case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); - break; - } - - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0x38) != 0x38) - { - if ((fetchdat & 0xc0) != 0xc0) - { - LOAD_EA(); - MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); - } - else - { - 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; - x86seg *target_seg = NULL; - - if ((fetchdat & 0x30) == 0x10) - return 0; - - if ((fetchdat & 0xc0) != 0xc0) - { - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - if ((fetchdat & 0x38) == 0x38) - { - MEM_LOAD_ADDR_EA_L(target_seg); - host_reg = 0; - } - else - { - SAVE_EA(); - MEM_CHECK_WRITE_L(target_seg); - host_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); - } - imm = fastreadb(cs + op_pc + 1); - } - else - { - 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((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); - break; - case 0x08: /*OR*/ - OR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - break; - case 0x20: /*AND*/ - AND_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - break; - case 0x28: /*SUB*/ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - break; - case 0x30: /*XOR*/ - XOR_HOST_REG_IMM(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); - break; - case 0x38: /*CMP*/ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); - break; - } - - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0x38) != 0x38) - { - if ((fetchdat & 0xc0) != 0xc0) - { - LOAD_EA(); - MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); - } - else - { - STORE_REG_L_RELEASE(host_reg); - } - } - else - RELEASE_REG(host_reg); - - codegen_flags_changed = 1; - return op_pc + 2; -} +uint32_t ropINCDEC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_branch.c b/src/codegen_ops_branch.c new file mode 100644 index 0000000..ea9b986 --- /dev/null +++ b/src/codegen_ops_branch.c @@ -0,0 +1,1011 @@ +#include "ibm.h" + +#include "x86.h" +#include "386_common.h" +#include "x86_flags.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_mov.h" + +static int NF_SET_01() +{ + return NF_SET() ? 1 : 0; +} +static int VF_SET_01() +{ + return VF_SET() ? 1 : 0; +} + +static int ropJO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Overflow is always zero*/ + return 0; + + case FLAGS_SUB8: case FLAGS_DEC8: + jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + + case FLAGS_SUB16: case FLAGS_DEC16: + jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + + case FLAGS_SUB32: case FLAGS_DEC32: + jump_uop = uop_CMP_JNO_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, VF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; +} +static int ropJNO_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Overflow is always zero*/ + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + return 0; + + case FLAGS_SUB8: case FLAGS_DEC8: + jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + + case FLAGS_SUB16: case FLAGS_DEC16: + jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + + case FLAGS_SUB32: case FLAGS_DEC32: + jump_uop = uop_CMP_JO_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, VF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; +} + +static int ropJB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = (CF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Carry is always zero*/ + return 0; + + case FLAGS_SUB8: + if (do_unroll) + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + + case FLAGS_SUB16: + if (do_unroll) + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + + case FLAGS_SUB32: + if (do_unroll) + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + if (do_unroll) + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + else + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} +static int ropJNB_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = (!CF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Carry is always zero*/ + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + return 0; + + case FLAGS_SUB8: + if (do_unroll) + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + + case FLAGS_SUB16: + if (do_unroll) + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + + case FLAGS_SUB32: + if (do_unroll) + jump_uop = uop_CMP_JNB_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JB_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + if (do_unroll) + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + else + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} + +static int ropJE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + if (ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)) + { + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 1; + } + else + { + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + } + return 0; +} +int ropJNE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + if (!ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)) + { + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 1; + } + else + { + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + } + return 0; +} + +static int ropJBE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop, jump_uop2 = -1; + int do_unroll = ((CF_SET() || ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Carry is always zero, so test zero only*/ + if (do_unroll) + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + else + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + break; + + case FLAGS_SUB8: + if (do_unroll) + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: + if (do_unroll) + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: + if (do_unroll) + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + if (do_unroll) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + else + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + break; + } + if (do_unroll) + { + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + return 1; + } + else + { + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; + } +} +static int ropJNBE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop, jump_uop2 = -1; + int do_unroll = ((!CF_SET() && !ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: case FLAGS_ZN16: case FLAGS_ZN32: + /*Carry is always zero, so test zero only*/ + if (do_unroll) + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + else + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + break; + + case FLAGS_SUB8: + if (do_unroll) + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: + if (do_unroll) + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: + if (do_unroll) + jump_uop = uop_CMP_JNBE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JBE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + if (do_unroll) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + else + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, CF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + break; + } + if (do_unroll) + { + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 1; + } + else + { + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + return 0; + } +} + +static int ropJS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = (NF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + 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: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B); + 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: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W); + 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: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET); + if (do_unroll) + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + else + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} +static int ropJNS_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = (!NF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + 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: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B); + 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: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W); + 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: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET); + if (do_unroll) + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + else + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + break; + } + uop_MOV_IMM(ir, IREG_pc, do_unroll ? next_pc : dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} + +static int ropJP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + uop_CALL_FUNC_RESULT(ir, IREG_temp0, PF_SET); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; +} +static int ropJNP_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + + uop_CALL_FUNC_RESULT(ir, IREG_temp0, PF_SET); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; +} + +static int ropJL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = ((NF_SET() ? 1 : 0) != (VF_SET() ? 1 : 0) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + /*V flag is always clear. Condition is true if N is set*/ + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B); + break; + case FLAGS_ZN16: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W); + break; + case FLAGS_ZN32: + if (do_unroll) + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res); + else + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res); + break; + + case FLAGS_SUB8: case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + if (do_unroll) + jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1); + else + jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1); + break; + } + if (do_unroll) + uop_MOV_IMM(ir, IREG_pc, next_pc); + else + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} +static int ropJNL_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop; + int do_unroll = ((NF_SET() ? 1 : 0) == (VF_SET() ? 1 : 0) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + /*V flag is always clear. Condition is true if N is set*/ + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_B); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_B); + break; + case FLAGS_ZN16: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res_W); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res_W); + break; + case FLAGS_ZN32: + if (do_unroll) + jump_uop = uop_TEST_JNS_DEST(ir, IREG_flags_res); + else + jump_uop = uop_TEST_JS_DEST(ir, IREG_flags_res); + break; + + case FLAGS_SUB8: case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_CMP_JNL_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JL_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + if (do_unroll) + jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1); + else + jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1); + break; + } + if (do_unroll) + uop_MOV_IMM(ir, IREG_pc, next_pc); + else + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return do_unroll ? 1 : 0; +} + +static int ropJLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop, jump_uop2 = -1; + int do_unroll = (((NF_SET() ? 1 : 0) != (VF_SET() ? 1 : 0) || ZF_SET()) && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + if (do_unroll) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1); + } + else + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1); + } + break; + } + if (do_unroll) + { + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + return 1; + } + else + { + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 0; + } +} +static int ropJNLE_common(codeblock_t *block, ir_data_t *ir, uint32_t dest_addr, uint32_t next_pc) +{ + int jump_uop, jump_uop2 = -1; + int do_unroll = ((NF_SET() ? 1 : 0) == (VF_SET() ? 1 : 0) && !ZF_SET() && codegen_can_unroll(block, ir, next_pc, dest_addr)); + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: case FLAGS_DEC8: + if (do_unroll) + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + else + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_B, IREG_flags_op2_B); + break; + case FLAGS_SUB16: case FLAGS_DEC16: + if (do_unroll) + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + else + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1_W, IREG_flags_op2_W); + break; + case FLAGS_SUB32: case FLAGS_DEC32: + if (do_unroll) + jump_uop = uop_CMP_JNLE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + else + jump_uop = uop_CMP_JLE_DEST(ir, IREG_flags_op1, IREG_flags_op2); + break; + + case FLAGS_UNKNOWN: + default: + if (do_unroll) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + jump_uop = uop_CMP_JZ_DEST(ir, IREG_temp0, IREG_temp1); + } + else + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + uop_CALL_FUNC_RESULT(ir, IREG_temp0, NF_SET_01); + uop_CALL_FUNC_RESULT(ir, IREG_temp1, VF_SET_01); + jump_uop = uop_CMP_JNZ_DEST(ir, IREG_temp0, IREG_temp1); + } + break; + } + if (do_unroll) + { + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + uop_MOV_IMM(ir, IREG_pc, next_pc); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + return 1; + } + else + { + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + if (jump_uop2 != -1) + uop_set_jump_dest(ir, jump_uop2); + return 0; + } +} + +#define ropJ(cond) \ +uint32_t ropJ ## cond ## _8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); \ + uint32_t dest_addr = op_pc + 1 + offset; \ + int ret; \ + \ + if (!(op_32 & 0x100)) \ + dest_addr &= 0xffff; \ + ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+1); \ + \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + return ret ? dest_addr : (op_pc+1); \ +} \ +uint32_t ropJ ## cond ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uint32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); \ + uint32_t dest_addr = (op_pc + 2 + offset) & 0xffff; \ + int ret; \ + \ + ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+2); \ + \ + codegen_mark_code_present(block, cs+op_pc, 2); \ + return ret ? dest_addr : (op_pc+2); \ +} \ +uint32_t ropJ ## cond ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uint32_t offset = fastreadl(cs + op_pc); \ + uint32_t dest_addr = op_pc + 4 + offset; \ + int ret; \ + \ + ret = ropJ ## cond ## _common(block, ir, dest_addr, op_pc+4); \ + \ + codegen_mark_code_present(block, cs+op_pc, 4); \ + return ret ? dest_addr : (op_pc+4); \ +} + +ropJ(O) +ropJ(NO) +ropJ(B) +ropJ(NB) +ropJ(E) +ropJ(NE) +ropJ(BE) +ropJ(NBE) +ropJ(S) +ropJ(NS) +ropJ(P) +ropJ(NP) +ropJ(L) +ropJ(NL) +ropJ(LE) +ropJ(NLE) + + +uint32_t ropJCXZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc + 1 + offset; + int jump_uop; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (op_32 & 0x200) + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_ECX, 0); + else + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_CX, 0); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc+1; +} + +uint32_t ropLOOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc + 1 + offset; + uint32_t ret_addr; + int jump_uop; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (((op_32 & 0x200) ? ECX : CX) != 1 && codegen_can_unroll(block, ir, op_pc+1, dest_addr)) + { + if (op_32 & 0x200) + { + uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_ECX, 0); + } + else + { + uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1); + jump_uop = uop_CMP_IMM_JNZ_DEST(ir, IREG_CX, 0); + } + uop_MOV_IMM(ir, IREG_pc, op_pc+1); + ret_addr = dest_addr; + CPU_BLOCK_END(); + } + else + { + if (op_32 & 0x200) + { + uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_ECX, 0); + } + else + { + uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_CX, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + ret_addr = op_pc+1; + } + uop_JMP(ir, codegen_exit_rout); + uop_set_jump_dest(ir, jump_uop); + + codegen_mark_code_present(block, cs+op_pc, 1); + return ret_addr; +} + +uint32_t ropLOOPE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc + 1 + offset; + int jump_uop, jump_uop2; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (op_32 & 0x200) + { + uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_ECX, 0); + } + else + { + uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_CX, 0); + } + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_NOP_BARRIER(ir); + uop_set_jump_dest(ir, jump_uop); + uop_set_jump_dest(ir, jump_uop2); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc+1; +} +uint32_t ropLOOPNE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc + 1 + offset; + int jump_uop, jump_uop2; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (op_32 & 0x200) + { + uop_SUB_IMM(ir, IREG_ECX, IREG_ECX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_ECX, 0); + } + else + { + uop_SUB_IMM(ir, IREG_CX, IREG_CX, 1); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_CX, 0); + } + if (!codegen_flags_changed || !flags_res_valid()) + { + uop_CALL_FUNC_RESULT(ir, IREG_temp0, ZF_SET); + jump_uop2 = uop_CMP_IMM_JNZ_DEST(ir, IREG_temp0, 0); + } + else + { + jump_uop2 = uop_CMP_IMM_JZ_DEST(ir, IREG_flags_res, 0); + } + uop_MOV_IMM(ir, IREG_pc, dest_addr); + uop_JMP(ir, codegen_exit_rout); + uop_NOP_BARRIER(ir); + uop_set_jump_dest(ir, jump_uop); + uop_set_jump_dest(ir, jump_uop2); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc+1; +} diff --git a/src/codegen_ops_branch.h b/src/codegen_ops_branch.h new file mode 100644 index 0000000..a67a2b5 --- /dev/null +++ b/src/codegen_ops_branch.h @@ -0,0 +1,69 @@ +uint32_t ropJB_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJB_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJB_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNB_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNB_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNB_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJBE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJBE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJBE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNBE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNBE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNBE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJL_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJL_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJL_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNL_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNL_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNL_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJLE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJLE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJLE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNLE_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNLE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNLE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJO_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJO_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJO_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNO_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNO_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNO_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJP_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJP_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJP_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNP_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNP_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNP_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJS_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJNS_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJNS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropJCXZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropLOOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLOOPE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLOOPNE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_fpu.h b/src/codegen_ops_fpu.h deleted file mode 100644 index de7cf4c..0000000 --- a/src/codegen_ops_fpu.h +++ /dev/null @@ -1,638 +0,0 @@ -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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.oldpc, op_old_pc); - - CHECK_SEG_READ(target_seg); - MEM_LOAD_ADDR_EA_Q(target_seg); - - FP_LOAD_IQ(); - - codegen_fpu_loaded_iq[(cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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 ropFCOMPP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - FP_ENTER(); - FP_COMPARE_REG(0, 1); - FP_POP2(); - - 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((uintptr_t)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.npxc, 0); - UPDATE_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)&cpu_state.npxc); - MEM_STORE_ADDR_EA_W(target_seg, host_reg); - - return op_pc + 1; -} - - -static uint32_t ropFCHS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - FP_ENTER(); - FP_FCHS(); - - return op_pc; -} - -#define opFLDimm(name, v) \ - static uint32_t ropFLD ## name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ - { \ - static double fp_imm = v; \ - \ - FP_ENTER(); \ - FP_LOAD_IMM_Q(*(uint64_t *)&fp_imm); \ - \ - return op_pc; \ - } - -opFLDimm(1, 1.0) -opFLDimm(L2T, 3.3219280948873623) -opFLDimm(L2E, 1.4426950408889634); -opFLDimm(PI, 3.141592653589793); -opFLDimm(EG2, 0.3010299956639812); -opFLDimm(LN2, 0.693147180559945); -opFLDimm(Z, 0.0) diff --git a/src/codegen_ops_fpu_arith.c b/src/codegen_ops_fpu_arith.c new file mode 100644 index 0000000..e3bfb28 --- /dev/null +++ b/src/codegen_ops_fpu_arith.c @@ -0,0 +1,572 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_arith.h" +#include "codegen_ops_helpers.h" + +uint32_t ropFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFADDr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FADD(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFADDP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FADD(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + + return op_pc; +} +uint32_t ropFCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + fpu_POP(block, ir); + + return op_pc; +} +uint32_t ropFCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + fpu_POP2(block, ir); + + return op_pc; +} + +uint32_t ropFDIV(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(0), IREG_ST(src_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFDIVP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} +uint32_t ropFDIVRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FDIV(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFMULr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FMUL(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFMULP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FMUL(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_ST(src_reg)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(0), IREG_ST(src_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + + return op_pc; +} +uint32_t ropFSUBP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} +uint32_t ropFSUBRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FSUB(ir, IREG_ST(dest_reg), IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV_IMM(ir, IREG_tag(dest_reg), TAG_VALID); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFUCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + + return op_pc; +} +uint32_t ropFUCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(src_reg)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + fpu_POP(block, ir); + + return op_pc; +} +uint32_t ropFUCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FCOM(ir, IREG_temp0_W, IREG_ST(0), IREG_ST(1)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + fpu_POP2(block, ir); + + return op_pc; +} + +#define ropF_arith_mem(name, load_uop) \ +uint32_t ropFADD ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + if ((cpu_state.npxc >> 10) & 3) \ + return 0; \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFCOM ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFCOMP ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + fpu_POP(block, ir); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFDIV ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFDIVR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFMUL ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFSUB ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFSUBR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + load_uop(ir, IREG_temp0_D, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} + +ropF_arith_mem(s, uop_MEM_LOAD_SINGLE) +ropF_arith_mem(d, uop_MEM_LOAD_DOUBLE) + +#define ropFI_arith_mem(name, temp_reg) \ +uint32_t ropFIADD ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FADD(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFICOM ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFICOMP ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FCOM(ir, IREG_temp1_W, IREG_ST(0), IREG_temp0_D); \ + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); \ + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp1_W); \ + fpu_POP(block, ir); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFIDIV ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FDIV(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFIDIVR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)\ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FDIV(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFIMUL ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FMUL(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFISUB ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FSUB(ir, IREG_ST(0), IREG_ST(0), IREG_temp0_D); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} \ +uint32_t ropFISUBR ## name(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc)\ +{ \ + x86seg *target_seg; \ + \ + uop_FP_ENTER(ir); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + op_pc--; \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, temp_reg, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MOV_DOUBLE_INT(ir, IREG_temp0_D, temp_reg); \ + uop_FSUB(ir, IREG_ST(0), IREG_temp0_D, IREG_ST(0)); \ + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); \ + \ + return op_pc+1; \ +} + +ropFI_arith_mem(l, IREG_temp0) +ropFI_arith_mem(w, IREG_temp0_W) + + +uint32_t ropFABS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FABS(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} + +uint32_t ropFCHS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FCHS(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FSQRT(ir, IREG_ST(0), IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_VALID); + + return op_pc; +} +uint32_t ropFTST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_FTST(ir, IREG_temp0_W, IREG_ST(0)); + uop_AND_IMM(ir, IREG_NPXS, IREG_NPXS, ~(C0|C2|C3)); + uop_OR(ir, IREG_NPXS, IREG_NPXS, IREG_temp0_W); + + return op_pc; +} diff --git a/src/codegen_ops_fpu_arith.h b/src/codegen_ops_fpu_arith.h new file mode 100644 index 0000000..60ae273 --- /dev/null +++ b/src/codegen_ops_fpu_arith.h @@ -0,0 +1,63 @@ +uint32_t ropFADD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFADDr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFADDP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIV(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMUL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRr(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFUCOM(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFUCOMP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFUCOMPP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFADDs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFADDd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMPs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCOMPd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFDIVRd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFMULd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSUBRd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFIADDl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIADDw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFICOMl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFICOMw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFICOMPl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFICOMPw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIDIVl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIDIVw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIDIVRl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIDIVRw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIMULl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFIMULw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISUBl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISUBw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISUBRl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISUBRw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFABS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFCHS(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSQRT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFTST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_fpu_constant.c b/src/codegen_ops_fpu_constant.c new file mode 100644 index 0000000..aa264ce --- /dev/null +++ b/src/codegen_ops_fpu_constant.c @@ -0,0 +1,33 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_constant.h" +#include "codegen_ops_helpers.h" + +uint32_t ropFLD1(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_temp0, 1); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc; +} +uint32_t ropFLDZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_temp0, 0); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc; +} diff --git a/src/codegen_ops_fpu_constant.h b/src/codegen_ops_fpu_constant.h new file mode 100644 index 0000000..29384b5 --- /dev/null +++ b/src/codegen_ops_fpu_constant.h @@ -0,0 +1,2 @@ +uint32_t ropFLD1(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFLDZ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_fpu_loadstore.c b/src/codegen_ops_fpu_loadstore.c new file mode 100644 index 0000000..e61e5cb --- /dev/null +++ b/src/codegen_ops_fpu_loadstore.c @@ -0,0 +1,231 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_arith.h" +#include "codegen_ops_helpers.h" + +uint32_t ropFLDs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_SINGLE(ir, IREG_ST(-1), ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc+1; +} +uint32_t ropFLDd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_DOUBLE(ir, IREG_ST(-1), ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc+1; +} + +uint32_t ropFSTs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_SINGLE(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_ST(0)); + + return op_pc+1; +} +uint32_t ropFSTPs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_SINGLE(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} +uint32_t ropFSTd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 7); + uop_MEM_STORE_DOUBLE(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_ST(0)); + + return op_pc+1; +} +uint32_t ropFSTPd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 7); + uop_MEM_STORE_DOUBLE(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_ST(0)); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} + + +uint32_t ropFILDw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0_W); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc+1; +} +uint32_t ropFILDl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID); + fpu_PUSH(block, ir); + + return op_pc+1; +} +uint32_t ropFILDq(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_ST_i64(-1), ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOV_DOUBLE_INT(ir, IREG_ST(-1), IREG_ST_i64(-1)); + uop_MOV_IMM(ir, IREG_tag(-1), TAG_VALID | TAG_UINT64); + fpu_PUSH(block, ir); + + return op_pc+1; +} + +uint32_t ropFISTw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE(ir, IREG_temp0_W, IREG_ST(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + + return op_pc+1; +} +uint32_t ropFISTPw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE(ir, IREG_temp0_W, IREG_ST(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} +uint32_t ropFISTl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE(ir, IREG_temp0, IREG_ST(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + + return op_pc+1; +} +uint32_t ropFISTPl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE(ir, IREG_temp0, IREG_ST(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} +uint32_t ropFISTPq(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MOV_INT_DOUBLE_64(ir, IREG_temp0_Q, IREG_ST(0), IREG_ST_i64(0), IREG_tag(0)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_Q); + uop_MOV_IMM(ir, IREG_tag(0), TAG_EMPTY); + fpu_POP(block, ir); + + return op_pc+1; +} diff --git a/src/codegen_ops_fpu_loadstore.h b/src/codegen_ops_fpu_loadstore.h new file mode 100644 index 0000000..b206f96 --- /dev/null +++ b/src/codegen_ops_fpu_loadstore.h @@ -0,0 +1,17 @@ +uint32_t ropFLDs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFLDd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFSTs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTPs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTPd(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFILDw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFILDl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFILDq(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFISTw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISTPw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISTl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISTPl(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFISTPq(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_fpu_misc.c b/src/codegen_ops_fpu_misc.c new file mode 100644 index 0000000..2848ba9 --- /dev/null +++ b/src/codegen_ops_fpu_misc.c @@ -0,0 +1,111 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_fpu_misc.h" +#include "codegen_ops_helpers.h" + +uint32_t ropFFREE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_tag(dest_reg), TAG_EMPTY); + + return op_pc; +} + +uint32_t ropFLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_ST(-1), IREG_ST(src_reg)); + uop_MOV(ir, IREG_ST_i64(-1), IREG_ST_i64(src_reg)); + uop_MOV(ir, IREG_tag(-1), IREG_tag(src_reg)); + fpu_PUSH(block, ir); + + return op_pc; +} + +uint32_t ropFST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV(ir, IREG_ST_i64(dest_reg), IREG_ST_i64(0)); + uop_MOV(ir, IREG_tag(dest_reg), IREG_tag(0)); + + return op_pc; +} +uint32_t ropFSTP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_ST(dest_reg), IREG_ST(0)); + uop_MOV(ir, IREG_ST_i64(dest_reg), IREG_ST_i64(0)); + uop_MOV(ir, IREG_tag(dest_reg), IREG_tag(0)); + fpu_POP(block, ir); + + return op_pc; +} + +uint32_t ropFSTCW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_NPXC); + + return op_pc+1; +} +uint32_t ropFSTSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + + uop_FP_ENTER(ir); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + op_pc--; + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_NPXS); + + return op_pc+1; +} +uint32_t ropFSTSW_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_AX, IREG_NPXS); + + return op_pc; +} + +uint32_t ropFXCH(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = fetchdat & 7; + + uop_FP_ENTER(ir); + uop_MOV(ir, IREG_temp0_D, IREG_ST(0)); + uop_MOV(ir, IREG_temp1_Q, IREG_ST_i64(0)); + uop_MOV(ir, IREG_temp2, IREG_tag(0)); + uop_MOV(ir, IREG_ST(0), IREG_ST(dest_reg)); + uop_MOV(ir, IREG_ST_i64(0), IREG_ST_i64(dest_reg)); + uop_MOV(ir, IREG_tag(0), IREG_tag(dest_reg)); + uop_MOV(ir, IREG_ST(dest_reg), IREG_temp0_D); + uop_MOV(ir, IREG_ST_i64(dest_reg), IREG_temp1_Q); + uop_MOV(ir, IREG_tag(dest_reg), IREG_temp2); + + return op_pc; +} diff --git a/src/codegen_ops_fpu_misc.h b/src/codegen_ops_fpu_misc.h new file mode 100644 index 0000000..257aa7a --- /dev/null +++ b/src/codegen_ops_fpu_misc.h @@ -0,0 +1,12 @@ +uint32_t ropFFREE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFST(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFSTCW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFSTSW_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropFXCH(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_helpers.c b/src/codegen_ops_helpers.c new file mode 100644 index 0000000..896ac29 --- /dev/null +++ b/src/codegen_ops_helpers.c @@ -0,0 +1,72 @@ +#include "ibm.h" +#include "x86.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ir_defs.h" +#include "codegen_reg.h" +#include "codegen_ops_helpers.h" + +void LOAD_IMMEDIATE_FROM_RAM_16_unaligned(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + /*Word access that crosses two pages. Perform reads from both pages, shift and combine*/ + uop_MOVZX_REG_PTR_8(ir, IREG_temp3_W, get_ram_ptr(addr)); + uop_MOVZX_REG_PTR_8(ir, dest_reg, get_ram_ptr(addr+1)); + uop_SHL_IMM(ir, IREG_temp3_W, IREG_temp3_W, 8); + uop_OR(ir, dest_reg, dest_reg, IREG_temp3_W); +} + +void LOAD_IMMEDIATE_FROM_RAM_32_unaligned(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + /*Dword access that crosses two pages. Perform reads from both pages, shift and combine*/ + uop_MOV_REG_PTR(ir, dest_reg, get_ram_ptr(addr & ~3)); + uop_MOV_REG_PTR(ir, IREG_temp3, get_ram_ptr((addr + 4) & ~3)); + uop_SHR_IMM(ir, dest_reg, dest_reg, (addr & 3) * 8); + uop_SHL_IMM(ir, IREG_temp3, IREG_temp3, (4 - (addr & 3)) * 8); + uop_OR(ir, dest_reg, dest_reg, IREG_temp3); +} + +#define UNROLL_MAX_REG_REFERENCES 200 +#define UNROLL_MAX_UOPS 1000 +#define UNROLL_MAX_COUNT 10 +int codegen_can_unroll_full(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr) +{ + int start; + int max_unroll; + int first_instruction; + int TOP = -1; + + /*Check that dest instruction was actually compiled into block*/ + start = codegen_get_instruction_uop(block, dest_addr, &first_instruction, &TOP); + + /*Couldn't find any uOPs corresponding to the destination instruction*/ + if (start == -1) + { + /*Is instruction jumping to itself?*/ + if (dest_addr != cpu_state.oldpc) + { +// pclog("Couldn't find start. start_pc=%08x end_pc=%08x dest_pc=%08x wr_pos=%i loop_size=%i\n", block->pc-cs, next_pc, dest_addr, ir->wr_pos, ir->wr_pos-start); + return 0; + } + else + { + start = ir->wr_pos; + TOP = cpu_state.TOP; + } + } + + if (TOP != cpu_state.TOP) + return 0; + + max_unroll = UNROLL_MAX_UOPS / ((ir->wr_pos-start)+6); + if (max_unroll > (UNROLL_MAX_REG_REFERENCES / max_version_refcount)) + max_unroll = (UNROLL_MAX_REG_REFERENCES / max_version_refcount); + if (max_unroll > UNROLL_MAX_COUNT) + max_unroll = UNROLL_MAX_COUNT; + if (max_unroll <= 1) + return 0; + + codegen_ir_set_unroll(max_unroll, start, first_instruction); + + return 1; +} diff --git a/src/codegen_ops_helpers.h b/src/codegen_ops_helpers.h new file mode 100644 index 0000000..ae3e5ed --- /dev/null +++ b/src/codegen_ops_helpers.h @@ -0,0 +1,126 @@ +#include "386_common.h" +#include "codegen_backend.h" + +static inline int LOAD_SP_WITH_OFFSET(ir_data_t *ir, int offset) +{ + if (stack32) + { + if (offset) + { + uop_ADD_IMM(ir, IREG_eaaddr, IREG_ESP, offset); + return IREG_eaaddr; + } + else + return IREG_ESP; + } + else + { + if (offset) + { + uop_ADD_IMM(ir, IREG_eaaddr_W, IREG_SP, offset); + uop_MOVZX(ir, IREG_eaaddr, IREG_eaaddr_W); + return IREG_eaaddr; + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + return IREG_eaaddr; + } + } +} + +static inline int LOAD_SP(ir_data_t *ir) +{ + return LOAD_SP_WITH_OFFSET(ir, 0); +} + +static inline void ADD_SP(ir_data_t *ir, int offset) +{ + if (stack32) + uop_ADD_IMM(ir, IREG_ESP, IREG_ESP, offset); + else + uop_ADD_IMM(ir, IREG_SP, IREG_SP, offset); +} +static inline void SUB_SP(ir_data_t *ir, int offset) +{ + if (stack32) + uop_SUB_IMM(ir, IREG_ESP, IREG_ESP, offset); + else + uop_SUB_IMM(ir, IREG_SP, IREG_SP, offset); +} + +static inline void fpu_POP(codeblock_t *block, ir_data_t *ir) +{ + if (block->flags & CODEBLOCK_STATIC_TOP) + uop_MOV_IMM(ir, IREG_FPU_TOP, cpu_state.TOP + 1); + else + uop_ADD_IMM(ir, IREG_FPU_TOP, IREG_FPU_TOP, 1); +} +static inline void fpu_POP2(codeblock_t *block, ir_data_t *ir) +{ + if (block->flags & CODEBLOCK_STATIC_TOP) + uop_MOV_IMM(ir, IREG_FPU_TOP, cpu_state.TOP + 2); + else + uop_ADD_IMM(ir, IREG_FPU_TOP, IREG_FPU_TOP, 2); +} +static inline void fpu_PUSH(codeblock_t *block, ir_data_t *ir) +{ + if (block->flags & CODEBLOCK_STATIC_TOP) + uop_MOV_IMM(ir, IREG_FPU_TOP, cpu_state.TOP - 1); + else + uop_SUB_IMM(ir, IREG_FPU_TOP, IREG_FPU_TOP, 1); +} + +static inline void CHECK_SEG_LIMITS(codeblock_t *block, ir_data_t *ir, x86seg *seg, int addr_reg, int end_offset) +{ + if ((seg == &cpu_state.seg_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || + (seg == &cpu_state.seg_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + return; + + uop_CMP_JB(ir, addr_reg, ireg_seg_limit_low(seg), codegen_gpf_rout); + if (end_offset) + { + uop_ADD_IMM(ir, IREG_temp3, addr_reg, end_offset); + uop_CMP_JNBE(ir, IREG_temp3, ireg_seg_limit_high(seg), codegen_gpf_rout); + } + else + uop_CMP_JNBE(ir, addr_reg, ireg_seg_limit_high(seg), codegen_gpf_rout); +} + +static inline void LOAD_IMMEDIATE_FROM_RAM_8(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + uop_MOVZX_REG_PTR_8(ir, dest_reg, get_ram_ptr(addr)); +} + +void LOAD_IMMEDIATE_FROM_RAM_16_unaligned(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr); +static inline void LOAD_IMMEDIATE_FROM_RAM_16(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + if ((addr & 0xfff) == 0xfff) + LOAD_IMMEDIATE_FROM_RAM_16_unaligned(block, ir, dest_reg, addr); + else + uop_MOVZX_REG_PTR_16(ir, dest_reg, get_ram_ptr(addr)); +} + +void LOAD_IMMEDIATE_FROM_RAM_32_unaligned(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr); +static inline void LOAD_IMMEDIATE_FROM_RAM_32(codeblock_t *block, ir_data_t *ir, int dest_reg, uint32_t addr) +{ + if ((addr & 0xfff) >= 0xffd) + LOAD_IMMEDIATE_FROM_RAM_32_unaligned(block, ir, dest_reg, addr); + else + uop_MOV_REG_PTR(ir, dest_reg, get_ram_ptr(addr)); +} + +int codegen_can_unroll_full(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr); +static inline int codegen_can_unroll(codeblock_t *block, ir_data_t *ir, uint32_t next_pc, uint32_t dest_addr) +{ + if (block->flags & CODEBLOCK_BYTE_MASK) + return 0; + + /*Is dest within block?*/ + if (dest_addr > next_pc) + return 0; + if ((cs+dest_addr) < block->pc) + return 0; + + return codegen_can_unroll_full(block, ir, next_pc, dest_addr); +} diff --git a/src/codegen_ops_jump.c b/src/codegen_ops_jump.c new file mode 100644 index 0000000..5e4cda4 --- /dev/null +++ b/src/codegen_ops_jump.c @@ -0,0 +1,289 @@ +#include "ibm.h" + +#include "x86.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_mov.h" + +uint32_t ropJMP_r8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int8_t)fastreadb(cs + op_pc); + uint32_t dest_addr = op_pc+1+offset; + + if (!(op_32 & 0x100)) + dest_addr &= 0xffff; + + if (offset < 0) + codegen_can_unroll(block, ir, op_pc+1, dest_addr); + codegen_mark_code_present(block, cs+op_pc, 1); + return dest_addr; +} +uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); + uint32_t dest_addr = op_pc+2+offset; + + dest_addr &= 0xffff; + + if (offset < 0) + codegen_can_unroll(block, ir, op_pc+1, dest_addr); + codegen_mark_code_present(block, cs+op_pc, 2); + return dest_addr; +} +uint32_t ropJMP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = fastreadl(cs + op_pc); + uint32_t dest_addr = op_pc+4+offset; + + if (offset < 0) + codegen_can_unroll(block, ir, op_pc+1, dest_addr); + codegen_mark_code_present(block, cs+op_pc, 4); + return dest_addr; +} + +uint32_t ropJMP_far_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t new_pc = fastreadw(cs + op_pc); + uint16_t new_cs = fastreadw(cs + op_pc + 2); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + uop_MOV_IMM(ir, IREG_pc, new_pc); + uop_LOAD_FUNC_ARG_IMM(ir, 0, new_cs); + uop_LOAD_FUNC_ARG_IMM(ir, 1, op_pc + 4); + uop_CALL_FUNC(ir, loadcsjmp); + + codegen_mark_code_present(block, cs+op_pc, 4); + return -1; +} +uint32_t ropJMP_far_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t new_pc = fastreadl(cs + op_pc); + uint16_t new_cs = fastreadw(cs + op_pc + 4); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + uop_MOV_IMM(ir, IREG_pc, new_pc); + uop_LOAD_FUNC_ARG_IMM(ir, 0, new_cs); + uop_LOAD_FUNC_ARG_IMM(ir, 1, op_pc + 4); + uop_CALL_FUNC(ir, loadcsjmp); + + codegen_mark_code_present(block, cs+op_pc, 6); + return -1; +} + +uint32_t ropCALL_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = (int32_t)(int16_t)fastreadw(cs + op_pc); + uint16_t ret_addr = op_pc + 2; + uint16_t dest_addr = ret_addr + offset; + int sp_reg; + + dest_addr &= 0xffff; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_IMM_16(ir, IREG_SS_base, sp_reg, ret_addr); + SUB_SP(ir, 2); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} +uint32_t ropCALL_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t offset = fastreadl(cs + op_pc); + uint32_t ret_addr = op_pc + 4; + uint32_t dest_addr = ret_addr + offset; + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, ret_addr); + SUB_SP(ir, 4); + uop_MOV_IMM(ir, IREG_pc, dest_addr); + + codegen_mark_code_present(block, cs+op_pc, 4); + return -1; +} + +uint32_t ropRET_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + } + ADD_SP(ir, 2); + uop_MOVZX(ir, IREG_pc, IREG_temp0_W); + + return -1; +} +uint32_t ropRET_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_eaaddr); + } + ADD_SP(ir, 4); + + return -1; +} + +uint32_t ropRET_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t offset = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + } + ADD_SP(ir, 2+offset); + uop_MOVZX(ir, IREG_pc, IREG_temp0_W); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} +uint32_t ropRET_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t offset = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_pc, IREG_SS_base, IREG_eaaddr); + } + ADD_SP(ir, 4+offset); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} + +uint32_t ropRETF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) + return 0; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + { + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_ESP, 2); + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_eaaddr, 2); + } + uop_MOVZX(ir, IREG_pc, IREG_temp0_W); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_CALL_FUNC(ir, loadcs); + ADD_SP(ir, 4); + + return -1; +} +uint32_t ropRETF_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) + return 0; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + { + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_ESP); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_ESP, 4); + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_eaaddr); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_eaaddr, 4); + } + uop_MOV(ir, IREG_pc, IREG_temp0); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_CALL_FUNC(ir, loadcs); + ADD_SP(ir, 8); + + return -1; +} + +uint32_t ropRETF_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t offset; + + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) + return 0; + + offset = fastreadw(cs + op_pc); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + { + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_ESP, 2); + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_eaaddr, 2); + } + uop_MOVZX(ir, IREG_pc, IREG_temp0_W); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_CALL_FUNC(ir, loadcs); + ADD_SP(ir, 4+offset); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} +uint32_t ropRETF_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t offset; + + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) + return 0; + + offset = fastreadw(cs + op_pc); + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + { + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_ESP); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_ESP, 4); + } + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_eaaddr); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, IREG_SS_base, IREG_eaaddr, 4); + } + uop_MOV(ir, IREG_pc, IREG_temp0); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_CALL_FUNC(ir, loadcs); + ADD_SP(ir, 8+offset); + + codegen_mark_code_present(block, cs+op_pc, 2); + return -1; +} diff --git a/src/codegen_ops_jump.h b/src/codegen_ops_jump.h index d2271cf..db4c95c 100644 --- a/src/codegen_ops_jump.h +++ b/src/codegen_ops_jump.h @@ -1,270 +1,21 @@ -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; +uint32_t ropJMP_r8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJMP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJMP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - if (offset & 0x80) - offset |= 0xffffff00; +uint32_t ropJMP_far_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropJMP_far_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+1+offset); - - return -1; -} +uint32_t ropCALL_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCALL_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -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; +uint32_t ropRET_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropRET_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); - - return -1; -} +uint32_t ropRET_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropRET_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -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); +uint32_t ropRETF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropRETF_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t 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 void BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int not) -{ - CALL_FUNC((uintptr_t)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 void 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((uintptr_t)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 void BRANCH_COND_O(int pc_offset, uint32_t op_pc, uint32_t offset, int not) -{ - CALL_FUNC((uintptr_t)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 void BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int not) -{ - CALL_FUNC((uintptr_t)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 void 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((uintptr_t)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) +uint32_t ropRETF_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropRETF_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_logic.c b/src/codegen_ops_logic.c new file mode 100644 index 0000000..015031f --- /dev/null +++ b/src/codegen_ops_logic.c @@ -0,0 +1,804 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_logic.h" + +uint32_t ropAND_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_AND_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropAND_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_AND_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropAND_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_AND(ir, IREG_EAX, IREG_EAX, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_AND_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + return op_pc + 4; +} +uint32_t ropAND_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_AND(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_temp0_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_AND(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_temp0_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropAND_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_AND(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_temp0, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropOR_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_OR_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropOR_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_OR_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropOR_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_OR(ir, IREG_EAX, IREG_EAX, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_OR_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropOR_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_OR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_OR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_temp0_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_OR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_OR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_temp0_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_OR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, dest_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropOR_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_OR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_temp0, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropTEST_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_AND_IMM(ir, IREG_flags_res, IREG_EAX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropTEST_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_AND_IMM(ir, IREG_flags_res, IREG_EAX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropTEST_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_AND(ir, IREG_flags_res, IREG_EAX, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_AND_IMM(ir, IREG_flags_res, IREG_EAX, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropTEST_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_flags_res_B, IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropTEST_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_flags_res_W, IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropTEST_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_AND(ir, IREG_flags_res, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_flags_res, IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropXOR_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm_data = fastreadb(cs + op_pc); + + uop_XOR_IMM(ir, IREG_AL, IREG_AL, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_AL); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropXOR_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm_data = fastreadw(cs + op_pc); + + uop_XOR_IMM(ir, IREG_AX, IREG_AX, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_AX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropXOR_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_temp0, cs + op_pc); + uop_XOR(ir, IREG_EAX, IREG_EAX, IREG_temp0); + } + else + { + fetchdat = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + uop_XOR_IMM(ir, IREG_EAX, IREG_EAX, fetchdat); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, IREG_EAX); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} +uint32_t ropXOR_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_XOR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_XOR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_8(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_temp0_B, IREG_temp0_B, IREG_8(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_XOR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_XOR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_16(src_reg)); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_temp0_W, IREG_temp0_W, IREG_16(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + + uop_XOR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + uop_MOV(ir, IREG_flags_res, dest_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropXOR_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_XOR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_32(src_reg)); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_temp0, IREG_temp0, IREG_32(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + } + + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + return op_pc + 1; +} diff --git a/src/codegen_ops_logic.h b/src/codegen_ops_logic.h index ca57fca..d86fbb4 100644 --- a/src/codegen_ops_logic.h +++ b/src/codegen_ops_logic.h @@ -1,564 +1,36 @@ -#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; \ - x86seg *target_seg; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - { \ - dst_reg = LOAD_REG_B(fetchdat & 7); \ - } \ - else \ - { \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - SAVE_EA(); \ - MEM_CHECK_WRITE(target_seg); \ - dst_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); \ - } \ - 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) \ - { \ - if ((fetchdat & 0xc0) == 0xc0) \ - STORE_REG_B_RELEASE(dst_reg); \ - else \ - { \ - LOAD_EA(); \ - MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, 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; \ - x86seg *target_seg; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - { \ - dst_reg = LOAD_REG_W(fetchdat & 7); \ - } \ - else \ - { \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - SAVE_EA(); \ - MEM_CHECK_WRITE_W(target_seg); \ - dst_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); \ - } \ - 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) \ - { \ - if ((fetchdat & 0xc0) == 0xc0) \ - STORE_REG_W_RELEASE(dst_reg); \ - else \ - { \ - LOAD_EA(); \ - MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, 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; \ - x86seg *target_seg; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - { \ - dst_reg = LOAD_REG_L(fetchdat & 7); \ - } \ - else \ - { \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - SAVE_EA(); \ - MEM_CHECK_WRITE_L(target_seg); \ - dst_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); \ - } \ - 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) \ - { \ - if ((fetchdat & 0xc0) == 0xc0) \ - STORE_REG_L_RELEASE(dst_reg); \ - else \ - { \ - LOAD_EA(); \ - MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, 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)&cpu_state.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)&cpu_state.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)&cpu_state.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; \ - } +uint32_t ropAND_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropAND_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -ROP_LOGIC(AND, AND, 1) -ROP_LOGIC(OR, OR, 1) -ROP_LOGIC(XOR, XOR, 1) +uint32_t ropOR_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropOR_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -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; +uint32_t ropTEST_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropTEST_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - 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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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; -} +uint32_t ropXOR_AL_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_AX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_EAX_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_b_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_b_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_w_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_w_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_l_rm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXOR_l_rmw(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_misc.c b/src/codegen_ops_misc.c new file mode 100644 index 0000000..4eb5906 --- /dev/null +++ b/src/codegen_ops_misc.c @@ -0,0 +1,611 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_misc.h" + +uint32_t ropLEA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + uop_MOV(ir, IREG_16(dest_reg), IREG_eaaddr_W); + + return op_pc + 1; +} +uint32_t ropLEA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + uop_MOV(ir, IREG_32(dest_reg), IREG_eaaddr); + + return op_pc + 1; +} + +uint32_t ropF6(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint8_t imm_data; + int reg; + + if (fetchdat & 0x20) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + reg = IREG_8(fetchdat & 7); + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x30) == 0x10) /*NEG/NOT*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + reg = IREG_temp0_B; + } + + switch (fetchdat & 0x38) + { + case 0x00: case 0x08: /*TEST*/ + imm_data = fastreadb(cs + op_pc + 1); + + uop_AND_IMM(ir, IREG_flags_res_B, reg, imm_data); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN8); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc+2; + + case 0x10: /*NOT*/ + uop_XOR_IMM(ir, reg, reg, 0xff); + if ((fetchdat & 0xc0) != 0xc0) + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg); + + codegen_flags_changed = 1; + return op_pc+1; + + case 0x18: /*NEG*/ + uop_MOV_IMM(ir, IREG_temp1_B, 0); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op2, reg); + uop_SUB(ir, IREG_temp1_B, IREG_temp1_B, reg); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + uop_MOV(ir, reg, IREG_temp1_B); + } + else + { + uop_SUB(ir, IREG_temp1_B, IREG_temp1_B, reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_B); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB8); + uop_MOV_IMM(ir, IREG_flags_op1, 0); + + codegen_flags_changed = 1; + return op_pc+1; + } + return 0; +} +uint32_t ropF7_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint16_t imm_data; + int reg; + + if (fetchdat & 0x20) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + reg = IREG_16(fetchdat & 7); + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x30) == 0x10) /*NEG/NOT*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + reg = IREG_temp0_W; + } + + switch (fetchdat & 0x38) + { + case 0x00: case 0x08: /*TEST*/ + imm_data = fastreadw(cs + op_pc + 1); + + uop_AND_IMM(ir, IREG_flags_res_W, reg, imm_data); + uop_MOVZX(ir, IREG_flags_res, IREG_flags_res_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN16); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 2); + return op_pc+3; + + case 0x10: /*NOT*/ + uop_XOR_IMM(ir, reg, reg, 0xffff); + if ((fetchdat & 0xc0) != 0xc0) + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg); + + codegen_flags_changed = 1; + return op_pc+1; + + case 0x18: /*NEG*/ + uop_MOV_IMM(ir, IREG_temp1_W, 0); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op2, reg); + uop_SUB(ir, IREG_temp1_W, IREG_temp1_W, reg); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + uop_MOV(ir, reg, IREG_temp1_W); + } + else + { + uop_SUB(ir, IREG_temp1_W, IREG_temp1_W, reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op2, IREG_temp0_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB16); + uop_MOV_IMM(ir, IREG_flags_op1, 0); + + codegen_flags_changed = 1; + return op_pc+1; + } + return 0; +} +uint32_t ropF7_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint32_t imm_data; + int reg; + + if (fetchdat & 0x20) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + reg = IREG_32(fetchdat & 7); + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if ((fetchdat & 0x30) == 0x10) /*NEG/NOT*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + reg = IREG_temp0; + } + + switch (fetchdat & 0x38) + { + case 0x00: case 0x08: /*TEST*/ + imm_data = fastreadl(cs + op_pc + 1); + + uop_AND_IMM(ir, IREG_flags_res, reg, imm_data); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ZN32); + + codegen_flags_changed = 1; + codegen_mark_code_present(block, cs+op_pc+1, 4); + return op_pc+5; + + case 0x10: /*NOT*/ + uop_XOR_IMM(ir, reg, reg, 0xffffffff); + if ((fetchdat & 0xc0) != 0xc0) + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg); + + codegen_flags_changed = 1; + return op_pc+1; + + case 0x18: /*NEG*/ + uop_MOV_IMM(ir, IREG_temp1, 0); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOV(ir, IREG_flags_op2, reg); + uop_SUB(ir, IREG_temp1, IREG_temp1, reg); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + uop_MOV(ir, reg, IREG_temp1); + } + else + { + uop_SUB(ir, IREG_temp1, IREG_temp1, reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op2, IREG_temp0); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + } + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SUB32); + uop_MOV_IMM(ir, IREG_flags_op1, 0); + + codegen_flags_changed = 1; + return op_pc+1; + } + return 0; +} + +static void rebuild_c(ir_data_t *ir) +{ + int needs_rebuild = 1; + + if (codegen_flags_changed) + { + switch (cpu_state.flags_op) + { + case FLAGS_INC8: case FLAGS_INC16: case FLAGS_INC32: + case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: + needs_rebuild = 0; + break; + } + } + + if (needs_rebuild) + { + uop_CALL_FUNC(ir, flags_rebuild_c); + } +} + +uint32_t ropFF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg, sp_reg; + + if ((fetchdat & 0x38) != 0x00 && (fetchdat & 0x38) != 0x08 && (fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20 && (fetchdat & 0x38) != 0x28 && (fetchdat & 0x38) != 0x30) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + if ((fetchdat & 0x38) == 0x28) + return 0; + src_reg = IREG_16(fetchdat & 7); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if (!(fetchdat & 0x30)) /*INC/DEC*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + src_reg = IREG_temp0_W; + } + + switch (fetchdat & 0x38) + { + case 0x00: /*INC*/ + rebuild_c(ir); + codegen_flags_changed = 1; + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op1, src_reg); + uop_ADD_IMM(ir, src_reg, src_reg, 1); + uop_MOVZX(ir, IREG_flags_res, src_reg); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC16); + } + else + { + uop_ADD_IMM(ir, IREG_temp1_W, src_reg, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, src_reg); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC16); + } + return op_pc+1; + + case 0x08: /*DEC*/ + rebuild_c(ir); + codegen_flags_changed = 1; + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOVZX(ir, IREG_flags_op1, src_reg); + uop_SUB_IMM(ir, src_reg, src_reg, 1); + uop_MOVZX(ir, IREG_flags_res, src_reg); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC16); + } + else + { + uop_SUB_IMM(ir, IREG_temp1_W, src_reg, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, src_reg); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC16); + } + return op_pc+1; + + case 0x10: /*CALL*/ + if ((fetchdat & 0xc0) == 0xc0) + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_IMM_16(ir, IREG_SS_base, sp_reg, op_pc + 1); + SUB_SP(ir, 2); + uop_MOVZX(ir, IREG_pc, src_reg); + return -1; + + case 0x20: /*JMP*/ + uop_MOVZX(ir, IREG_pc, src_reg); + return -1; + + case 0x28: /*JMP far*/ + uop_MOVZX(ir, IREG_pc, src_reg); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_LOAD_FUNC_ARG_IMM(ir, 1, op_pc + 1); + uop_CALL_FUNC(ir, loadcsjmp); + return -1; + + case 0x30: /*PUSH*/ + if ((fetchdat & 0xc0) == 0xc0) + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, src_reg); + SUB_SP(ir, 2); + return op_pc+1; + } + return 0; +} + +uint32_t ropFF_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg, sp_reg; + + if ((fetchdat & 0x38) != 0x00 && (fetchdat & 0x38) != 0x08 && (fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20 && (fetchdat & 0x38) != 0x28 && (fetchdat & 0x38) != 0x30) + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + if ((fetchdat & 0x38) == 0x28) + return 0; + src_reg = IREG_32(fetchdat & 7); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + if (!(fetchdat & 0x30)) /*INC/DEC*/ + codegen_check_seg_write(block, ir, target_seg); + else + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + src_reg = IREG_temp0; + } + + switch (fetchdat & 0x38) + { + case 0x00: /*INC*/ + rebuild_c(ir); + codegen_flags_changed = 1; + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOV(ir, IREG_flags_op1, src_reg); + uop_ADD_IMM(ir, src_reg, src_reg, 1); + uop_MOV(ir, IREG_flags_res, src_reg); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC32); + } + else + { + uop_ADD_IMM(ir, IREG_temp1, src_reg, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, src_reg); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_INC32); + } + return op_pc+1; + + case 0x08: /*DEC*/ + rebuild_c(ir); + codegen_flags_changed = 1; + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOV(ir, IREG_flags_op1, src_reg); + uop_SUB_IMM(ir, src_reg, src_reg, 1); + uop_MOV(ir, IREG_flags_res, src_reg); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC32); + } + else + { + uop_SUB_IMM(ir, IREG_temp1, src_reg, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, src_reg); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op2, 1); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_DEC32); + } + return op_pc+1; + + case 0x10: /*CALL*/ + if ((fetchdat & 0xc0) == 0xc0) + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, op_pc + 1); + SUB_SP(ir, 4); + uop_MOV(ir, IREG_pc, src_reg); + return -1; + + case 0x20: /*JMP*/ + uop_MOV(ir, IREG_pc, src_reg); + return -1; + + case 0x28: /*JMP far*/ + uop_MOV(ir, IREG_pc, src_reg); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); + uop_LOAD_FUNC_ARG_REG(ir, 0, IREG_temp1_W); + uop_LOAD_FUNC_ARG_IMM(ir, 1, op_pc + 1); + uop_CALL_FUNC(ir, loadcsjmp); + return -1; + + case 0x30: /*PUSH*/ + if ((fetchdat & 0xc0) == 0xc0) + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, src_reg); + SUB_SP(ir, 4); + return op_pc+1; + } + return 0; +} + +uint32_t ropNOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + return op_pc; +} + +uint32_t ropCBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOVSX(ir, IREG_AX, IREG_AL); + + return op_pc; +} +uint32_t ropCDQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_SAR_IMM(ir, IREG_EDX, IREG_EAX, 31); + + return op_pc; +} +uint32_t ropCWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_SAR_IMM(ir, IREG_DX, IREG_AX, 15); + + return op_pc; +} +uint32_t ropCWDE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOVSX(ir, IREG_EAX, IREG_AX); + + return op_pc; +} + +#define ropLxS(name, seg) \ +uint32_t rop ## name ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg = NULL; \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + return 0; \ + \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 2); \ + uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ + uop_MOV(ir, IREG_16(dest_reg), IREG_temp0_W); \ + \ + if (seg == &cpu_state.seg_ss) \ + CPU_BLOCK_END(); \ + \ + return op_pc + 1; \ +} \ +uint32_t rop ## name ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + x86seg *target_seg = NULL; \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + return 0; \ + \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_MEM_LOAD_REG_OFFSET(ir, IREG_temp1_W, ireg_seg_base(target_seg), IREG_eaaddr, 4); \ + uop_LOAD_SEG(ir, seg, IREG_temp1_W); \ + uop_MOV(ir, IREG_32(dest_reg), IREG_temp0); \ + \ + if (seg == &cpu_state.seg_ss) \ + CPU_BLOCK_END(); \ + \ + return op_pc + 1; \ +} + +ropLxS(LDS, &cpu_state.seg_ds) +ropLxS(LES, &cpu_state.seg_es) +ropLxS(LFS, &cpu_state.seg_fs) +ropLxS(LGS, &cpu_state.seg_gs) +ropLxS(LSS, &cpu_state.seg_ss) + +uint32_t ropCLC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_CALL_FUNC(ir, flags_rebuild); + uop_AND_IMM(ir, IREG_flags, IREG_flags, ~C_FLAG); + return op_pc; +} +uint32_t ropCMC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_CALL_FUNC(ir, flags_rebuild); + uop_XOR_IMM(ir, IREG_flags, IREG_flags, C_FLAG); + return op_pc; +} +uint32_t ropSTC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_CALL_FUNC(ir, flags_rebuild); + uop_OR_IMM(ir, IREG_flags, IREG_flags, C_FLAG); + return op_pc; +} + +uint32_t ropCLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_AND_IMM(ir, IREG_flags, IREG_flags, ~D_FLAG); + return op_pc; +} +uint32_t ropSTD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_OR_IMM(ir, IREG_flags, IREG_flags, D_FLAG); + return op_pc; +} + +uint32_t ropCLI(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) + return 0; + + uop_AND_IMM(ir, IREG_flags, IREG_flags, ~I_FLAG); + return op_pc; +} +uint32_t ropSTI(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) + return 0; + + uop_OR_IMM(ir, IREG_flags, IREG_flags, I_FLAG); + return op_pc; +} diff --git a/src/codegen_ops_misc.h b/src/codegen_ops_misc.h index 1ccbcff..8f2fd76 100644 --- a/src/codegen_ops_misc.h +++ b/src/codegen_ops_misc.h @@ -1,265 +1,37 @@ -static uint32_t ropNOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - return op_pc; -} +uint32_t ropLEA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLEA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t 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; -} +uint32_t ropF6(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropF7_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropF7_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -static uint32_t ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - CLEAR_BITS((uintptr_t)&flags, I_FLAG); - return op_pc; -} -static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - SET_BITS((uintptr_t)&flags, I_FLAG); - return op_pc; -} +uint32_t ropFF_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropFF_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - x86seg *target_seg = NULL; - int host_reg; +uint32_t ropNOP(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - if ((fetchdat & 0x30) != 0x00) - return 0; +uint32_t ropCBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCDQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCWDE(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - CALL_FUNC((uintptr_t)flags_rebuild_c); - - if ((fetchdat & 0xc0) == 0xc0) - host_reg = LOAD_REG_B(fetchdat & 7); - else - { - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); +uint32_t ropLDS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLDS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLES_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLES_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLFS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLFS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLGS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLGS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLSS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLSS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - SAVE_EA(); - MEM_CHECK_WRITE(target_seg); - host_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); - } - - switch (fetchdat & 0x38) - { - case 0x00: /*INC*/ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_B(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); - break; - case 0x08: /*DEC*/ - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_B(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC8); - STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); - break; - } +uint32_t ropCLC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropCMC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSTC(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - if ((fetchdat & 0xc0) == 0xc0) - STORE_REG_B_RELEASE(host_reg); - else - { - LOAD_EA(); - MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, host_reg); - } - codegen_flags_changed = 1; - - return op_pc + 1; -} -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) -{ - x86seg *target_seg = NULL; - int host_reg; - - if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) - return 0; +uint32_t ropCLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSTD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - if ((fetchdat & 0x30) == 0x00) - CALL_FUNC((uintptr_t)flags_rebuild_c); - - if ((fetchdat & 0xc0) == 0xc0) - host_reg = LOAD_REG_W(fetchdat & 7); - else - { - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - - if ((fetchdat & 0x30) != 0x00) - { - MEM_LOAD_ADDR_EA_W(target_seg); - host_reg = 0; - } - else - { - SAVE_EA(); - MEM_CHECK_WRITE_W(target_seg); - host_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); - } - } - - switch (fetchdat & 0x38) - { - case 0x00: /*INC*/ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM_W(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0xc0) == 0xc0) - STORE_REG_W_RELEASE(host_reg); - else - { - LOAD_EA(); - MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); - } - codegen_flags_changed = 1; - return op_pc + 1; - case 0x08: /*DEC*/ - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM_W(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC16); - STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0xc0) == 0xc0) - STORE_REG_W_RELEASE(host_reg); - else - { - LOAD_EA(); - MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); - } - codegen_flags_changed = 1; - return op_pc + 1; - - case 0x10: /*CALL*/ - STORE_HOST_REG_ADDR_W((uintptr_t)&codegen_temp, host_reg); - RELEASE_REG(host_reg); - - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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)&cpu_state.oldpc, op_old_pc); - LOAD_STACK_TO_EA(-2); - MEM_STORE_ADDR_EA_W(&_ss, host_reg); - SP_MODIFY(-2); - return op_pc + 1; - } - return 0; -} -static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - x86seg *target_seg = NULL; - int host_reg; - - if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) - return 0; - - if ((fetchdat & 0x30) == 0x00) - CALL_FUNC((uintptr_t)flags_rebuild_c); - - if ((fetchdat & 0xc0) == 0xc0) - host_reg = LOAD_REG_L(fetchdat & 7); - else - { - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - - if ((fetchdat & 0x30) != 0x00) - { - MEM_LOAD_ADDR_EA_L(target_seg); - host_reg = 0; - } - else - { - SAVE_EA(); - MEM_CHECK_WRITE_L(target_seg); - host_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); - } - } - - switch (fetchdat & 0x38) - { - case 0x00: /*INC*/ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - ADD_HOST_REG_IMM(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0xc0) == 0xc0) - STORE_REG_L_RELEASE(host_reg); - else - { - LOAD_EA(); - MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); - } - codegen_flags_changed = 1; - return op_pc + 1; - case 0x08: /*DEC*/ - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); - SUB_HOST_REG_IMM(host_reg, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC32); - STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); - if ((fetchdat & 0xc0) == 0xc0) - STORE_REG_L_RELEASE(host_reg); - else - { - LOAD_EA(); - MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); - } - codegen_flags_changed = 1; - return op_pc + 1; - - case 0x10: /*CALL*/ - STORE_HOST_REG_ADDR((uintptr_t)&codegen_temp, host_reg); - RELEASE_REG(host_reg); - - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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)&cpu_state.oldpc, op_old_pc); - LOAD_STACK_TO_EA(-4); - MEM_STORE_ADDR_EA_L(&_ss, host_reg); - SP_MODIFY(-4); - return op_pc + 1; - } - return 0; -} +uint32_t ropCLI(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSTI(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_mmx.h b/src/codegen_ops_mmx.h deleted file mode 100644 index 78239cb..0000000 --- a/src/codegen_ops_mmx.h +++ /dev/null @@ -1,277 +0,0 @@ -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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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_mmx_arith.c b/src/codegen_ops_mmx_arith.c new file mode 100644 index 0000000..1629fe6 --- /dev/null +++ b/src/codegen_ops_mmx_arith.c @@ -0,0 +1,57 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_arith.h" +#include "codegen_ops_helpers.h" + +#define ropParith(func) \ +uint32_t rop ## func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + int src_reg = fetchdat & 7; \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } \ + else \ + { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ +} + +ropParith(PADDB) +ropParith(PADDW) +ropParith(PADDD) +ropParith(PADDSB) +ropParith(PADDSW) +ropParith(PADDUSB) +ropParith(PADDUSW) + +ropParith(PSUBB) +ropParith(PSUBW) +ropParith(PSUBD) +ropParith(PSUBSB) +ropParith(PSUBSW) +ropParith(PSUBUSB) +ropParith(PSUBUSW) + +ropParith(PMADDWD) +ropParith(PMULHW) +ropParith(PMULLW) diff --git a/src/codegen_ops_mmx_arith.h b/src/codegen_ops_mmx_arith.h new file mode 100644 index 0000000..5f67f0a --- /dev/null +++ b/src/codegen_ops_mmx_arith.h @@ -0,0 +1,19 @@ +uint32_t ropPADDB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDSB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDUSB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPADDUSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPSUBB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBSB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBUSB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSUBUSW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPMADDWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPMULHW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPMULLW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_mmx_cmp.c b/src/codegen_ops_mmx_cmp.c new file mode 100644 index 0000000..b7fe44d --- /dev/null +++ b/src/codegen_ops_mmx_cmp.c @@ -0,0 +1,44 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_cmp.h" +#include "codegen_ops_helpers.h" + +#define ropPcmp(func) \ +uint32_t rop ## func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + int src_reg = fetchdat & 7; \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } \ + else \ + { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ +} + +ropPcmp(PCMPEQB) +ropPcmp(PCMPEQW) +ropPcmp(PCMPEQD) +ropPcmp(PCMPGTB) +ropPcmp(PCMPGTW) +ropPcmp(PCMPGTD) diff --git a/src/codegen_ops_mmx_cmp.h b/src/codegen_ops_mmx_cmp.h new file mode 100644 index 0000000..6069ad1 --- /dev/null +++ b/src/codegen_ops_mmx_cmp.h @@ -0,0 +1,6 @@ +uint32_t ropPCMPEQB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPEQW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPEQD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPGTB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPGTW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPCMPGTD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_mmx_loadstore.c b/src/codegen_ops_mmx_loadstore.c new file mode 100644 index 0000000..a376f9b --- /dev/null +++ b/src/codegen_ops_mmx_loadstore.c @@ -0,0 +1,113 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_loadstore.h" +#include "codegen_ops_helpers.h" + +uint32_t ropMOVD_r_d(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_MM(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_MM(dest_reg), IREG_temp0); + } + + return op_pc + 1; +} +uint32_t ropMOVD_d_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + if (cpu_iscyrix && (cpu_cur_status & CPU_STATUS_SMM)) + return 0; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_32(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 3); + uop_MOVZX(ir, IREG_temp0, IREG_MM(src_reg)); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + } + + return op_pc + 1; +} + +uint32_t ropMOVQ_r_q(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_MM(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + return op_pc + 1; +} + +uint32_t ropMOVQ_q_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 7); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_MM(src_reg)); + } + + return op_pc + 1; +} diff --git a/src/codegen_ops_mmx_loadstore.h b/src/codegen_ops_mmx_loadstore.h new file mode 100644 index 0000000..4b473ad --- /dev/null +++ b/src/codegen_ops_mmx_loadstore.h @@ -0,0 +1,5 @@ +uint32_t ropMOVD_r_d(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVD_d_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropMOVQ_r_q(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVQ_q_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_mmx_logic.c b/src/codegen_ops_mmx_logic.c new file mode 100644 index 0000000..744f22b --- /dev/null +++ b/src/codegen_ops_mmx_logic.c @@ -0,0 +1,108 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_logic.h" +#include "codegen_ops_helpers.h" + +uint32_t ropPAND(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_AND(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_AND(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); + } + + return op_pc + 1; +} +uint32_t ropPANDN(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_ANDN(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_ANDN(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); + } + + return op_pc + 1; +} +uint32_t ropPOR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_OR(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_OR(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); + } + + return op_pc + 1; +} +uint32_t ropPXOR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_XOR(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); + uop_XOR(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); + } + + return op_pc + 1; +} diff --git a/src/codegen_ops_mmx_logic.h b/src/codegen_ops_mmx_logic.h new file mode 100644 index 0000000..f8f3009 --- /dev/null +++ b/src/codegen_ops_mmx_logic.h @@ -0,0 +1,4 @@ +uint32_t ropPAND(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPANDN(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPXOR(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_mmx_pack.c b/src/codegen_ops_mmx_pack.c new file mode 100644 index 0000000..e625217 --- /dev/null +++ b/src/codegen_ops_mmx_pack.c @@ -0,0 +1,47 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_pack.h" +#include "codegen_ops_helpers.h" + +#define ropPpack(func) \ +uint32_t rop ## func(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + \ + uop_MMX_ENTER(ir); \ + codegen_mark_code_present(block, cs+op_pc, 1); \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + int src_reg = fetchdat & 7; \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_MM(src_reg)); \ + } \ + else \ + { \ + x86seg *target_seg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); \ + codegen_check_seg_read(block, ir, target_seg); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_Q, ireg_seg_base(target_seg), IREG_eaaddr); \ + uop_ ## func(ir, IREG_MM(dest_reg), IREG_MM(dest_reg), IREG_temp0_Q); \ + } \ + \ + return op_pc + 1; \ +} + +ropPpack(PACKSSWB) +ropPpack(PACKSSDW) +ropPpack(PACKUSWB) +ropPpack(PUNPCKLBW) +ropPpack(PUNPCKLWD) +ropPpack(PUNPCKLDQ) +ropPpack(PUNPCKHBW) +ropPpack(PUNPCKHWD) +ropPpack(PUNPCKHDQ) diff --git a/src/codegen_ops_mmx_pack.h b/src/codegen_ops_mmx_pack.h new file mode 100644 index 0000000..f46eea6 --- /dev/null +++ b/src/codegen_ops_mmx_pack.h @@ -0,0 +1,9 @@ +uint32_t ropPACKSSWB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPACKSSDW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPACKUSWB(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKLBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKLWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKLDQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKHBW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKHWD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUNPCKHDQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_mmx_shift.c b/src/codegen_ops_mmx_shift.c new file mode 100644 index 0000000..3086f4d --- /dev/null +++ b/src/codegen_ops_mmx_shift.c @@ -0,0 +1,93 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_accumulate.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_mmx_shift.h" +#include "codegen_ops_helpers.h" + +uint32_t ropPSxxW_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = fastreadb(cs + op_pc + 1); + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + switch (op) + { + case 0x10: /*PSRLW*/ + uop_PSRLW_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x20: /*PSRAW*/ + uop_PSRAW_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x30: /*PSLLW*/ + uop_PSLLW_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + default: + return 0; + + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropPSxxD_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = fastreadb(cs + op_pc + 1); + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + switch (op) + { + case 0x10: /*PSRLD*/ + uop_PSRLD_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x20: /*PSRAD*/ + uop_PSRAD_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x30: /*PSLLD*/ + uop_PSLLD_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + default: + return 0; + + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropPSxxQ_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = fastreadb(cs + op_pc + 1); + + uop_MMX_ENTER(ir); + codegen_mark_code_present(block, cs+op_pc, 1); + switch (op) + { + case 0x10: /*PSRLQ*/ + uop_PSRLQ_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x20: /*PSRAQ*/ + uop_PSRAQ_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + case 0x30: /*PSLLQ*/ + uop_PSLLQ_IMM(ir, IREG_MM(reg), IREG_MM(reg), shift); + break; + default: + return 0; + + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} diff --git a/src/codegen_ops_mmx_shift.h b/src/codegen_ops_mmx_shift.h new file mode 100644 index 0000000..3a3b712 --- /dev/null +++ b/src/codegen_ops_mmx_shift.h @@ -0,0 +1,7 @@ +uint32_t ropPSxxW_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSxxD_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSxxQ_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); + +uint32_t ropPSLLW(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSLLD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPSLLQ(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_mov.c b/src/codegen_ops_mov.c new file mode 100644 index 0000000..26cd4e5 --- /dev/null +++ b/src/codegen_ops_mov.c @@ -0,0 +1,772 @@ +#include "ibm.h" + +#include "x86.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_mov.h" + +uint32_t ropMOV_rb_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint8_t imm = fastreadb(cs + op_pc); + + uop_MOV_IMM(ir, IREG_8(opcode & 7), imm); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropMOV_rw_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_16(opcode & 7), imm); + + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropMOV_rl_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_32(opcode & 7), cs + op_pc); + } + else + { + fetchdat = fastreadl(cs + op_pc); + uop_MOV_IMM(ir, IREG_32(opcode & 7), fetchdat); + codegen_mark_code_present(block, cs+op_pc, 4); + } + return op_pc + 4; +} + + + +uint32_t ropMOV_b_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + +// if (block->phys == 0x49a400) +// pclog("ropMOVb_rmarkcode %08x 1\n", cs+op_pc); + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 0); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_8(src_reg)); + } + + return op_pc + 1; +} +uint32_t ropMOV_w_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_16(src_reg)); + } + + return op_pc + 1; +} +uint32_t ropMOV_l_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 3); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_32(src_reg)); + } + + return op_pc + 1; +} +uint32_t ropMOV_r_b(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_8(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_8(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + return op_pc + 1; +} +uint32_t ropMOV_r_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_16(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_16(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + return op_pc + 1; +} +uint32_t ropMOV_r_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOV(ir, IREG_32(dest_reg), IREG_32(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_32(dest_reg), ireg_seg_base(target_seg), IREG_eaaddr); + } + + return op_pc + 1; +} + +uint32_t ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + uop_MEM_LOAD_ABS(ir, IREG_AL, ireg_seg_base(op_ea_seg), addr); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + uop_MEM_LOAD_ABS(ir, IREG_AX, ireg_seg_base(op_ea_seg), addr); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr = 0; + + if (op_32 & 0x200) + { + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + LOAD_IMMEDIATE_FROM_RAM_32(block, ir, IREG_eaaddr, cs + op_pc); + } + else + { + addr = fastreadl(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 4); + } + } + else + { + addr = fastreadw(cs + op_pc); + codegen_mark_code_present(block, cs+op_pc, 2); + } + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_read(block, ir, op_ea_seg); + if ((block->flags & CODEBLOCK_NO_IMMEDIATES) && (op_32 & 0x200)) + uop_MEM_LOAD_REG(ir, IREG_EAX, ireg_seg_base(op_ea_seg), IREG_eaaddr); + else + uop_MEM_LOAD_ABS(ir, IREG_EAX, ireg_seg_base(op_ea_seg), addr); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +uint32_t ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_AL); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_AX); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +uint32_t ropMOV_abs_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + codegen_check_seg_write(block, ir, op_ea_seg); + uop_MEM_STORE_ABS(ir, ireg_seg_base(op_ea_seg), addr, IREG_EAX); + + codegen_mark_code_present(block, cs+op_pc, (op_32 & 0x200) ? 4 : 2); + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +uint32_t ropMOV_b_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadb(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_8(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadb(cs + op_pc + 1); + uop_MEM_STORE_IMM_8(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + codegen_mark_code_present(block, cs+op_pc+1, 1); + return op_pc + 2; +} +uint32_t ropMOV_w_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint16_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadw(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_16(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadw(cs + op_pc + 1); + uop_MEM_STORE_IMM_16(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + codegen_mark_code_present(block, cs+op_pc+1, 2); + return op_pc + 3; +} +uint32_t ropMOV_l_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg; + uint32_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + imm = fastreadl(cs + op_pc + 1); + uop_MOV_IMM(ir, IREG_32(dest_reg), imm); + } + else + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + imm = fastreadl(cs + op_pc + 1); + uop_MEM_STORE_IMM_32(ir, ireg_seg_base(target_seg), IREG_eaaddr, imm); + } + + codegen_mark_code_present(block, cs+op_pc+1, 4); + return op_pc + 5; +} + +uint32_t ropMOV_w_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg; + + codegen_mark_code_present(block, cs+op_pc, 1); + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + src_reg = IREG_ES_seg_W; + break; + case 0x08: /*CS*/ + src_reg = IREG_CS_seg_W; + break; + case 0x18: /*DS*/ + src_reg = IREG_DS_seg_W; + break; + case 0x10: /*SS*/ + src_reg = IREG_SS_seg_W; + break; + case 0x20: /*FS*/ + src_reg = IREG_FS_seg_W; + break; + case 0x28: /*GS*/ + src_reg = IREG_GS_seg_W; + break; + default: + return 0; + } + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOV(ir, IREG_16(dest_reg), src_reg); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + CHECK_SEG_LIMITS(block, ir, target_seg, IREG_eaaddr, 1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, src_reg); + } + + return op_pc + 1; +} +uint32_t ropMOV_l_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg; + + codegen_mark_code_present(block, cs+op_pc, 1); + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + src_reg = IREG_ES_seg_W; + break; + case 0x08: /*CS*/ + src_reg = IREG_CS_seg_W; + break; + case 0x18: /*DS*/ + src_reg = IREG_DS_seg_W; + break; + case 0x10: /*SS*/ + src_reg = IREG_SS_seg_W; + break; + case 0x20: /*FS*/ + src_reg = IREG_FS_seg_W; + break; + case 0x28: /*GS*/ + src_reg = IREG_GS_seg_W; + break; + default: + return 0; + } + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_32(dest_reg), src_reg); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, src_reg); + } + + return op_pc + 1; +} + +uint32_t ropMOV_seg_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int src_reg; + x86seg *rseg; + + codegen_mark_code_present(block, cs+op_pc, 1); + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + rseg = &cpu_state.seg_es; + break; + case 0x18: /*DS*/ + rseg = &cpu_state.seg_ds; + break; + case 0x20: /*FS*/ + rseg = &cpu_state.seg_fs; + break; + case 0x28: /*GS*/ + rseg = &cpu_state.seg_gs; + break; + default: + return 0; + } + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if ((fetchdat & 0xc0) == 0xc0) + { + uop_MOV(ir, IREG_temp0_W, IREG_16(fetchdat & 7)); + src_reg = IREG_temp0_W; + } + else + { + x86seg *target_seg; + + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + src_reg = IREG_temp0_W; + } + + uop_LOAD_SEG(ir, rseg, src_reg); + + return op_pc + 1; +} + +uint32_t ropMOVSX_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVSX(ir, IREG_16(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVSX(ir, IREG_16(dest_reg), IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropMOVSX_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVSX(ir, IREG_32(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVSX(ir, IREG_32(dest_reg), IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropMOVSX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVSX(ir, IREG_32(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVSX(ir, IREG_32(dest_reg), IREG_temp0_W); + } + + return op_pc + 1; +} + +uint32_t ropMOVZX_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_16(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_16(dest_reg), IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropMOVZX_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_32(dest_reg), IREG_8(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_32(dest_reg), IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropMOVZX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int dest_reg = (fetchdat >> 3) & 7; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int src_reg = fetchdat & 7; + uop_MOVZX(ir, IREG_32(dest_reg), IREG_16(src_reg)); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_read(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MOVZX(ir, IREG_32(dest_reg), IREG_temp0_W); + } + + return op_pc + 1; +} + + +uint32_t ropXCHG_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg2 = IREG_16(opcode & 7); + + uop_MOV(ir, IREG_temp0_W, IREG_AX); + uop_MOV(ir, IREG_AX, reg2); + uop_MOV(ir, reg2, IREG_temp0_W); + + return op_pc; +} +uint32_t ropXCHG_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg2 = IREG_32(opcode & 7); + + uop_MOV(ir, IREG_temp0, IREG_EAX); + uop_MOV(ir, IREG_EAX, reg2); + uop_MOV(ir, reg2, IREG_temp0); + + return op_pc; +} + +uint32_t ropXCHG_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg1 = IREG_8((fetchdat >> 3) & 7); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int reg2 = IREG_8(fetchdat & 7); + + uop_MOV(ir, IREG_temp0_B, reg1); + uop_MOV(ir, reg1, reg2); + uop_MOV(ir, reg2, IREG_temp0_B); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg1); + uop_MOV(ir, reg1, IREG_temp0_B); + } + + return op_pc + 1; +} +uint32_t ropXCHG_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg1 = IREG_16((fetchdat >> 3) & 7); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int reg2 = IREG_16(fetchdat & 7); + + uop_MOV(ir, IREG_temp0_W, reg1); + uop_MOV(ir, reg1, reg2); + uop_MOV(ir, reg2, IREG_temp0_W); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg1); + uop_MOV(ir, reg1, IREG_temp0_W); + } + + return op_pc + 1; +} +uint32_t ropXCHG_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int reg1 = IREG_32((fetchdat >> 3) & 7); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int reg2 = IREG_32(fetchdat & 7); + + uop_MOV(ir, IREG_temp0, reg1); + uop_MOV(ir, reg1, reg2); + uop_MOV(ir, reg2, IREG_temp0); + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, reg1); + uop_MOV(ir, reg1, IREG_temp0); + } + + return op_pc + 1; +} + +uint32_t ropXLAT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + uop_MOVZX(ir, IREG_eaaddr, IREG_AL); + uop_ADD(ir, IREG_eaaddr, IREG_eaaddr, IREG_EBX); + if (!(op_32 & 0x200)) + uop_AND_IMM(ir, IREG_eaaddr, IREG_eaaddr, 0xffff); + + uop_MEM_LOAD_REG(ir, IREG_AL, ireg_seg_base(op_ea_seg), IREG_eaaddr); + + return op_pc; +} diff --git a/src/codegen_ops_mov.h b/src/codegen_ops_mov.h index 61fcd0f..03a9cb8 100644 --- a/src/codegen_ops_mov.h +++ b/src/codegen_ops_mov.h @@ -1,656 +1,43 @@ -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); +uint32_t ropMOV_rb_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_rw_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_rl_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - 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); +uint32_t ropMOV_b_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_w_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_l_r(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_r_b(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_r_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_r_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_REG_L(opcode & 7, fetchdat); - - return op_pc + 4; -} +uint32_t ropMOV_AL_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_AX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_EAX_abs(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_abs_AL(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_abs_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_abs_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -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); +uint32_t ropMOV_b_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_w_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_l_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - - CHECK_SEG_WRITE(target_seg); - CHECK_SEG_LIMITS(target_seg, 0); +uint32_t ropMOV_w_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_l_seg(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOV_seg_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - 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); +uint32_t ropMOVSX_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVSX_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVSX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - - CHECK_SEG_WRITE(target_seg); - CHECK_SEG_LIMITS(target_seg, 1); +uint32_t ropMOVZX_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVZX_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropMOVZX_32_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - MEM_STORE_ADDR_EA_W(target_seg, host_reg); - RELEASE_REG(host_reg); - } - - return op_pc + 1; -} +uint32_t ropXCHG_AX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXCHG_EAX(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -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); +uint32_t ropXCHG_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXCHG_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropXCHG_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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; -} - -static uint32_t ropMOV_w_seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - int host_reg; - - switch (fetchdat & 0x38) - { - case 0x00: /*ES*/ - host_reg = LOAD_VAR_WL((uintptr_t)&ES); - break; - case 0x08: /*CS*/ - host_reg = LOAD_VAR_WL((uintptr_t)&CS); - break; - case 0x18: /*DS*/ - host_reg = LOAD_VAR_WL((uintptr_t)&DS); - break; - case 0x10: /*SS*/ - host_reg = LOAD_VAR_WL((uintptr_t)&SS); - break; - case 0x20: /*FS*/ - host_reg = LOAD_VAR_WL((uintptr_t)&FS); - break; - case 0x28: /*GS*/ - host_reg = LOAD_VAR_WL((uintptr_t)&GS); - break; - default: - return 0; - } - - if ((fetchdat & 0xc0) == 0xc0) - { - if (op_32 & 0x100) - STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); - else - 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)&cpu_state.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_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - int host_reg; - - switch (fetchdat & 0x38) - { - case 0x00: /*ES*/ - case 0x18: /*DS*/ - case 0x20: /*FS*/ - case 0x28: /*GS*/ - break; - case 0x10: /*SS*/ - default: - return 0; - } - - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); - - 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); - - CHECK_SEG_READ(target_seg); - MEM_LOAD_ADDR_EA_W(target_seg); - - host_reg = 0; - } - - switch (fetchdat & 0x38) - { - case 0x00: /*ES*/ - LOAD_SEG(host_reg, &_es); - break; - case 0x18: /*DS*/ - LOAD_SEG(host_reg, &_ds); - break; - case 0x20: /*FS*/ - LOAD_SEG(host_reg, &_fs); - break; - case 0x28: /*GS*/ - LOAD_SEG(host_reg, &_gs); - break; - } - - return op_pc + 1; -} - -#define ropLseg(seg, rseg) \ -static uint32_t ropL ## seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ -{ \ - int dest_reg = (fetchdat >> 3) & 7; \ - x86seg *target_seg; \ - \ - if ((fetchdat & 0xc0) == 0xc0) \ - return 0; \ - \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - SAVE_EA(); \ - \ - if (op_32 & 0x100) \ - { \ - MEM_LOAD_ADDR_EA_L(target_seg); \ - STORE_HOST_REG_ADDR((uintptr_t)&codegen_temp, 0); \ - LOAD_EA(); \ - MEM_LOAD_ADDR_EA_W_OFFSET(target_seg, 4); \ - } \ - else \ - { \ - MEM_LOAD_ADDR_EA_W(target_seg); \ - STORE_HOST_REG_ADDR_W((uintptr_t)&codegen_temp, 0); \ - LOAD_EA(); \ - MEM_LOAD_ADDR_EA_W_OFFSET(target_seg, 2); \ - } \ - LOAD_SEG(0, &rseg); \ - if (op_32 & 0x100) \ - { \ - \ - int host_reg = LOAD_VAR_L((uintptr_t)&codegen_temp); \ - STORE_REG_TARGET_L_RELEASE(host_reg, dest_reg); \ - } \ - else \ - { \ - int host_reg = LOAD_VAR_W((uintptr_t)&codegen_temp); \ - STORE_REG_TARGET_W_RELEASE(host_reg, dest_reg); \ - } \ - \ - if (&rseg == &_ss) \ - CPU_BLOCK_END(); /*Instruction might change stack size, so end block here*/ \ - return op_pc + 1; \ -} - -ropLseg(DS, _ds) -ropLseg(ES, _es) -ropLseg(FS, _fs) -ropLseg(GS, _gs) -ropLseg(SS, _ss) +uint32_t ropXLAT(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_shift.c b/src/codegen_ops_shift.c new file mode 100644 index 0000000..0d19f40 --- /dev/null +++ b/src/codegen_ops_shift.c @@ -0,0 +1,1135 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_shift.h" + +static uint32_t shift_common_8(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, x86seg *target_seg, int count) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SHL_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SHR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SAR_IMM(ir, IREG_8(dest_reg), IREG_8(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + default: + return 0; + } + } + else + { + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_temp0_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_temp0_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL_IMM(ir, IREG_temp1_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x28: /*SHR*/ + uop_SHR_IMM(ir, IREG_temp1_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x38: /*SAR*/ + uop_SAR_IMM(ir, IREG_temp1_B, IREG_temp0_B, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} + +static uint32_t shift_common_16(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, x86seg *target_seg, int count) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHL_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SAR_IMM(ir, IREG_16(dest_reg), IREG_16(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + default: + return 0; + } + } + else + { + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_temp0_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_temp0_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL_IMM(ir, IREG_temp1_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x28: /*SHR*/ + uop_SHR_IMM(ir, IREG_temp1_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x38: /*SAR*/ + uop_SAR_IMM(ir, IREG_temp1_W, IREG_temp0_W, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t shift_common_32(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, x86seg *target_seg, int count) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHL_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SAR_IMM(ir, IREG_32(dest_reg), IREG_32(dest_reg), count); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + default: + return 0; + } + } + else + { + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL_IMM(ir, IREG_temp0, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR_IMM(ir, IREG_temp0, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL_IMM(ir, IREG_temp1, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x28: /*SHR*/ + uop_SHR_IMM(ir, IREG_temp1, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x38: /*SAR*/ + uop_SAR_IMM(ir, IREG_temp1, IREG_temp0, count); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, count); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} + +static uint32_t shift_common_variable_32(ir_data_t *ir, uint32_t fetchdat, uint32_t op_pc, x86seg *target_seg, int count_reg) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHL(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHR(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SAR(ir, IREG_32(dest_reg), IREG_32(dest_reg), count_reg); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + default: + return 0; + } + } + else + { + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_temp0, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_temp0, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL(ir, IREG_temp1, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x28: /*SHR*/ + uop_SHR(ir, IREG_temp1, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x38: /*SAR*/ + uop_SAR(ir, IREG_temp1, IREG_temp0, count_reg); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, count_reg); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropC0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint8_t imm; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (imm) + return shift_common_8(ir, fetchdat, op_pc, target_seg, imm) + 1; + return op_pc+1; +} +uint32_t ropC1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + uint8_t imm; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (imm) + return shift_common_16(ir, fetchdat, op_pc, target_seg, imm) + 1; + return op_pc+1; +} +uint32_t ropC1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + } + if (block->flags & CODEBLOCK_NO_IMMEDIATES) + { + uint32_t new_pc; + int jump_uop; + + LOAD_IMMEDIATE_FROM_RAM_8(block, ir, IREG_temp2, cs + op_pc + 1); + uop_AND_IMM(ir, IREG_temp2, IREG_temp2, 0x1f); + jump_uop = uop_CMP_IMM_JZ_DEST(ir, IREG_temp2, 0); + + new_pc = shift_common_variable_32(ir, fetchdat, op_pc, target_seg, IREG_temp2) + 1; + uop_NOP_BARRIER(ir); + uop_set_jump_dest(ir, jump_uop); + return new_pc; + } + else + { + uint8_t imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (imm) + return shift_common_32(ir, fetchdat, op_pc, target_seg, imm) + 1; + } + return op_pc+1; +} + +uint32_t ropD0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + } + + return shift_common_8(ir, fetchdat, op_pc, target_seg, 1); +} +uint32_t ropD1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + } + + return shift_common_16(ir, fetchdat, op_pc, target_seg, 1); +} +uint32_t ropD1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + } + + return shift_common_32(ir, fetchdat, op_pc, target_seg, 1); +} + +uint32_t ropD2(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + if (!(CL & 0x1f) || !block->ins) + return 0; + + uop_AND_IMM(ir, IREG_temp2, REG_ECX, 0x1f); + uop_CMP_IMM_JZ(ir, IREG_temp2, 0, codegen_exit_rout); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SHL(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SHR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_8(dest_reg)); + uop_SAR(ir, IREG_8(dest_reg), IREG_8(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); + uop_MOVZX(ir, IREG_flags_res, IREG_8(dest_reg)); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_B, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_temp0_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_temp0_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_B); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_B); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL(ir, IREG_temp1_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x28: /*SHR*/ + uop_SHR(ir, IREG_temp1_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + case 0x38: /*SAR*/ + uop_SAR(ir, IREG_temp1_B, IREG_temp0_B, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_B); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_B); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR8); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_B); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropD3_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + if (!(CL & 0x1f) || !block->ins) + return 0; + + uop_AND_IMM(ir, IREG_temp2, REG_ECX, 0x1f); + uop_CMP_IMM_JZ(ir, IREG_temp2, 0, codegen_exit_rout); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHL(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SAR(ir, IREG_16(dest_reg), IREG_16(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x28: /*SHR*/ + uop_SHR(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + case 0x38: /*SAR*/ + uop_SAR(ir, IREG_temp1_W, IREG_temp0_W, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1_W); + uop_MOVZX(ir, IREG_flags_op1, IREG_temp0_W); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR16); + uop_MOVZX(ir, IREG_flags_res, IREG_temp1_W); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} +uint32_t ropD3_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + if ((fetchdat & 0x30) == 0x10) /*RCL/RCR*/ + return 0; + + if (!(CL & 0x1f) || !block->ins) + return 0; + + uop_AND_IMM(ir, IREG_temp2, REG_ECX, 0x1f); + uop_CMP_IMM_JZ(ir, IREG_temp2, 0, codegen_exit_rout); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHL(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x28: /*SHR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + case 0x38: /*SAR*/ + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SAR(ir, IREG_32(dest_reg), IREG_32(dest_reg), IREG_temp2); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + break; + + default: + return 0; + } + } + else + { + x86seg *target_seg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp0, ireg_seg_base(target_seg), IREG_eaaddr); + + switch (fetchdat & 0x38) + { + case 0x00: /*ROL*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROL(ir, IREG_temp0, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROL32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x08: /*ROR*/ + uop_CALL_FUNC(ir, flags_rebuild); + uop_ROR(ir, IREG_temp0, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_ROR32); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + break; + + case 0x20: case 0x30: /*SHL*/ + uop_SHL(ir, IREG_temp1, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x28: /*SHR*/ + uop_SHR(ir, IREG_temp1, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + case 0x38: /*SAR*/ + uop_SAR(ir, IREG_temp1, IREG_temp0, IREG_temp2); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp1); + uop_MOV(ir, IREG_flags_op1, IREG_temp0); + uop_MOV(ir, IREG_flags_op2, IREG_temp2); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SAR32); + uop_MOV(ir, IREG_flags_res, IREG_temp1); + break; + + default: + return 0; + } + } + + codegen_flags_changed = 1; + return op_pc + 1; +} + +uint32_t ropSHLD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg = (fetchdat >> 3) & 7; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (!imm) + return op_pc+2; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHL_IMM(ir, IREG_temp0_W, IREG_16(dest_reg), imm); + uop_SHR_IMM(ir, IREG_temp1_W, IREG_16(src_reg), 16 - imm); + uop_OR(ir, IREG_16(dest_reg), IREG_temp0_W, IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp2_W, ireg_seg_base(target_seg), IREG_eaaddr); + + uop_SHL_IMM(ir, IREG_temp0_W, IREG_temp2, imm); + uop_SHR_IMM(ir, IREG_temp1_W, IREG_16(src_reg), 16 - imm); + uop_OR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp1_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + + uop_MOVZX(ir, IREG_flags_op1, IREG_temp2_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL16); + } + + return op_pc+2; +} +uint32_t ropSHLD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg = (fetchdat >> 3) & 7; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (!imm) + return op_pc+2; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHL_IMM(ir, IREG_temp0, IREG_32(dest_reg), imm); + uop_SHR_IMM(ir, IREG_temp1, IREG_32(src_reg), 32 - imm); + uop_OR(ir, IREG_32(dest_reg), IREG_temp0, IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp2, ireg_seg_base(target_seg), IREG_eaaddr); + + uop_SHL_IMM(ir, IREG_temp0, IREG_temp2, imm); + uop_SHR_IMM(ir, IREG_temp1, IREG_32(src_reg), 32 - imm); + uop_OR(ir, IREG_temp0, IREG_temp0, IREG_temp1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + + uop_MOV(ir, IREG_flags_op1, IREG_temp2); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHL32); + } + + return op_pc+2; +} +uint32_t ropSHRD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg = (fetchdat >> 3) & 7; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (!imm) + return op_pc+2; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOVZX(ir, IREG_flags_op1, IREG_16(dest_reg)); + uop_SHR_IMM(ir, IREG_temp0_W, IREG_16(dest_reg), imm); + uop_SHL_IMM(ir, IREG_temp1_W, IREG_16(src_reg), 16 - imm); + uop_OR(ir, IREG_16(dest_reg), IREG_temp0_W, IREG_temp1_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + uop_MOVZX(ir, IREG_flags_res, IREG_16(dest_reg)); + } + else + { + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp2_W, ireg_seg_base(target_seg), IREG_eaaddr); + + uop_SHR_IMM(ir, IREG_temp0_W, IREG_temp2, imm); + uop_SHL_IMM(ir, IREG_temp1_W, IREG_16(src_reg), 16 - imm); + uop_OR(ir, IREG_temp0_W, IREG_temp0_W, IREG_temp1_W); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + + uop_MOVZX(ir, IREG_flags_op1, IREG_temp2_W); + uop_MOVZX(ir, IREG_flags_res, IREG_temp0_W); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR16); + } + + return op_pc+2; +} +uint32_t ropSHRD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + x86seg *target_seg = NULL; + int src_reg = (fetchdat >> 3) & 7; + uint8_t imm; + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) != 0xc0) + { + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 0); + } + imm = fastreadb(cs + op_pc + 1) & 0x1f; + codegen_mark_code_present(block, cs+op_pc+1, 1); + + if (!imm) + return op_pc+2; + + if ((fetchdat & 0xc0) == 0xc0) + { + int dest_reg = fetchdat & 7; + + uop_MOV(ir, IREG_flags_op1, IREG_32(dest_reg)); + uop_SHR_IMM(ir, IREG_temp0, IREG_32(dest_reg), imm); + uop_SHL_IMM(ir, IREG_temp1, IREG_32(src_reg), 32 - imm); + uop_OR(ir, IREG_32(dest_reg), IREG_temp0, IREG_temp1); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + uop_MOV(ir, IREG_flags_res, IREG_32(dest_reg)); + } + else + { + codegen_check_seg_write(block, ir, target_seg); + uop_MEM_LOAD_REG(ir, IREG_temp2, ireg_seg_base(target_seg), IREG_eaaddr); + + uop_SHR_IMM(ir, IREG_temp0, IREG_temp2, imm); + uop_SHL_IMM(ir, IREG_temp1, IREG_32(src_reg), 32 - imm); + uop_OR(ir, IREG_temp0, IREG_temp0, IREG_temp1); + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + + uop_MOV(ir, IREG_flags_op1, IREG_temp2); + uop_MOV(ir, IREG_flags_res, IREG_temp0); + uop_MOV_IMM(ir, IREG_flags_op2, imm); + uop_MOV_IMM(ir, IREG_flags_op, FLAGS_SHR32); + } + + return op_pc+2; +} diff --git a/src/codegen_ops_shift.h b/src/codegen_ops_shift.h index 75d024f..f109b0d 100644 --- a/src/codegen_ops_shift.h +++ b/src/codegen_ops_shift.h @@ -1,125 +1,16 @@ -#define SHIFT(size, size2, res_store, immediate) \ - if ((fetchdat & 0xc0) == 0xc0) \ - { \ - reg = LOAD_REG_ ## size(fetchdat & 7); \ - if (immediate) count = (fetchdat >> 8) & 0x1f; \ - } \ - else \ - { \ - target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - SAVE_EA(); \ - MEM_CHECK_WRITE_ ## size(target_seg); \ - reg = MEM_LOAD_ADDR_EA_ ## size ## _NO_ABRT(target_seg); \ - if (immediate) count = fastreadb(cs + op_pc + 1) & 0x1f; \ - } \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, count); \ - \ - res_store((uintptr_t)&cpu_state.flags_op1, reg); \ - \ - switch (fetchdat & 0x38) \ - { \ - case 0x20: case 0x30: /*SHL*/ \ - SHL_ ## size ## _IMM(reg, count); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SHL ## size2); \ - break; \ - \ - case 0x28: /*SHR*/ \ - SHR_ ## size ## _IMM(reg, count); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SHR ## size2); \ - break; \ - \ - case 0x38: /*SAR*/ \ - SAR_ ## size ## _IMM(reg, count); \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SAR ## size2); \ - break; \ - } \ - \ - res_store((uintptr_t)&cpu_state.flags_res, reg); \ - if ((fetchdat & 0xc0) == 0xc0) \ - STORE_REG_ ## size ## _RELEASE(reg); \ - else \ - { \ - LOAD_EA(); \ - MEM_STORE_ADDR_EA_ ## size ## _NO_ABRT(target_seg, reg); \ - } +uint32_t ropC0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropC1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropC1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -static uint32_t ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) -{ - x86seg *target_seg = NULL; - int count; - int reg; +uint32_t ropD0(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropD1_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropD1_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - if ((fetchdat & 0x38) < 0x20) - return 0; +uint32_t ropD2(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropD3_w(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropD3_l(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - SHIFT(B, 8, STORE_HOST_REG_ADDR_BL, 1); - - 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) -{ - x86seg *target_seg = NULL; - int count; - int reg; - - if ((fetchdat & 0x38) < 0x20) - return 0; - - SHIFT(W, 16, STORE_HOST_REG_ADDR_WL, 1); - - 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) -{ - x86seg *target_seg = NULL; - int count; - int reg; - - if ((fetchdat & 0x38) < 0x20) - return 0; - - SHIFT(L, 32, STORE_HOST_REG_ADDR, 1); - - 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) -{ - x86seg *target_seg = NULL; - int count = 1; - int reg; - - if ((fetchdat & 0x38) < 0x20) - return 0; - - SHIFT(B, 8, STORE_HOST_REG_ADDR_BL, 0); - - 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) -{ - x86seg *target_seg = NULL; - int count = 1; - int reg; - - if ((fetchdat & 0x38) < 0x20) - return 0; - - SHIFT(W, 16, STORE_HOST_REG_ADDR_WL, 0); - - 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) -{ - x86seg *target_seg = NULL; - int count = 1; - int reg; - - if ((fetchdat & 0x38) < 0x20) - return 0; - - SHIFT(L, 32, STORE_HOST_REG_ADDR, 0); - - return op_pc + 1; -} +uint32_t ropSHLD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSHLD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSHRD_16_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropSHRD_32_imm(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_stack.c b/src/codegen_ops_stack.c new file mode 100644 index 0000000..c3c8a46 --- /dev/null +++ b/src/codegen_ops_stack.c @@ -0,0 +1,409 @@ +#include "ibm.h" + +#include "x86.h" +#include "x86_flags.h" +#include "386_common.h" +#include "codegen.h" +#include "codegen_ir.h" +#include "codegen_ops.h" +#include "codegen_ops_helpers.h" +#include "codegen_ops_misc.h" + +uint32_t ropPUSH_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_16(opcode & 7)); + SUB_SP(ir, 2); + + return op_pc; +} +uint32_t ropPUSH_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_32(opcode & 7)); + SUB_SP(ir, 4); + + return op_pc; +} + +uint32_t ropPOP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_16(opcode & 7), IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_16(opcode & 7), IREG_SS_base, IREG_eaaddr); + } + if ((opcode & 7) != REG_SP) + ADD_SP(ir, 2); + + return op_pc; +} +uint32_t ropPOP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_32(opcode & 7), IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_32(opcode & 7), IREG_SS_base, IREG_eaaddr); + } + if ((opcode & 7) != REG_ESP) + ADD_SP(ir, 4); + + return op_pc; +} + +uint32_t ropPUSH_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm = fastreadw(cs + op_pc); + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_IMM_16(ir, IREG_SS_base, sp_reg, imm); + SUB_SP(ir, 2); + + codegen_mark_code_present(block, cs+op_pc, 2); + return op_pc + 2; +} +uint32_t ropPUSH_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t imm = fastreadl(cs + op_pc); + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, imm); + SUB_SP(ir, 4); + + codegen_mark_code_present(block, cs+op_pc, 4); + return op_pc + 4; +} + +uint32_t ropPUSH_imm_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint16_t imm = (int16_t)(int8_t)fastreadb(cs + op_pc); + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_IMM_16(ir, IREG_SS_base, sp_reg, imm); + SUB_SP(ir, 2); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} +uint32_t ropPUSH_imm_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uint32_t imm = (int32_t)(int8_t)fastreadb(cs + op_pc); + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_IMM_32(ir, IREG_SS_base, sp_reg, imm); + SUB_SP(ir, 4); + + codegen_mark_code_present(block, cs+op_pc, 1); + return op_pc + 1; +} + +uint32_t ropPOP_W(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_16(fetchdat & 7), IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_16(fetchdat & 7), IREG_SS_base, IREG_eaaddr); + } + } + else + { + x86seg *target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 2); + codegen_check_seg_write(block, ir, target_seg); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_temp0, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_temp0); + } + + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0_W); + } + + if ((fetchdat & 0xc7) != (0xc0 | REG_SP)) + ADD_SP(ir, 2); + + return op_pc + 1; +} +uint32_t ropPOP_L(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + codegen_mark_code_present(block, cs+op_pc, 1); + if ((fetchdat & 0xc0) == 0xc0) + { + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_32(fetchdat & 7), IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_32(fetchdat & 7), IREG_SS_base, IREG_eaaddr); + } + } + else + { + x86seg *target_seg = codegen_generate_ea(ir, op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32, 4); + codegen_check_seg_write(block, ir, target_seg); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_ESP); + else + { + uop_MOVZX(ir, IREG_temp0, IREG_SP); + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_temp0); + } + + uop_MEM_STORE_REG(ir, ireg_seg_base(target_seg), IREG_eaaddr, IREG_temp0); + } + + if ((fetchdat & 0xc7) != (0xc0 | REG_ESP)) + ADD_SP(ir, 4); + + return op_pc + 1; +} + +#define ROP_PUSH_SEG(seg) \ +uint32_t ropPUSH_ ## seg ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int sp_reg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); \ + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_ ## seg ## _seg_W); \ + SUB_SP(ir, 2); \ + \ + return op_pc; \ +} \ +uint32_t ropPUSH_ ## seg ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + int sp_reg; \ + \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); \ + uop_MOVZX(ir, IREG_temp0, IREG_ ## seg ## _seg_W); \ + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_temp0); \ + SUB_SP(ir, 4); \ + \ + return op_pc; \ +} + +#define ROP_POP_SEG(seg, rseg) \ +uint32_t ropPOP_ ## seg ## _16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + \ + if (stack32) \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); \ + else \ + { \ + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); \ + } \ + uop_LOAD_SEG(ir, &rseg, IREG_temp0_W); \ + ADD_SP(ir, 2); \ + \ + return op_pc; \ +} \ +uint32_t ropPOP_ ## seg ## _32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) \ +{ \ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); \ + \ + if (stack32) \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_ESP); \ + else \ + { \ + uop_MOVZX(ir, IREG_eaaddr, IREG_SP); \ + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); \ + } \ + uop_LOAD_SEG(ir, &rseg, IREG_temp0_W); \ + ADD_SP(ir, 4); \ + \ + return op_pc; \ +} + + +ROP_PUSH_SEG(CS) +ROP_PUSH_SEG(DS) +ROP_PUSH_SEG(ES) +ROP_PUSH_SEG(FS) +ROP_PUSH_SEG(GS) +ROP_PUSH_SEG(SS) +ROP_POP_SEG(DS, cpu_state.seg_ds) +ROP_POP_SEG(ES, cpu_state.seg_es) +ROP_POP_SEG(FS, cpu_state.seg_fs) +ROP_POP_SEG(GS, cpu_state.seg_gs) + +uint32_t ropLEAVE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_EBP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_BP); + uop_MEM_LOAD_REG(ir, IREG_temp0_W, IREG_SS_base, IREG_eaaddr); + } + uop_ADD_IMM(ir, IREG_SP, IREG_BP, 2); + uop_MOV(ir, IREG_BP, IREG_temp0_W); + + return op_pc; +} +uint32_t ropLEAVE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + + if (stack32) + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_EBP); + else + { + uop_MOVZX(ir, IREG_eaaddr, IREG_BP); + uop_MEM_LOAD_REG(ir, IREG_temp0, IREG_SS_base, IREG_eaaddr); + } + uop_ADD_IMM(ir, IREG_ESP, IREG_EBP, 4); + uop_MOV(ir, IREG_EBP, IREG_temp0); + + return op_pc; +} + + +uint32_t ropPUSHA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -16); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 14, IREG_AX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 12, IREG_CX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 10, IREG_DX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 8, IREG_BX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 6, IREG_SP); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 4, IREG_BP); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 2, IREG_SI); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_DI); + SUB_SP(ir, 16); + + return op_pc; +} +uint32_t ropPUSHA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -32); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 28, IREG_EAX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 24, IREG_ECX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 20, IREG_EDX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 16, IREG_EBX); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 12, IREG_ESP); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 8, IREG_EBP); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 4, IREG_ESI); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_EDI); + SUB_SP(ir, 32); + + return op_pc; +} + +uint32_t ropPOPA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP(ir); + uop_MEM_LOAD_REG(ir, IREG_DI, IREG_SS_base, sp_reg); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_SI, IREG_SS_base, sp_reg, 2); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_BP, IREG_SS_base, sp_reg, 4); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_BX, IREG_SS_base, sp_reg, 8); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_DX, IREG_SS_base, sp_reg, 10); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_CX, IREG_SS_base, sp_reg, 12); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_AX, IREG_SS_base, sp_reg, 14); + ADD_SP(ir, 16); + + return op_pc; +} +uint32_t ropPOPA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + sp_reg = LOAD_SP(ir); + uop_MEM_LOAD_REG(ir, IREG_EDI, IREG_SS_base, sp_reg); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_ESI, IREG_SS_base, sp_reg, 4); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_EBP, IREG_SS_base, sp_reg, 8); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_EBX, IREG_SS_base, sp_reg, 16); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_EDX, IREG_SS_base, sp_reg, 20); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_ECX, IREG_SS_base, sp_reg, 24); + uop_MEM_LOAD_REG_OFFSET(ir, IREG_EAX, IREG_SS_base, sp_reg, 28); + ADD_SP(ir, 32); + + return op_pc; +} + +uint32_t ropPUSHF(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + return 0; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + uop_CALL_FUNC(ir, flags_rebuild); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -2); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_flags); + SUB_SP(ir, 2); + + return op_pc; +} +uint32_t ropPUSHFD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc) +{ + int sp_reg; + + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) + return 0; + + uop_MOV_IMM(ir, IREG_oldpc, cpu_state.oldpc); + uop_CALL_FUNC(ir, flags_rebuild); + + if (cpu_CR4_mask & CR4_VME) + uop_AND_IMM(ir, IREG_temp0_W, IREG_eflags, 0x3c); + else if (CPUID) + uop_AND_IMM(ir, IREG_temp0_W, IREG_eflags, 0x24); + else + uop_AND_IMM(ir, IREG_temp0_W, IREG_eflags, 4); + sp_reg = LOAD_SP_WITH_OFFSET(ir, -4); + uop_MEM_STORE_REG(ir, IREG_SS_base, sp_reg, IREG_flags); + uop_MEM_STORE_REG_OFFSET(ir, IREG_SS_base, sp_reg, 2, IREG_temp0_W); + SUB_SP(ir, 4); + + return op_pc; +} diff --git a/src/codegen_ops_stack.h b/src/codegen_ops_stack.h index 3ea27d3..6b9ac57 100644 --- a/src/codegen_ops_stack.h +++ b/src/codegen_ops_stack.h @@ -1,269 +1,49 @@ -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; +uint32_t ropPUSH_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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; +uint32_t ropPOP_r16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_r32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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); +uint32_t ropPUSH_imm_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_imm_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_imm_16_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_imm_32_8(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - return op_pc; -} +uint32_t ropPOP_W(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_L(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t 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; +uint32_t ropPUSH_CS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_DS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_ES_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_FS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_GS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_SS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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; +uint32_t ropPUSH_CS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_DS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_ES_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_FS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_GS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSH_SS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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; -} +uint32_t ropPOP_DS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_ES_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_FS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_GS_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); -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; +uint32_t ropPOP_DS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_ES_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_FS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOP_GS_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - if (imm & 0x80) - imm |= 0xff00; +uint32_t ropLEAVE_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropLEAVE_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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; +uint32_t ropPUSHA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSHA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - if (imm & 0x80) - imm |= 0xffffff00; +uint32_t ropPOPA_16(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPOPA_32(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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) -{ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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) -{ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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) -{ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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) -{ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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; - - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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; - - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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)&cpu_state.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(FS) -ROP_PUSH_SEG(GS) -ROP_PUSH_SEG(SS) - -#define ROP_POP_SEG(seg, rseg) \ -static uint32_t ropPOP_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ -{ \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - LOAD_STACK_TO_EA(0); \ - MEM_LOAD_ADDR_EA_W(&_ss); \ - LOAD_SEG(0, &rseg); \ - SP_MODIFY(2); \ - \ - return op_pc; \ -} \ -static uint32_t ropPOP_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ -{ \ - STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ - LOAD_STACK_TO_EA(0); \ - MEM_LOAD_ADDR_EA_W(&_ss); \ - LOAD_SEG(0, &rseg); \ - SP_MODIFY(4); \ - \ - return op_pc; \ -} - -ROP_POP_SEG(DS, _ds) -ROP_POP_SEG(ES, _es) -ROP_POP_SEG(FS, _fs) -ROP_POP_SEG(GS, _gs) +uint32_t ropPUSHF(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); +uint32_t ropPUSHFD(codeblock_t *block, ir_data_t *ir, uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc); diff --git a/src/codegen_ops_x86-64.h b/src/codegen_ops_x86-64.h deleted file mode 100644 index 76f142c..0000000 --- a/src/codegen_ops_x86-64.h +++ /dev/null @@ -1,6138 +0,0 @@ -/*Register allocation : - R8-R15 - emulated registers -*/ -#include - -#define HOST_REG_XMM_START 0 -#define HOST_REG_XMM_END 7 - -#define IS_32_ADDR(x) !(((uintptr_t)x) & 0xffffffff00000000) - -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 inline void call(codeblock_t *block, uintptr_t func) -{ - uintptr_t diff = func - (uintptr_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 inline 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 inline 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 inline 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 -} -#if 0 -static inline 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); -} -#endif - -static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline void RELEASE_REG(int host_reg) -{ -} - -static inline 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(cpu_state_offset(regs[host_reg & 3].b)); - } - - codegen_reg_loaded[reg & 3] = 1; - - if (reg & 4) - return host_reg | 0x18; - - return host_reg | 8; -} -static inline 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(cpu_state_offset(regs[reg & 7].w)); - } - - codegen_reg_loaded[reg & 7] = 1; - - return host_reg | 8; -} -static inline 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(cpu_state_offset(regs[reg & 7].l)); - } - - codegen_reg_loaded[reg & 7] = 1; - - return host_reg | 8; -} - -static inline 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 inline 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(cpu_state_offset(regs[guest_reg & 3].w)); - } - 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(cpu_state_offset(regs[guest_reg & 3].b)); - } - 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(cpu_state_offset(regs[guest_reg & 3].b)); - } - } - 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(cpu_state_offset(regs[guest_reg & 3].b)); - } - } -} -static inline 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(cpu_state_offset(regs[guest_reg & 7].w)); - } - 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(cpu_state_offset(regs[guest_reg & 7].w)); - } -} -static inline 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(cpu_state_offset(regs[guest_reg & 7].l)); - } - 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(cpu_state_offset(regs[guest_reg & 7].l)); - } -} - -static inline 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(cpu_state_offset(regs[host_reg & 7].w)); - } - else - { - addbyte(0x44); /*MOVB [reg],host_reg*/ - addbyte(0x88); - addbyte(0x45 | ((host_reg & 7) << 3)); - addbyte(cpu_state_offset(regs[host_reg & 7].b)); - } -} -static inline 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(cpu_state_offset(regs[host_reg & 7].w)); -} -static inline void STORE_REG_L_RELEASE(int host_reg) -{ - addbyte(0x44); /*MOVL [reg],host_reg*/ - addbyte(0x89); - addbyte(0x45 | ((host_reg & 7) << 3)); - addbyte(cpu_state_offset(regs[host_reg & 7].l)); -} - -static inline 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(cpu_state_offset(regs[reg & 3].w)); - } - 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(cpu_state_offset(regs[reg & 7].b)); - } -} -static inline 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(cpu_state_offset(regs[reg & 7].w)); -} -static inline 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(cpu_state_offset(regs[reg & 7].l)); -} - -static inline void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) -{ - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - addbyte(0xC7); /*MOVL [addr],val*/ - addbyte(0x45); - addbyte(addr - (uintptr_t)&cpu_state - 128); - addlong(val); - } - else if (addr < 0x100000000) - { - addbyte(0xC7); /*MOVL [addr],val*/ - addbyte(0x04); - addbyte(0x25); - addlong(addr); - addlong(val); - } - else - { - addbyte(0x48); /*MOV ESI, &addr*/ - addbyte(0xb8 | REG_ESI); - addquad(addr); - addbyte(0xc7); /*MOVL [ESI], val*/ - addbyte(0x00 | REG_ESI); - addlong(val); - } -} - - - - -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 inline 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 inline 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; - - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x83); /*CMP seg->base, -1*/ - addbyte(0x3c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - addbyte(-1); - } - else - { - addbyte(0x48); /*MOV RSI, &addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x83); /*CMP RSI, -1*/ - addbyte(0xe8 | REG_ESI); - addbyte(0xff); - } - addbyte(0x0f); /*JE end*/ - addbyte(0x84); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - - seg->checked = 1; -} -static inline 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; - - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x83); /*CMP seg->base, -1*/ - addbyte(0x3c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - addbyte(-1); - } - else - { - addbyte(0x48); /*MOV RSI, &addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x83); /*CMP RSI, -1*/ - addbyte(0xe8 | REG_ESI); - addbyte(0xff); - } - addbyte(0x0f); /*JE end*/ - addbyte(0x84); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - - seg->checked = 1; -} -static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0xb8 | REG_ESI); /*MOV ESI, &addr*/ - addlong((uint32_t)(uintptr_t)seg); - } - else - { - addbyte(0x48); /*MOV RSI, &addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)seg); - } - addbyte(0x3b); /*CMP EAX, seg->limit_low*/ - addbyte(0x46); - addbyte((uintptr_t)&seg->limit_low - (uintptr_t)seg); - 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(0x46); - addbyte((uintptr_t)&seg->limit_high - (uintptr_t)seg); - 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 inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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+4+6); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemb386l); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} -static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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+4+6); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemwl); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} -static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) -{ - addbyte(0x83); /*ADD EAX, offset*/ - addbyte(0xc0); - addbyte(offset); - MEM_LOAD_ADDR_EA_W(seg); -} -static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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+4+6); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemll); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} -static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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+4+6); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemql); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} - -static inline 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 inline 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 inline 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 inline 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; - } - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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+4+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((uintptr_t)writememb386l); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} -static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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+4+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((uintptr_t)writememwl); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} -static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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+4+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((uintptr_t)writememll); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} -static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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+4+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((uintptr_t)writememql); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - /*done:*/ -} - -static inline 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 inline 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 inline 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 inline void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) -{ - int temp_reg = REG_ECX; - - if (host_reg_mapping[REG_ECX] != -1) - temp_reg = REG_EBX; - - if (host_reg & 0x10) - { - if (host_reg & 8) - addbyte(0x41); - addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ - addbyte(0xb7); - addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); - addbyte(0xc1); /*SHR temp_reg, 8*/ - addbyte(0xe8 | temp_reg); - addbyte(8); - } - else - { - if (host_reg & 8) - addbyte(0x41); - addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ - addbyte(0xb6); - addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); - } - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - addbyte(0x89); /*MOV addr, temp_reg*/ - addbyte(0x45 | (temp_reg << 3)); - addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); - } - else if (IS_32_ADDR(addr)) - { - addbyte(0x89); /*MOV addr, temp_reg*/ - addbyte(0x04 | (temp_reg << 3)); - addbyte(0x25); - addlong(addr); - } - else - { - addbyte(0x48); /*MOV RSI, addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)addr); - addbyte(0x89); /*MOV [RSI], temp_reg*/ - addbyte(0x06 | (temp_reg << 3)); - } -} -static inline void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) -{ - int temp_reg = REG_ECX; - - if (host_reg_mapping[REG_ECX] != -1) - temp_reg = REG_EBX; - - if (host_reg & 8) - addbyte(0x41); - addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ - addbyte(0xb7); - addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - addbyte(0x89); /*MOV addr, temp_reg*/ - addbyte(0x45 | (temp_reg << 3)); - addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); - } - else if (IS_32_ADDR(addr)) - { - addbyte(0x89); /*MOV addr, temp_reg*/ - addbyte(0x04 | (temp_reg << 3)); - addbyte(0x25); - addlong(addr); - } - else - { - addbyte(0x48); /*MOV RSI, addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)addr); - addbyte(0x89); /*MOV [RSI], temp_reg*/ - addbyte(0x06 | (temp_reg << 3)); - } -} -static inline void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) -{ - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - 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)(uintptr_t)&cpu_state - 128); - } - else if (IS_32_ADDR(addr)) - { - addbyte(0x66); - if (host_reg & 8) - addbyte(0x44); - addbyte(0x89); /*MOVW addr,host_reg*/ - addbyte(0x04 | ((host_reg & 7) << 3)); - addbyte(0x25); - addlong(addr); - } - else - { - addbyte(0x48); /*MOV RSI, addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)addr); - - addbyte(0x66); - if (host_reg & 8) - addbyte(0x44); - addbyte(0x89); /*MOVW [RSI],host_reg*/ - addbyte(0x06 | ((host_reg & 7) << 3)); - } -} -static inline void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) -{ - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - if (host_reg & 8) - addbyte(0x44); - addbyte(0x89); /*MOVL [addr],host_reg*/ - addbyte(0x45 | ((host_reg & 7) << 3)); - addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); - } - else if (IS_32_ADDR(addr)) - { - if (host_reg & 8) - addbyte(0x44); - addbyte(0x89); /*MOVL addr,host_reg*/ - addbyte(0x04 | ((host_reg & 7) << 3)); - addbyte(0x25); - addlong(addr); - } - else - { - addbyte(0x48); /*MOV RSI, addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)addr); - - if (host_reg & 8) - addbyte(0x44); - addbyte(0x89); /*MOVL [RSI],host_reg*/ - addbyte(0x06 | ((host_reg & 7) << 3)); - } -} - -static inline 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)); - } - } -} -static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 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(0x08); /*ORB dst_reg, EBX*/ - addbyte(0xd8 | (dst_reg & 7)); - } - else - { - addbyte(0x44); /*ORB dst_reg, src_reg*/ - addbyte(0x08); - 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(0x08); /*ORB dst_reg, EBX*/ - addbyte(0xd8 | (dst_reg & 7)); - } - else - { - addbyte(0x08); /*ORB dst_reg, src_reg*/ - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } - } -} -static inline 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 if (src_reg & 8) - { - addbyte(0x66); /*ORW dst_reg, src_reg*/ - addbyte(0x44); - addbyte(0x09); - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } - else - { - addbyte(0x66); /*ORW dst_reg, src_reg*/ - addbyte(0x09); - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } -} -static inline 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 if (src_reg & 8) - { - addbyte(0x44); /*ORL dst_reg, src_reg*/ - addbyte(0x09); - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } - else - { - addbyte(0x09); /*ORW dst_reg, src_reg*/ - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } -} -static inline 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 - { - addbyte(0x81); /*ORL host_reg, imm*/ - addbyte(0xc8 | (host_reg & 7)); - addlong(imm); - } -// fatal("OR to bad register\n"); -} - -static inline 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 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(0x30); /*XORB dst_reg, EBX*/ - addbyte(0xd8 | (dst_reg & 7)); - } - else - { - addbyte(0x44); /*XORB dst_reg, src_reg*/ - addbyte(0x30); - 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(0x30); /*XORB dst_reg, EBX*/ - addbyte(0xd8 | (dst_reg & 7)); - } - else - { - addbyte(0x30); /*XORB dst_reg, src_reg*/ - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } - } -} -static inline 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 if (src_reg & 8) - { - addbyte(0x66); /*XORW dst_reg, src_reg*/ - addbyte(0x44); - addbyte(0x31); - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } - else - { - addbyte(0x66); /*XORW dst_reg, src_reg*/ - addbyte(0x31); - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } -} -static inline 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 if (src_reg & 8) - { - addbyte(0x44); /*XORW dst_reg, src_reg*/ - addbyte(0x31); - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } - else - { - addbyte(0x31); /*XORW dst_reg, src_reg*/ - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } -} -static inline 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 - { - addbyte(0x81); /*ORL host_reg, imm*/ - addbyte(0xf0 | (host_reg & 7)); - addlong(imm); - } -// fatal("XOR to bad register\n"); -} - -static inline 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 if (src_reg & 8) - { - 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(0x00); /*ADDB dst_reg, AL*/ - addbyte(0xc0 | (dst_reg & 7)); - } - else - { - addbyte(0x44); /*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 inline 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 if (src_reg & 8) - { - addbyte(0x66); /*ADDW dst_reg, src_reg*/ - addbyte(0x44); - addbyte(0x01); - addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); - } - else - fatal("!(dst_reg & src_reg & 8)\n"); -} -static inline 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 if (src_reg & 8) - { - addbyte(0x44); /*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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) -{ - if (host_reg & 0x10) - { - addbyte(0x66); /*ADDW host_reg, imm*/ - if (host_reg & 8) - addbyte(0x41); - addbyte(0x81); - addbyte(0xC0 | (host_reg & 7)); - addword(imm << 8); - } - else - { - if (host_reg & 8) - addbyte(0x41); - addbyte(0x80); /*ADDB host_reg, imm*/ - addbyte(0xC0 | (host_reg & 7)); - addbyte(imm); - } -} -static inline void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) -{ - addbyte(0x66); /*ADDW host_reg, imm*/ - if (host_reg & 8) - addbyte(0x41); - addbyte(0x81); - addbyte(0xC0 | (host_reg & 7)); - addword(imm); -} -static inline void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) -{ - if (host_reg & 8) - addbyte(0x41); - addbyte(0x81); /*ADDL host_reg, imm*/ - addbyte(0xC0 | (host_reg & 7)); - addlong(imm); -} - -static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline void LOAD_STACK_TO_EA(int off) -{ - if (stack32) - { - addbyte(0x8b); /*MOVL EAX,[ESP]*/ - addbyte(0x45 | (REG_EAX << 3)); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); - 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((uint8_t)cpu_state_offset(regs[REG_ESP].w)); - if (off) - { - addbyte(0x66); /*ADD AX, off*/ - addbyte(0x05); - addword(off); - } - } -} -static inline void LOAD_EBP_TO_EA(int off) -{ - if (stack32) - { - addbyte(0x8b); /*MOVL EAX,[EBP]*/ - addbyte(0x45 | (REG_EAX << 3)); - addbyte((uint8_t)cpu_state_offset(regs[REG_EBP].l)); - 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((uint8_t)cpu_state_offset(regs[REG_BP].l)); - if (off) - { - addbyte(0x66); /*ADD AX, off*/ - addbyte(0x05); - addword(off); - } - } -} - -static inline void SP_MODIFY(int off) -{ - if (stack32) - { - if (off < 0x80) - { - addbyte(0x83); /*ADD [ESP], off*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); - addbyte(off); - } - else - { - addbyte(0x81); /*ADD [ESP], off*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); - addlong(off); - } - } - else - { - if (off < 0x80) - { - addbyte(0x66); /*ADD [SP], off*/ - addbyte(0x83); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); - addbyte(off); - } - else - { - addbyte(0x66); /*ADD [SP], off*/ - addbyte(0x81); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); - addword(off); - } - } -} - -static inline 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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(new_pc); - if (taken_cycles) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(taken_cycles); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} -static inline 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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(new_pc); - if (taken_cycles) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(taken_cycles); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} - -static inline 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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(new_pc); - if (taken_cycles) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(taken_cycles); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} -static inline 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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(new_pc); - if (taken_cycles) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(taken_cycles); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} - -static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) -{ - uint8_t *jump1; - - if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) - { - addbyte(0x83); /*CMP flags_res, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(flags_res)); - addbyte(0); - addbyte(0x74); /*JZ +*/ - } - else - { - CALL_FUNC((uintptr_t)ZF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - addbyte(0x75); /*JNZ +*/ - } - jump1 = &codeblock[block_current].data[block_pos]; - addbyte(0); - CALL_FUNC((uintptr_t)CF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - if (not) - addbyte(0x75); /*JNZ +*/ - else - addbyte(0x74); /*JZ +*/ - addbyte(7+5+(timing_bt ? 4 : 0)); - - if (!not) - *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(op_pc+pc_offset+offset); - if (timing_bt) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(timing_bt); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - if (not) - *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; -} - -static inline void BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) -{ - CALL_FUNC((uintptr_t)NF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - addbyte(0x0f); /*SETNE BL*/ - addbyte(0x95); - addbyte(0xc3); - CALL_FUNC((uintptr_t)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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(op_pc+pc_offset+offset); - if (timing_bt) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(timing_bt); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} - -static inline void BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) -{ - uint8_t *jump1; - if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) - { - addbyte(0x83); /*CMP flags_res, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(flags_res)); - addbyte(0); - addbyte(0x74); /*JZ +*/ - } - else - { - CALL_FUNC((uintptr_t)ZF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - addbyte(0x75); /*JNZ +*/ - } - jump1 = &codeblock[block_current].data[block_pos]; - addbyte(0); - CALL_FUNC((uintptr_t)NF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - addbyte(0x0f); /*SETNE BL*/ - addbyte(0x95); - addbyte(0xc3); - CALL_FUNC((uintptr_t)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 ? 4 : 0)); - if (!not) - *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(op_pc+pc_offset+offset); - if (timing_bt) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(timing_bt); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - if (not) - *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; -} - -static inline int LOAD_VAR_W(uintptr_t addr) -{ - int host_reg = REG_EBX; - - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - addbyte(0x0f); /*MOVZX host_reg, offset[cpu_state]*/ - addbyte(0xb7); - addbyte(0x45 | (host_reg << 3)); - addbyte(addr - (uintptr_t)&cpu_state - 128); - } - else if (IS_32_ADDR(addr)) - { - addbyte(0x0f); /*MOVZX host_reg,[reg]*/ - addbyte(0xb7); - addbyte(0x04 | (host_reg << 3)); - addbyte(0x25); - addlong((uint32_t)addr); - } - else - { - addbyte(0x48); /*MOV host_reg, &addr*/ - addbyte(0xb8 | host_reg); - addquad(addr); - addbyte(0x0f); /*MOVZX host_reg, [host_reg]*/ - addbyte(0xb7); - addbyte(host_reg | (host_reg << 3)); - } - - return host_reg; -} -static inline int LOAD_VAR_WL(uintptr_t addr) -{ - return LOAD_VAR_W(addr); -} -static inline int LOAD_VAR_L(uintptr_t addr) -{ - int host_reg = REG_EBX; - - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - addbyte(0x8b); /*MOVL host_reg, offset[cpu_state]*/ - addbyte(0x45 | (host_reg << 3)); - addbyte(addr - (uintptr_t)&cpu_state - 128); - } - else if (IS_32_ADDR(addr)) - { - addbyte(0x8b); /*MOVL host_reg,[reg]*/ - addbyte(0x04 | (host_reg << 3)); - addbyte(0x25); - addlong((uint32_t)addr); - } - else - { - addbyte(0x48); /*MOV host_reg, &addr*/ - addbyte(0xb8 | host_reg); - addquad(addr); - addbyte(0x8b); /*MOVL host_reg, [host_reg]*/ - addbyte(host_reg | (host_reg << 3)); - } - - return host_reg; -} - -static inline 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 inline int LOAD_HOST_REG(int host_reg) -{ - if (host_reg & 8) - addbyte(0x44); - addbyte(0x89); - addbyte(0xc0 | REG_EBX | ((host_reg & 7) << 3)); - - return REG_EBX | (host_reg & 0x10); -} - -static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline void NEG_HOST_REG_W(int reg) -{ - addbyte(0x66); - if (reg & 8) - addbyte(0x41); - addbyte(0xf7); - addbyte(0xd8 | (reg & 7)); -} -static inline void NEG_HOST_REG_L(int reg) -{ - if (reg & 8) - addbyte(0x41); - addbyte(0xf7); - addbyte(0xd8 | (reg & 7)); -} - - -static inline void FP_ENTER() -{ - if (codegen_fpu_entered) - return; - if (IS_32_ADDR(&cr0)) - { - addbyte(0xf6); /*TEST cr0, 0xc*/ - addbyte(0x04); - addbyte(0x25); - addlong((uintptr_t)&cr0); - addbyte(0x0c); - } - else - { - addbyte(0x48); /*MOV RAX, &cr0*/ - addbyte(0xb8 | REG_EAX); - addquad((uint64_t)&cr0); - addbyte(0xf6); /*TEST [RAX], 0xc*/ - addbyte(0 | (REG_EAX << 3)); - addbyte(0x0c); - } - addbyte(0x74); /*JZ +*/ - addbyte(7+5+12+5); - addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(oldpc)); - addlong(op_old_pc); - load_param_1_32(&codeblock[block_current], 7); - CALL_FUNC((uintptr_t)x86_int); - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - - codegen_fpu_entered = 1; -} - -static inline void FP_FXCH(int reg) -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - addbyte(0x83); /*ADD EAX, reg*/ - addbyte(0xc0); - addbyte(reg); - - addbyte(0x48); /*MOV RDX, ST[RBX*8]*/ - addbyte(0x8b); - addbyte(0x54); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x83); /*AND EAX, 7*/ - addbyte(0xe0); - addbyte(0x07); - addbyte(0x48); /*MOV RCX, ST[RAX*8]*/ - addbyte(0x8b); - addbyte(0x4c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x48); /*MOV ST[RAX*8], RDX*/ - addbyte(0x89); - addbyte(0x54); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x48); /*MOV ST[RBX*8], RCX*/ - addbyte(0x89); - addbyte(0x4c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - - addbyte(0x8a); /*MOV CL, tag[EAX]*/ - addbyte(0x4c); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag)); - addbyte(0x8a); /*MOV DL, tag[EBX]*/ - addbyte(0x54); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); - addbyte(0x88); /*MOV tag[EBX], CL*/ - addbyte(0x4c); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); - addbyte(0x88); /*MOV tag[EAX], DL*/ - addbyte(0x54); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag)); - - addbyte(0x48); /*MOV RDX, MM[RBX*8]*/ - addbyte(0x8b); - addbyte(0x54); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x48); /*MOV RCX, MM[RAX*8]*/ - addbyte(0x8b); - addbyte(0x4c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x48); /*MOV MM[RAX*8], RDX*/ - addbyte(0x89); - addbyte(0x54); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x48); /*MOV MM[RBX*8], RCX*/ - addbyte(0x89); - addbyte(0x4c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - reg = reg; -} - - - -static inline void FP_FLD(int reg) -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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(0x4c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x83); /*AND EBX, 7*/ - addbyte(0xe3); - addbyte(0x07); - addbyte(0x48); /*MOV RDX, ST_i64[EAX*8]*/ - addbyte(0x8b); - addbyte(0x54); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x8a); /*MOV AL, [tag+EAX]*/ - addbyte(0x44); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag)); - addbyte(0x48); /*MOV ST[EBX*8], RCX*/ - addbyte(0x89); - addbyte(0x4c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x48); /*MOV ST_i64[EBX*8], RDX*/ - addbyte(0x89); - addbyte(0x54); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x88); /*MOV [tag+EBX], AL*/ - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); - - addbyte(0x89); /*MOV [TOP], EBX*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); -} - -static inline void FP_FST(int reg) -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ - addbyte(0x8b); - addbyte(0x4c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x8a); /*MOV BL, [tag+EAX]*/ - addbyte(0x5c); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(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(0x4c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x88); /*MOV [tag+EAX], BL*/ - addbyte(0x5c); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag)); -} - -static inline void FP_POP() -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xc6); /*MOVB tag[EAX], 3*/ - addbyte(0x44); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(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(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); -} -static inline void FP_POP2() -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xc6); /*MOVB tag[EAX], 3*/ - addbyte(0x44); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag)); - addbyte(3); - addbyte(0x83); /*ADD AL, 2*/ - addbyte(0xc0); - addbyte(2); - addbyte(0x83); /*AND AL, 7*/ - addbyte(0xe0); - addbyte(7); - addbyte(0x89); /*MOV [TOP], EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); -} - -static inline void FP_LOAD_S() -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0f); /*SETE [tag+EBX]*/ - addbyte(0x94); - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); -} -static inline void FP_LOAD_D() -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x48); /*MOVQ [ST+EBX*8], RAX*/ - addbyte(0x89); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0f); /*SETE [tag+EBX]*/ - addbyte(0x94); - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); -} - -static inline void FP_LOAD_IW() -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0f); /*SETE [tag+EBX]*/ - addbyte(0x94); - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); -} -static inline void FP_LOAD_IL() -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0f); /*SETE [tag+EBX]*/ - addbyte(0x94); - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); -} -static inline void FP_LOAD_IQ() -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x89); /*MOV TOP, EBX*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x0f); /*SETE AL*/ - addbyte(0x94); - addbyte(0xc0); - addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0c); /*OR AL, TAG_UINT64*/ - addbyte(TAG_UINT64); - addbyte(0x88); /*MOV [tag+EBX], AL*/ - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); -} - -static inline void FP_LOAD_IMM_Q(uint64_t v) -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x83); /*SUB EBX, 1*/ - addbyte(0xeb); - addbyte(0x01); - addbyte(0x83); /*AND EBX, 7*/ - addbyte(0xe3); - addbyte(7); - addbyte(0xc7); /*MOV ST[EBP+EBX*8], v*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addlong(v & 0xffffffff); - addbyte(0xc7); /*MOV ST[EBP+EBX*8]+4, v*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST) + 4); - addlong(v >> 32); - addbyte(0x89); /*MOV TOP, EBX*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xc6); /*MOV [tag+EBX], (v ? 0 : 1)*/ - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag)); - addbyte(v ? 0 : 1); -} - -static inline void FP_FCHS() -{ - addbyte(0x8b); /*MOV EAX, TOP*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xf2); /*SUBSD XMM0, XMM0*/ - addbyte(0x0f); - addbyte(0x5c); - addbyte(0xc0); - addbyte(0xf2); /*SUBSD XMM0, ST[EAX*8]*/ - addbyte(0x0f); - addbyte(0x5c); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xf2); /*MOVSD ST[EAX*8], XMM0*/ - addbyte(0x0f); - addbyte(0x11); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); -} - -static inline int FP_LOAD_REG(int reg) -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(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 inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - - *host_reg1 = REG_EBX; -} -static inline int64_t x87_fround(double b) -{ - int64_t a, c; - - switch ((cpu_state.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; - } - - return 0; -} -static inline int FP_LOAD_REG_INT_W(int reg) -{ - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - - CALL_FUNC((uintptr_t)x87_fround); - - addbyte(0x93); /*XCHG EBX, EAX*/ - - return REG_EBX; -} -static inline int FP_LOAD_REG_INT(int reg) -{ - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - - CALL_FUNC((uintptr_t)x87_fround); - - addbyte(0x93); /*XCHG EBX, EAX*/ - - return REG_EBX; -} -static inline 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(0x45); - addbyte((uint8_t)cpu_state_offset(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[cpu_state.TOP] && (cpu_state.tag[cpu_state.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(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(MM)); - - addbyte(0x48); /*XCHG RBX, RAX*/ - addbyte(0x93); - - *host_reg1 = REG_EBX; - - return; - } - - addbyte(0xf6); /*TEST TAG[EAX], TAG_UINT64*/ - addbyte(0x44); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag)); - addbyte(TAG_UINT64); - - addbyte(0x74); /*JZ +*/ - addbyte(5+2); - - addbyte(0x48); /*MOV RAX, [ST_i64+EAX*8]*/ - addbyte(0x8b); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(MM)); - - addbyte(0xeb); /*JMP done*/ - addbyte(6+12); - - addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - - CALL_FUNC((uintptr_t)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 inline void FP_OP_REG(int op, int dst, int src) -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - 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); - } - addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag)); - addbyte(~TAG_UINT64); - if (op == FPU_DIVR || op == FPU_SUBR) - { - addbyte(0xf3); /*MOVQ XMM0, ST[RBX*8]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - } - else - { - addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - } - switch (op) - { - case FPU_ADD: - addbyte(0xf2); /*ADDSD XMM0, ST[RBX*8]*/ - addbyte(0x0f); - addbyte(0x58); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - break; - case FPU_DIV: - addbyte(0xf2); /*DIVSD XMM0, ST[RBX*8]*/ - addbyte(0x0f); - addbyte(0x5e); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - break; - case FPU_DIVR: - addbyte(0xf2); /*DIVSD XMM0, ST[RAX*8]*/ - addbyte(0x0f); - addbyte(0x5e); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - break; - case FPU_MUL: - addbyte(0xf2); /*MULSD XMM0, ST[RBX*8]*/ - addbyte(0x0f); - addbyte(0x59); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - break; - case FPU_SUB: - addbyte(0xf2); /*SUBSD XMM0, ST[RBX*8]*/ - addbyte(0x0f); - addbyte(0x5c); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - break; - case FPU_SUBR: - addbyte(0xf2); /*SUBSD XMM0, ST[RAX*8]*/ - addbyte(0x0f); - addbyte(0x5c); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - break; - } - addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); -} - -static inline void FP_OP_MEM(int op) -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(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 ST[RAX*8], XMM1*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x4c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - } - else - { - addbyte(0x66); /*MOVQ ST[RAX*8], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - } -} - -static inline 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 inline void FP_OP_D(int op) -{ - addbyte(0x66); /*MOVQ XMM1, RAX*/ - addbyte(0x48); - addbyte(0x0f); - addbyte(0x6e); - addbyte(0xc8); - if (((cpu_state.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((cpu_state.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 (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) - { - addbyte(0x0f); /*LDMXCSR [RSP+8]*/ - addbyte(0xae); - addbyte(0x54); - addbyte(0x24); - addbyte(0x08); - } -} -static inline 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 inline 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 inline void FP_COMPARE_REG(int dst, int src) -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - 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(0x4d); - addbyte((uint8_t)cpu_state_offset(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, ST[RBX*8]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x66); /*COMISD XMM0, ST[RAX*8]*/ - addbyte(0x0f); - addbyte(0x2f); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - } - else - { - addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x66); /*COMISD XMM0, ST[RBX*8]*/ - addbyte(0x0f); - addbyte(0x2f); - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - } - - 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(0x4d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); -} - -static inline void FP_COMPARE_MEM() -{ - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - - addbyte(0x8a); /*MOV CL, [npxs+1]*/ - addbyte(0x4d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); -// addbyte(0xdb); /*FCLEX*/ -// addbyte(0xe2); - addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - 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(0x4d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); -} -static inline 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 inline void FP_COMPARE_D() -{ - addbyte(0x66); /*MOVQ XMM1, RAX*/ - addbyte(0x48); - addbyte(0x0f); - addbyte(0x6e); - addbyte(0xc8); - FP_COMPARE_MEM(); -} -static inline 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 inline void FP_COMPARE_IL() -{ - addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ - addbyte(0x0f); - addbyte(0x2a); - addbyte(0xc8); - FP_COMPARE_MEM(); -} - -static inline void UPDATE_NPXC(int reg) -{ -} - -static inline void SET_BITS(uintptr_t addr, uint32_t val) -{ - if (IS_32_ADDR(addr)) - { - if (val & ~0xff) - { - addbyte(0x81); /*OR [addr], val*/ - addbyte(0x0c); - addbyte(0x25); - addlong(addr); - addlong(val); - } - else - { - addbyte(0x80); /*OR [addr], val*/ - addbyte(0x0c); - addbyte(0x25); - addlong(addr); - addbyte(val); - } - } - else - { - addbyte(0x48); /*MOV RAX, &addr*/ - addbyte(0xb8 | REG_EAX); - addquad(addr); - if (val & ~0xff) - { - addbyte(0x81); /*OR [RAX], val*/ - addbyte(0x08); - addlong(val); - } - else - { - addbyte(0x80); /*OR [RAX], val*/ - addbyte(0x08); - addbyte(val); - } - } -} - -static inline void CLEAR_BITS(uintptr_t addr, uint32_t val) -{ - if (IS_32_ADDR(addr)) - { - if (val & ~0xff) - { - addbyte(0x81); /*AND [addr], val*/ - addbyte(0x24); - addbyte(0x25); - addlong(addr); - addlong(~val); - } - else - { - addbyte(0x80); /*AND [addr], val*/ - addbyte(0x24); - addbyte(0x25); - addlong(addr); - addbyte(~val); - } - } - else - { - addbyte(0x48); /*MOV RAX, &addr*/ - addbyte(0xb8 | REG_EAX); - addquad(addr); - if (val & ~0xff) - { - addbyte(0x81); /*AND [RAX], val*/ - addbyte(0x20); - addlong(~val); - } - else - { - addbyte(0x80); /*AND [RAX], val*/ - addbyte(0x20); - addbyte(~val); - } - } -} - -#define LOAD_Q_REG_1 REG_EAX -#define LOAD_Q_REG_2 REG_EDX - -static inline void MMX_ENTER() -{ - if (codegen_mmx_entered) - return; - - if (IS_32_ADDR(&cr0)) - { - addbyte(0xf6); /*TEST cr0, 0xc*/ - addbyte(0x04); - addbyte(0x25); - addlong((uintptr_t)&cr0); - addbyte(0x0c); - } - else - { - addbyte(0x48); /*MOV RAX, &cr0*/ - addbyte(0xb8 | REG_EAX); - addquad((uint64_t)&cr0); - addbyte(0xf6); /*TEST [RAX], 0xc*/ - addbyte(0 | (REG_EAX << 3)); - addbyte(0x0c); - } - addbyte(0x74); /*JZ +*/ - addbyte(7+5+12+5); - addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(oldpc)); - addlong(op_old_pc); - load_param_1_32(&codeblock[block_current], 7); - CALL_FUNC((uintptr_t)x86_int); - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); - - - addbyte(0x31); /*XOR EAX, EAX*/ - addbyte(0xc0); - addbyte(0xc6); /*MOV ISMMX, 1*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ismmx)); - addbyte(1); - addbyte(0x89); /*MOV TOP, EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV tag, EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(0x89); /*MOV tag+4, EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[4])); - - codegen_mmx_entered = 1; -} - -extern int mmx_ebx_ecx_loaded; - -static inline int LOAD_MMX_D(int guest_reg) -{ - int host_reg = REG_EBX; - - addbyte(0x8b); /*MOV EBX, reg*/ - addbyte(0x44 | (host_reg << 3)); - addbyte(0x25); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); - - return host_reg; -} -static inline 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(0x44 | ((host_reg & 7) << 3)); - addbyte(0x25); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); - - *host_reg1 = host_reg; -} -static inline 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(0x44 | ((dst_reg & 7) << 3)); - addbyte(0x25); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); - - return dst_reg; -} - -static inline 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 inline void STORE_MMX_LQ(int guest_reg, int host_reg1) -{ - addbyte(0xC7); /*MOVL [reg],0*/ - addbyte(0x44); - addbyte(0x25); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); - addlong(0); - if (host_reg1 & 8) - addbyte(0x44); - addbyte(0x89); /*MOVL [reg],host_reg*/ - addbyte(0x44 | ((host_reg1 & 7) << 3)); - addbyte(0x25); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); -} -static inline 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(0x44 | ((host_reg1 & 7) << 3)); - addbyte(0x25); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); -} -static inline void STORE_MMX_Q_MMX(int guest_reg, int host_reg) -{ - addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x44 | (host_reg << 3)); - addbyte(0x25); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); -} - -#define MMX_x86_OP(name, opcode) \ -static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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); -} - - -static inline void SAVE_EA() -{ - addbyte(0x89); /*MOV [ESP+0x24], EAX*/ - addbyte(0x44); - addbyte(0x24); - addbyte(0x24); -} -static inline void LOAD_EA() -{ - addbyte(0x8b); /*MOV EAX, [ESP+0x24]*/ - addbyte(0x44); - addbyte(0x24); - addbyte(0x24); -} - -#define MEM_CHECK_WRITE_B MEM_CHECK_WRITE - -static inline void MEM_CHECK_WRITE(x86seg *seg) -{ - uint8_t *jump1, *jump2, *jump3; - - CHECK_SEG_WRITE(seg); - - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOV ESI, seg->base*/ - addbyte(0x34); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ESI, [RSI]*/ - addbyte(0x36); - } - - - /*seg = ESI, addr = EAX*/ - - if (IS_32_ADDR(&cr0)) - { - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&cr0); - addbyte(0); - } - else - { - addbyte(0x48); /*MOV RDI, &cr0*/ - addbyte(0xbf); - addquad((uint64_t)&cr0); - addbyte(0x83); /*CMPL [RDI], 0*/ - addbyte(0x3f); - addbyte(0); - } - addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ - addbyte(0x8d); - addbyte(0x3c); - addbyte(0x30); - addbyte(0x79); /*JNS +*/ - jump1 = &codeblock[block_current].data[block_pos]; - addbyte(0); -// addbyte(0xc3); /*RET*/ - addbyte(0xc1); /*SHR EDI, 12*/ - addbyte(0xef); - addbyte(12); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - jump3 = &codeblock[block_current].data[block_pos]; - addbyte(0); - if (IS_32_ADDR(writelookup2)) - { - addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ - addbyte(0x3c); - addbyte(0xfd); - addlong((uint32_t)(uintptr_t)writelookup2); - addbyte(-1); - } - else - { - addbyte(0x48); /*MOV RCX, writelookup2*/ - addbyte(0xb9); - addquad((uint64_t)writelookup2); - addbyte(0x83); /*CMP [RCX+RDI*8], -1*/ - addbyte(0x3c); - addbyte(0xf9); - addbyte(-1); - } - addbyte(0x75); /*JNE +*/ - jump2 = &codeblock[block_current].data[block_pos]; - addbyte(0); -// addbyte(0xc3); /*RET*/ - - *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; - /*slowpath:*/ - addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ - addbyte(0x8d); - addbyte(0x3c); - addbyte(0x30); - - - load_param_1_reg_32(REG_EDI); - load_param_2_32(&codeblock[block_current], 1); - - -// addbyte(0x6a); /*PUSH 1*/ -// addbyte(1); -// addbyte(0x57); /*PUSH EDI*/ - call(&codeblock[block_current], (uintptr_t)mmutranslatereal); -// addbyte(0x48); /*ADD ESP, 8*/ -// addbyte(0x83); -// addbyte(0xc4); -// addbyte(8); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); -// addbyte(0xc3); /*RET*/ - *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; - *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - - - -// addbyte(0xe8); /*CALL mem_store_addr_ea_b*/ -// addlong(mem_check_write - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - LOAD_EA(); -} - -static inline void MEM_CHECK_WRITE_W(x86seg *seg) -{ - uint8_t *jump1, *jump2, *jump3, *jump4; - int jump_pos; - - CHECK_SEG_WRITE(seg); - - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOV ESI, seg->base*/ - addbyte(0x34); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ESI, [RSI]*/ - addbyte(0x36); - } - - - /*seg = ESI, addr = EAX*/ - - if (IS_32_ADDR(&cr0)) - { - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&cr0); - addbyte(0); - } - else - { - addbyte(0x48); /*MOV RDI, &cr0*/ - addbyte(0xbf); - addquad((uint64_t)&cr0); - addbyte(0x83); /*CMPL [RDI], 0*/ - addbyte(0x3f); - addbyte(0); - } - addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ - addbyte(0x8d); - addbyte(0x3c); - addbyte(0x30); - addbyte(0x79); /*JNS +*/ - jump1 = &codeblock[block_current].data[block_pos]; - addbyte(0); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); - addbyte(0x8d); /*LEA ESI, 1[EDI]*/ - addbyte(0x77); - addbyte(0x01); - addbyte(0x74); /*JE slowpath*/ - jump4 = &codeblock[block_current].data[block_pos]; - addbyte(0); - addbyte(0x89); /*MOV EBX, EDI*/ - addbyte(0xfb); - addbyte(0xc1); /*SHR EDI, 12*/ - addbyte(0xef); - addbyte(12); - addbyte(0xc1); /*SHR ESI, 12*/ - addbyte(0xee); - addbyte(12); - if (IS_32_ADDR(writelookup2)) - { - addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ - addbyte(0x3c); - addbyte(0xfd); - addlong((uint32_t)(uintptr_t)writelookup2); - addbyte(-1); - } - else - { - addbyte(0x48); /*MOV RAX, writelookup2*/ - addbyte(0xb8); - addquad((uint64_t)writelookup2); - addbyte(0x83); /*CMP [RAX+RDI*8], -1*/ - addbyte(0x3c); - addbyte(0xf8); - addbyte(-1); - } - addbyte(0x74); /*JE +*/ - jump2 = &codeblock[block_current].data[block_pos]; - addbyte(0); - if (IS_32_ADDR(writelookup2)) - { - addbyte(0x83); /*CMP writelookup2[RSI*8],-1*/ - addbyte(0x3c); - addbyte(0xfd); - addlong((uint32_t)(uintptr_t)writelookup2); - addbyte(-1); - } - else - { - addbyte(0x83); /*CMP [RAX+RSI*8], -1*/ - addbyte(0x3c); - addbyte(0xf0); - addbyte(-1); - } - addbyte(0x75); /*JNE +*/ - jump3 = &codeblock[block_current].data[block_pos]; - addbyte(0); - - /*slowpath:*/ - *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; - jump_pos = block_pos; - load_param_1_reg_32(REG_EBX); - load_param_2_32(&codeblock[block_current], 1); - call(&codeblock[block_current], (uintptr_t)mmutranslatereal); - addbyte(0x83); /*ADD EBX, 1*/ - addbyte(0xc3); - addbyte(1); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); - /*If bits 0-11 of the address are now 0 then this crosses a page, so loop back*/ - addbyte(0xf7); /*TEST $fff, EBX*/ - addbyte(0xc3); - addlong(0xfff); - addbyte(0x74); /*JNE slowpath*/ - addbyte(jump_pos - block_pos - 1); - - *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; - *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; - - LOAD_EA(); -} - -static inline void MEM_CHECK_WRITE_L(x86seg *seg) -{ - uint8_t *jump1, *jump2, *jump3, *jump4; - int jump_pos; - - CHECK_SEG_WRITE(seg); - - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOV ESI, seg->base*/ - addbyte(0x34); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &addr*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ESI, [RSI]*/ - addbyte(0x36); - } - - - /*seg = ESI, addr = EAX*/ - - if (IS_32_ADDR(&cr0)) - { - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&cr0); - addbyte(0); - } - else - { - addbyte(0x48); /*MOV RDI, &cr0*/ - addbyte(0xbf); - addquad((uint64_t)&cr0); - addbyte(0x83); /*CMPL [RDI], 0*/ - addbyte(0x3f); - addbyte(0); - } - addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ - addbyte(0x8d); - addbyte(0x3c); - addbyte(0x30); - addbyte(0x79); /*JNS +*/ - jump1 = &codeblock[block_current].data[block_pos]; - addbyte(0); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); - addbyte(0x8d); /*LEA ESI, 3[EDI]*/ - addbyte(0x77); - addbyte(0x03); - addbyte(0x74); /*JE slowpath*/ - jump4 = &codeblock[block_current].data[block_pos]; - addbyte(0); - addbyte(0x89); /*MOV EBX, EDI*/ - addbyte(0xfb); - addbyte(0xc1); /*SHR EDI, 12*/ - addbyte(0xef); - addbyte(12); - addbyte(0xc1); /*SHR ESI, 12*/ - addbyte(0xee); - addbyte(12); - if (IS_32_ADDR(writelookup2)) - { - addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ - addbyte(0x3c); - addbyte(0xfd); - addlong((uint32_t)(uintptr_t)writelookup2); - addbyte(-1); - } - else - { - addbyte(0x48); /*MOV RAX, writelookup2*/ - addbyte(0xb8); - addquad((uint64_t)writelookup2); - addbyte(0x83); /*CMP [RAX+RDI*8], -1*/ - addbyte(0x3c); - addbyte(0xf8); - addbyte(-1); - } - addbyte(0x74); /*JE slowpath*/ - jump2 = &codeblock[block_current].data[block_pos]; - addbyte(0); - if (IS_32_ADDR(writelookup2)) - { - addbyte(0x83); /*CMP writelookup2[RSI*8],-1*/ - addbyte(0x3c); - addbyte(0xfd); - addlong((uint32_t)(uintptr_t)writelookup2); - addbyte(-1); - } - else - { - addbyte(0x83); /*CMP [RAX+RSI*8], -1*/ - addbyte(0x3c); - addbyte(0xf0); - addbyte(-1); - } - addbyte(0x75); /*JNE +*/ - jump3 = &codeblock[block_current].data[block_pos]; - addbyte(0); - - /*slowpath:*/ - *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; - *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; - jump_pos = block_pos; - load_param_1_reg_32(REG_EBX); - load_param_2_32(&codeblock[block_current], 1); - call(&codeblock[block_current], (uintptr_t)mmutranslatereal); - addbyte(0x83); /*ADD EBX, 3*/ - addbyte(0xc3); - addbyte(3); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); - /*If bits 0-11 of the address are now 0 then this crosses a page, so loop back*/ - addbyte(0xf7); /*TEST $ffc, EBX*/ - addbyte(0xc3); - addlong(0xffc); - addbyte(0x74); /*JE slowpath*/ - addbyte(jump_pos - block_pos - 1); - - *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; - *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; - - LOAD_EA(); -} - -static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemb386l); - addbyte(0x89); /*MOV ECX, EAX*/ - addbyte(0xc1); - /*done:*/ - - host_reg_mapping[REG_ECX] = 8; - - return REG_ECX; -} -static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemwl); - addbyte(0x89); /*MOV ECX, EAX*/ - addbyte(0xc1); - /*done:*/ - - host_reg_mapping[REG_ECX] = 8; - - return REG_ECX; -} -static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL ECX, seg->base*/ - addbyte(0x0c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV ECX, [RSI]*/ - addbyte(0x0e); - } - 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)(uintptr_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); - /*slowpath:*/ - load_param_1_reg_32(REG_ECX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)readmemll); - addbyte(0x89); /*MOV ECX, EAX*/ - addbyte(0xc1); - /*done:*/ - - host_reg_mapping[REG_ECX] = 8; - - return REG_ECX; -} - -static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(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; - } - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL EBX, seg->base*/ - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV EBX, [RSI]*/ - addbyte(0x1e); - } - addbyte(0x67); /*LEA ESI, (EAX,EBX)*/ - addbyte(0x8d); - addbyte(0x34); - addbyte(0x18); - 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)(uintptr_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); - /*slowpath:*/ - load_param_3_reg_32(host_reg); - load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)writememb386l); - /*done:*/ -} -static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL EBX, seg->base*/ - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV EBX, [RSI]*/ - addbyte(0x1e); - } - addbyte(0x67); /*LEA ESI, (EAX,EBX)*/ - addbyte(0x8d); - addbyte(0x34); - addbyte(0x18); - 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)(uintptr_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); - /*slowpath:*/ - load_param_3_reg_32(host_reg); - load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)writememwl); - /*done:*/ -} -static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) -{ - if (IS_32_ADDR(&seg->base)) - { - addbyte(0x8b); /*MOVL EBX, seg->base*/ - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&seg->base); - } - else - { - addbyte(0x48); /*MOV RSI, &seg->base*/ - addbyte(0xb8 | REG_ESI); - addquad((uint64_t)&seg->base); - addbyte(0x8b); /*MOV EBX, [RSI]*/ - addbyte(0x1e); - } - addbyte(0x67); /*LEA ESI, (EAX,EBX)*/ - addbyte(0x8d); - addbyte(0x34); - addbyte(0x18); - 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)(uintptr_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); - /*slowpath:*/ - load_param_3_reg_32(host_reg); - load_param_1_reg_32(REG_EBX); - load_param_2_reg_32(REG_EAX); - call_long((uintptr_t)writememll); - /*done:*/ -} - -static inline void LOAD_SEG(int host_reg, void *seg) -{ - load_param_2_64(&codeblock[block_current], (uint64_t)seg); - load_param_1_reg_32(host_reg); - CALL_FUNC((uintptr_t)loadseg); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} diff --git a/src/codegen_ops_x86.h b/src/codegen_ops_x86.h deleted file mode 100644 index 3581f6e..0000000 --- a/src/codegen_ops_x86.h +++ /dev/null @@ -1,3844 +0,0 @@ -/*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; -} - -#if 0 -static inline void STORE_IMM_ADDR_B(uintptr_t addr, uint8_t val) -{ - addbyte(0xC6); /*MOVB [addr],val*/ - addbyte(0x05); - addlong(addr); - addbyte(val); -} -static inline void STORE_IMM_ADDR_W(uintptr_t addr, uint16_t val) -{ - addbyte(0x66); /*MOVW [addr],val*/ - addbyte(0xC7); - addbyte(0x05); - addlong(addr); - addword(val); -} -#endif -static inline void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) -{ - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - addbyte(0xC7); /*MOVL [addr],val*/ - addbyte(0x45); - addbyte(addr - (uint32_t)&cpu_state - 128); - addlong(val); - } - else - { - addbyte(0xC7); /*MOVL [addr],val*/ - addbyte(0x05); - addlong(addr); - addlong(val); - } -} - -static inline void STORE_IMM_REG_B(int reg, uint8_t val) -{ - addbyte(0xC6); /*MOVB [addr],val*/ - addbyte(0x45); - if (reg & 4) - addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.h)); - else - addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.l)); - addbyte(val); -} -static inline void STORE_IMM_REG_W(int reg, uint16_t val) -{ - addbyte(0x66); /*MOVW [addr],val*/ - addbyte(0xC7); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[reg & 7].w)); - addword(val); -} -static inline void STORE_IMM_REG_L(int reg, uint32_t val) -{ - addbyte(0xC7); /*MOVL [addr],val*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[reg & 7].l)); - addlong(val); -} - -static inline 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((uint8_t)cpu_state_offset(regs[reg & 3].b.h)); - else - addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.l)); - - return host_reg; -} -static inline 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((uint8_t)cpu_state_offset(regs[reg & 7].w)); - - return host_reg; -} -static inline 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((uint8_t)cpu_state_offset(regs[reg & 7].l)); - - return host_reg; -} - -static inline int LOAD_VAR_W(uintptr_t addr) -{ - int host_reg = find_host_reg(); - host_reg_mapping[host_reg] = 0; - - addbyte(0x66); /*MOVL host_reg,[reg]*/ - addbyte(0x8b); - addbyte(0x05 | (host_reg << 3)); - addlong((uint32_t)addr); - - return host_reg; -} -static inline int LOAD_VAR_WL(uintptr_t addr) -{ - int host_reg = find_host_reg(); - host_reg_mapping[host_reg] = 0; - - addbyte(0x0f); /*MOVZX host_reg, [addr]*/ - addbyte(0xb7); - addbyte(0x05 | (host_reg << 3)); - addlong((uint32_t)addr); - - return host_reg; -} -static inline int LOAD_VAR_L(uintptr_t addr) -{ - int host_reg = find_host_reg(); - host_reg_mapping[host_reg] = 0; - - addbyte(0x8b); /*MOVL host_reg,[reg]*/ - addbyte(0x05 | (host_reg << 3)); - addlong((uint32_t)addr); - - return host_reg; -} - -static inline int LOAD_REG_IMM(uint32_t imm) -{ - int host_reg = find_host_reg(); - host_reg_mapping[host_reg] = 0; - - addbyte(0xc7); /*MOVL host_reg, imm*/ - addbyte(0xc0 | host_reg); - addlong(imm); - - return host_reg; -} - -static inline int LOAD_HOST_REG(int host_reg) -{ - int new_host_reg = find_host_reg(); - host_reg_mapping[new_host_reg] = 0; - - addbyte(0x89); /*MOV new_host_reg, host_reg*/ - addbyte(0xc0 | (host_reg << 3) | new_host_reg); - - return new_host_reg; -} - -static inline 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((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg] & 3].b.h)); - else - addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg] & 3].b.l)); - host_reg_mapping[host_reg] = -1; -} -static inline void STORE_REG_W_RELEASE(int host_reg) -{ - addbyte(0x66); /*MOVW [reg],host_reg*/ - addbyte(0x89); - addbyte(0x45 | (host_reg << 3)); - addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg]].w)); - host_reg_mapping[host_reg] = -1; -} -static inline void STORE_REG_L_RELEASE(int host_reg) -{ - addbyte(0x89); /*MOVL [reg],host_reg*/ - addbyte(0x45 | (host_reg << 3)); - addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg]].l)); - host_reg_mapping[host_reg] = -1; -} - -static inline 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((uint8_t)cpu_state_offset(regs[guest_reg & 3].b.h)); - else - addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 3].b.l)); - host_reg_mapping[host_reg] = -1; -} -static inline 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((uint8_t)cpu_state_offset(regs[guest_reg & 7].w)); - host_reg_mapping[host_reg] = -1; -} -static inline 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((uint8_t)cpu_state_offset(regs[guest_reg & 7].l)); - host_reg_mapping[host_reg] = -1; -} - -static inline void RELEASE_REG(int host_reg) -{ - host_reg_mapping[host_reg] = -1; -} - -static inline void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) -{ - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - addbyte(0x66); /*MOVW [addr],host_reg*/ - addbyte(0x89); - addbyte(0x45 | (host_reg << 3)); - addbyte((uint32_t)addr - (uint32_t)&cpu_state - 128); - } - else - { - addbyte(0x66); /*MOVL [reg],host_reg*/ - addbyte(0x89); - addbyte(0x05 | (host_reg << 3)); - addlong(addr); - } -} -static inline void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) -{ - if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) - { - addbyte(0x89); /*MOVL [addr],host_reg*/ - addbyte(0x45 | (host_reg << 3)); - addbyte((uint32_t)addr - (uint32_t)&cpu_state - 128); - } - 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline int TEST_HOST_REG_B(int dst_reg, int src_reg) -{ - AND_HOST_REG_B(dst_reg, src_reg); - - return dst_reg; -} -static inline int TEST_HOST_REG_W(int dst_reg, int src_reg) -{ - AND_HOST_REG_W(dst_reg, src_reg); - - return dst_reg; -} -static inline int TEST_HOST_REG_L(int dst_reg, int src_reg) -{ - AND_HOST_REG_L(dst_reg, src_reg); - - return dst_reg; -} -static inline 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 inline 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 inline 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 inline void NEG_HOST_REG_B(int reg) -{ - addbyte(0xf6); - addbyte(0xd8 | reg); -} -static inline void NEG_HOST_REG_W(int reg) -{ - addbyte(0x66); - addbyte(0xf7); - addbyte(0xd8 | reg); -} -static inline void NEG_HOST_REG_L(int reg) -{ - addbyte(0xf7); - addbyte(0xd8 | reg); -} - -static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline int CMP_HOST_REG_B(int dst_reg, int src_reg) -{ - SUB_HOST_REG_B(dst_reg, src_reg); - - return dst_reg; -} -static inline int CMP_HOST_REG_W(int dst_reg, int src_reg) -{ - SUB_HOST_REG_W(dst_reg, src_reg); - - return dst_reg; -} -static inline int CMP_HOST_REG_L(int dst_reg, int src_reg) -{ - SUB_HOST_REG_L(dst_reg, src_reg); - - return dst_reg; -} -static inline int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) -{ - SUB_HOST_REG_IMM_B(host_reg, imm); - - return host_reg; -} -static inline int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) -{ - SUB_HOST_REG_IMM_W(host_reg, imm); - - return host_reg; -} -static inline 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 inline 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 inline 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 inline void CALL_FUNC(uintptr_t dest) -{ - addbyte(0xE8); /*CALL*/ - addlong(((uintptr_t)dest - (uintptr_t)(&codeblock[block_current].data[block_pos + 4]))); -} - -static inline void SHL_B_IMM(int reg, int count) -{ - addbyte(0xc0); /*SHL reg, count*/ - addbyte(0xc0 | reg | 0x20); - addbyte(count); -} -static inline void SHL_W_IMM(int reg, int count) -{ - addbyte(0x66); /*SHL reg, count*/ - addbyte(0xc1); - addbyte(0xc0 | reg | 0x20); - addbyte(count); -} -static inline void SHL_L_IMM(int reg, int count) -{ - addbyte(0xc1); /*SHL reg, count*/ - addbyte(0xc0 | reg | 0x20); - addbyte(count); -} -static inline void SHR_B_IMM(int reg, int count) -{ - addbyte(0xc0); /*SHR reg, count*/ - addbyte(0xc0 | reg | 0x28); - addbyte(count); -} -static inline void SHR_W_IMM(int reg, int count) -{ - addbyte(0x66); /*SHR reg, count*/ - addbyte(0xc1); - addbyte(0xc0 | reg | 0x28); - addbyte(count); -} -static inline void SHR_L_IMM(int reg, int count) -{ - addbyte(0xc1); /*SHR reg, count*/ - addbyte(0xc0 | reg | 0x28); - addbyte(count); -} -static inline void SAR_B_IMM(int reg, int count) -{ - addbyte(0xc0); /*SAR reg, count*/ - addbyte(0xc0 | reg | 0x38); - addbyte(count); -} -static inline void SAR_W_IMM(int reg, int count) -{ - addbyte(0x66); /*SAR reg, count*/ - addbyte(0xc1); - addbyte(0xc0 | reg | 0x38); - addbyte(count); -} -static inline void SAR_L_IMM(int reg, int count) -{ - addbyte(0xc1); /*SAR reg, count*/ - addbyte(0xc0 | reg | 0x38); - addbyte(count); -} - - -static inline 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 inline 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 inline 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 inline 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(0xe8); /*CALL mem_load_addr_ea_b*/ - addlong(mem_load_addr_ea_b - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - - host_reg_mapping[0] = 8; -} -static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) -{ - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); - addbyte(0xe8); /*CALL mem_load_addr_ea_b_no_abrt*/ - addlong(mem_load_addr_ea_b_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - - host_reg_mapping[REG_ECX] = 8; - - return REG_ECX; -} -static inline 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(0xe8); /*CALL mem_load_addr_ea_w*/ - addlong(mem_load_addr_ea_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - - host_reg_mapping[0] = 8; -} -static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) -{ - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); - addbyte(0x83); /*ADD EAX, offset*/ - addbyte(0xc0); - addbyte(offset); - addbyte(0xe8); /*CALL mem_load_addr_ea_w*/ - addlong(mem_load_addr_ea_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - - host_reg_mapping[0] = 8; -} -static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) -{ - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); - addbyte(0xe8); /*CALL mem_load_addr_ea_w_no_abrt*/ - addlong(mem_load_addr_ea_w_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - - host_reg_mapping[REG_ECX] = 8; - - return REG_ECX; -} -static inline 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(0xe8); /*CALL mem_load_addr_ea_l*/ - addlong(mem_load_addr_ea_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - - - host_reg_mapping[0] = 8; -} -static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) -{ - addbyte(0x8b); /*MOVL EDX, seg->base*/ - addbyte(0x05 | (REG_EDX << 3)); - addlong((uint32_t)&seg->base); - addbyte(0xe8); /*CALL mem_load_addr_ea_l_no_abrt*/ - addlong(mem_load_addr_ea_l_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - - host_reg_mapping[REG_ECX] = 8; - - return REG_ECX; -} - -static inline 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(0xe8); /*CALL mem_load_addr_ea_q*/ - addlong(mem_load_addr_ea_q - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - - host_reg_mapping[0] = 8; -} - -static inline 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 inline 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 inline 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 inline 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); - if (host_reg != REG_ECX) - { - addbyte(0x89); /*MOV ECX, host_reg*/ - addbyte(0xc0 | REG_ECX | (host_reg << 3)); - } - addbyte(0xe8); /*CALL mem_store_addr_ea_b*/ - addlong(mem_store_addr_ea_b - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); -} -static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) -{ - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); - if (host_reg != REG_ECX) - { - addbyte(0x89); /*MOV ECX, host_reg*/ - addbyte(0xc0 | REG_ECX | (host_reg << 3)); - } - addbyte(0xe8); /*CALL mem_store_addr_ea_b_no_abrt*/ - addlong(mem_store_addr_ea_b_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); -} -static inline 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); - if (host_reg != REG_ECX) - { - addbyte(0x89); /*MOV ECX, host_reg*/ - addbyte(0xc0 | REG_ECX | (host_reg << 3)); - } - addbyte(0xe8); /*CALL mem_store_addr_ea_w*/ - addlong(mem_store_addr_ea_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); -} -static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) -{ - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); - if (host_reg != REG_ECX) - { - addbyte(0x89); /*MOV ECX, host_reg*/ - addbyte(0xc0 | REG_ECX | (host_reg << 3)); - } - addbyte(0xe8); /*CALL mem_store_addr_ea_w_no_abrt*/ - addlong(mem_store_addr_ea_w_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); -} -static inline 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); - if (host_reg != REG_ECX) - { - addbyte(0x89); /*MOV ECX, host_reg*/ - addbyte(0xc0 | REG_ECX | (host_reg << 3)); - } - addbyte(0xe8); /*CALL mem_store_addr_ea_l*/ - addlong(mem_store_addr_ea_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); -} -static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) -{ - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); - if (host_reg != REG_ECX) - { - addbyte(0x89); /*MOV ECX, host_reg*/ - addbyte(0xc0 | REG_ECX | (host_reg << 3)); - } - addbyte(0xe8); /*CALL mem_store_addr_ea_l_no_abrt*/ - addlong(mem_store_addr_ea_l_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); -} -static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) -{ - if (host_reg != REG_EBX) - { - addbyte(0x89); /*MOV EBX, host_reg*/ - addbyte(0xc0 | REG_EBX | (host_reg << 3)); - } - if (host_reg2 != REG_ECX) - { - addbyte(0x89); /*MOV ECX, host_reg2*/ - addbyte(0xc0 | REG_ECX | (host_reg2 << 3)); - } - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); - addbyte(0xe8); /*CALL mem_store_addr_ea_q*/ - addlong(mem_store_addr_ea_q - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); -} - -static inline 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 inline 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 inline 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 inline 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 inline 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((uint8_t)cpu_state_offset(regs[sib & 7].l)); - } - break; - case 1: - addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); - 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((uint8_t)cpu_state_offset(regs[sib & 7].l)); - (*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((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); - break; - case 1: - addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*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((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*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((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*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((uint8_t)cpu_state_offset(regs[rm].l)); - cpu_state.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 inline 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 inline void LOAD_STACK_TO_EA(int off) -{ - if (stack32) - { - addbyte(0x8b); /*MOVL EAX,[ESP]*/ - addbyte(0x45 | (REG_EAX << 3)); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); - 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((uint8_t)cpu_state_offset(regs[REG_ESP].w)); - if (off) - { - addbyte(0x66); /*ADD AX, off*/ - addbyte(0x05); - addword(off); - } - } -} - -static inline void LOAD_EBP_TO_EA(int off) -{ - if (stack32) - { - addbyte(0x8b); /*MOVL EAX,[EBP]*/ - addbyte(0x45 | (REG_EAX << 3)); - addbyte((uint8_t)cpu_state_offset(regs[REG_EBP].l)); - 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((uint8_t)cpu_state_offset(regs[REG_EBP].w)); - if (off) - { - addbyte(0x66); /*ADD AX, off*/ - addbyte(0x05); - addword(off); - } - } -} - -static inline void SP_MODIFY(int off) -{ - if (stack32) - { - if (off < 0x80) - { - addbyte(0x83); /*ADD [ESP], off*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); - addbyte(off); - } - else - { - addbyte(0x81); /*ADD [ESP], off*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); - addlong(off); - } - } - else - { - if (off < 0x80) - { - addbyte(0x66); /*ADD [SP], off*/ - addbyte(0x83); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); - addbyte(off); - } - else - { - addbyte(0x66); /*ADD [SP], off*/ - addbyte(0x81); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); - addword(off); - } - } -} - - -static inline 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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(new_pc); - if (taken_cycles) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(taken_cycles); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} -static inline 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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(new_pc); - if (taken_cycles) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(taken_cycles); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} - -static inline 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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(new_pc); - if (taken_cycles) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(taken_cycles); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} -static inline 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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(new_pc); - if (taken_cycles) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(taken_cycles); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} - -static inline void 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((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x3a); /*CMP AL, flags_op2*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - if (not) - addbyte(0x76); /*JBE*/ - else - addbyte(0x77); /*JNBE*/ - break; - case FLAGS_SUB16: - addbyte(0x66); /*MOV AX, flags_op1*/ - addbyte(0x8b); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x66); /*CMP AX, flags_op2*/ - addbyte(0x3b); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - if (not) - addbyte(0x76); /*JBE*/ - else - addbyte(0x77); /*JNBE*/ - break; - case FLAGS_SUB32: - addbyte(0x8b); /*MOV EAX, flags_op1*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x3b); /*CMP EAX, flags_op2*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - 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((uint8_t)cpu_state_offset(flags_res)); - addbyte(0); - addbyte(0x74); /*JZ +*/ - } - else - { - CALL_FUNC((uintptr_t)ZF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - addbyte(0x75); /*JNZ +*/ - } - if (not) - addbyte(5+2+2+7+5+(timing_bt ? 4 : 0)); - else - addbyte(5+2+2); - CALL_FUNC((uintptr_t)CF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - if (not) - addbyte(0x75); /*JNZ +*/ - else - addbyte(0x74); /*JZ +*/ - break; - } - addbyte(7+5+(timing_bt ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(op_pc+pc_offset+offset); - if (timing_bt) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(timing_bt); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} - -static inline void 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((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x3a); /*CMP AL, flags_op2*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - if (not) - addbyte(0x7c); /*JL*/ - else - addbyte(0x7d); /*JNL*/ - break; - case FLAGS_SUB16: - addbyte(0x66); /*MOV AX, flags_op1*/ - addbyte(0x8b); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x66); /*CMP AX, flags_op2*/ - addbyte(0x3b); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - if (not) - addbyte(0x7c); /*JL*/ - else - addbyte(0x7d); /*JNL*/ - break; - case FLAGS_SUB32: - addbyte(0x8b); /*MOV EAX, flags_op1*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x3b); /*CMP EAX, flags_op2*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - if (not) - addbyte(0x7c); /*JL*/ - else - addbyte(0x7d); /*JNL*/ - break; - - default: - CALL_FUNC((uintptr_t)NF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - addbyte(0x0f); /*SETNE BL*/ - addbyte(0x95); - addbyte(0xc3); - CALL_FUNC((uintptr_t)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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(op_pc+pc_offset+offset); - if (timing_bt) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(timing_bt); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} - -static inline void 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((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x3a); /*CMP AL, flags_op2*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - if (not) - addbyte(0x7e); /*JLE*/ - else - addbyte(0x7f); /*JNLE*/ - break; - case FLAGS_SUB16: - addbyte(0x66); /*MOV AX, flags_op1*/ - addbyte(0x8b); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x66); /*CMP AX, flags_op2*/ - addbyte(0x3b); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - if (not) - addbyte(0x7e); /*JLE*/ - else - addbyte(0x7f); /*JNLE*/ - break; - case FLAGS_SUB32: - addbyte(0x8b); /*MOV EAX, flags_op1*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op1)); - addbyte(0x3b); /*CMP EAX, flags_op2*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(flags_op2)); - 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((uint8_t)cpu_state_offset(flags_res)); - addbyte(0); - addbyte(0x74); /*JZ +*/ - } - else - { - CALL_FUNC((uintptr_t)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 ? 4 : 0)); - else - addbyte(5+2+3+5+2+3+2+2); - - CALL_FUNC((uintptr_t)NF_SET); - addbyte(0x85); /*TEST EAX,EAX*/ - addbyte(0xc0); - addbyte(0x0f); /*SETNE BL*/ - addbyte(0x95); - addbyte(0xc3); - CALL_FUNC((uintptr_t)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 ? 4 : 0)); - addbyte(0xC7); /*MOVL [pc], new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(op_pc+pc_offset+offset); - if (timing_bt) - { - addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addbyte(timing_bt); - } - addbyte(0xe9); /*JMP end*/ - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} - - -static inline 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(7+7+5+5); - addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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 inline void FP_FLD(int reg) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xf3); /*MOVQ XMM0, ST[reg][EBP]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP - 1) & 7); - addbyte(0xf3); /*MOVQ XMM1, MM[reg][EBP]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x4d); - addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); - addbyte(0x66); /*MOVQ ST[-1][EBP], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); - addbyte(0x8a); /*MOV AL, tag[reg][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); - addbyte(0x66); /*MOVQ MM[-1][EBP], XMM1*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x4d); - addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); - addbyte(0x88); /*MOV tag[-1][EBP], AL*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); - } - else - { - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x83); /*AND EBX, 7*/ - addbyte(0xe3); - addbyte(0x07); - addbyte(0x8b); /*MOV EDX, [ST_i64+EAX]*/ - addbyte(0x54); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x8b); /*MOV ECX, [ST_i64+4+EAX]*/ - addbyte(0x4c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(MM)+4); - addbyte(0x8a); /*MOV AL, [tag+EAX]*/ - addbyte(0x44); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x88); /*MOV [tag+EBX], AL*/ - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(0x89); /*MOV [ST_i64+EBX], EDX*/ - addbyte(0x54); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x89); /*MOV [ST_i64+EBX+4], ECX*/ - addbyte(0x4c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)+4); - - addbyte(0x89); /*MOV [TOP], EBX*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - } -} - -static inline void FP_FST(int reg) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xf3); /*MOVQ XMM0, ST[0][EBP]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x8a); /*MOV AL, tag[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(0x66); /*MOVQ ST[reg][EBP], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); - addbyte(0x88); /*MOV tag[reg][EBP], AL*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); - } - else - { - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xdd); /*FLD [ST+EAX*8]*/ - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x8a); /*MOV BL, [tag+EAX]*/ - addbyte(0x5c); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - - 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(0x5c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x88); /*MOV [tag+EAX], BL*/ - addbyte(0x5c); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - } -} - -static inline void FP_FXCH(int reg) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xf3); /*MOVQ XMM0, ST[0][EBP]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0xf3); /*MOVQ XMM1, ST[reg][EBP]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x4d); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); - addbyte(0x66); /*MOVQ ST[reg][EBP], XMM0*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); - addbyte(0xf3); /*MOVQ XMM2, MM[0][EBP]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x55); - addbyte((uint8_t)cpu_state_offset(MM[cpu_state.TOP].q)); - addbyte(0x66); /*MOVQ ST[0][EBP], XMM1*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x4d); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0xf3); /*MOVQ XMM3, MM[reg][EBP]*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); - addbyte(0x66); /*MOVQ MM[reg][EBP], XMM2*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x55); - addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); - addbyte(0x8a); /*MOV AL, tag[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(0x66); /*MOVQ MM[0][EBP], XMM3*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(MM[cpu_state.TOP].q)); - addbyte(0x8a); /*MOV AH, tag[reg][EBP]*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); - addbyte(0x88); /*MOV tag[reg][EBP], AL*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); - addbyte(0x88); /*MOV tag[0][EBP], AH*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - } - else - { - addbyte(0x8b); /*MOV EAX, [TOP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV EBX, EAX*/ - addbyte(0xc3); - addbyte(0x83); /*ADD EAX, reg*/ - addbyte(0xc0); - addbyte(reg); - - addbyte(0xdd); /*FLD [ST+EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x83); /*AND EAX, 7*/ - addbyte(0xe0); - addbyte(0x07); - addbyte(0xdd); /*FLD [ST+EAX*8]*/ - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0xdd); /*FSTP [ST+EAX*8]*/ - addbyte(0x5c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x8a); /*MOV CL, tag[EAX]*/ - addbyte(0x4c); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(0x8a); /*MOV DL, tag[EBX]*/ - addbyte(0x54); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(0x88); /*MOV tag[EBX], CL*/ - addbyte(0x4c); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(0x88); /*MOV tag[EAX], DL*/ - addbyte(0x54); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(0xbe); /*MOVL ESI, ST_int64*/ - addlong((uintptr_t)cpu_state.MM); - 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); - } -} - - -static inline void FP_LOAD_S() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0x85); /*TEST EAX, EAX*/ - addbyte(0xc0); - addbyte(0xd9); /*FLD [ESP]*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP - 1) & 7); - addbyte(0x0f); /*SETE tag[reg][EBP]*/ - addbyte(0x94); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); - addbyte(0xdd); /*FSTP ST[reg][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); - block_current = block_current; - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x85); /*TEST EAX, EAX*/ - addbyte(0xc0); - addbyte(0x89); /*MOV TOP, EBX*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0f); /*SETE [tag+EBX]*/ - addbyte(0x94); - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - } -} -static inline void FP_LOAD_D() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV ST[reg][EBP], EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); - addbyte(0x09); /*OR EAX, EDX*/ - addbyte(0xd0); - addbyte(0x89); /*MOV ST[reg][EBP]+4, EDX*/ - addbyte(0x55); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7]) + 4); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP - 1) & 7); - addbyte(0x0f); /*SETE tag[reg][EBP]*/ - addbyte(0x94); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0f); /*SETE [tag+EBX]*/ - addbyte(0x94); - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - } -} -static inline void FP_LOAD_IW() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x66); /*MOV [ESP], AX*/ - addbyte(0x89); - addbyte(0x04); - addbyte(0x24); - addbyte(0x66); /*TEST AX, AX*/ - addbyte(0x85); - addbyte(0xc0); - addbyte(0xdf); /*FILDw [ESP]*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP - 1) & 7); - addbyte(0x0f); /*SETE tag[reg][EBP]*/ - addbyte(0x94); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); - addbyte(0xdd); /*FSTP ST[reg][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0f); /*SETE [tag+EBX]*/ - addbyte(0x94); - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - } -} -static inline void FP_LOAD_IL() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0x85); /*TEST EAX, EAX*/ - addbyte(0xc0); - addbyte(0xdb); /*FILDl [ESP]*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP - 1) & 7); - addbyte(0x0f); /*SETE tag[reg][EBP]*/ - addbyte(0x94); - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); - addbyte(0xdd); /*FSTP ST[reg][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0f); /*SETE [tag+EBX]*/ - addbyte(0x94); - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - } -} -static inline void FP_LOAD_IQ() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV MM[reg][EBP], EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); - addbyte(0x09); /*OR EAX, EDX*/ - addbyte(0xd0); - addbyte(0x89); /*MOV MM[reg][EBP]+4, EDX*/ - addbyte(0x55); - addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q) + 4); - addbyte(0x0f); /*SETE AL*/ - addbyte(0x94); - addbyte(0xc0); - addbyte(0xdf); /*FILDq MM[reg][EBP]*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); - addbyte(0x0c); /*OR AL, TAG_UINT64*/ - addbyte(TAG_UINT64); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP - 1) & 7); - addbyte(0x88); /*MOV tag[reg][EBP], AL*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); - addbyte(0xdd); /*FSTP ST[reg][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x09); /*OR EAX, EDX*/ - addbyte(0xd0); - addbyte(0x89); /*MOV [ST_i64+4+EBX*8], EDX*/ - addbyte(0x54); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)+4); - addbyte(0x83); /*CMP EAX, 0*/ - addbyte(0xf8); - addbyte(0); - addbyte(0xdf); /*FILDl [ST_i64+EBX*8]*/ - addbyte(0x6c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - addbyte(0x0f); /*SETE AL*/ - addbyte(0x94); - addbyte(0xc0); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x0c); /*OR AL, TAG_UINT64*/ - addbyte(TAG_UINT64); - addbyte(0x89); /*MOV TOP, EBX*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x88); /*MOV [tag+EBX], AL*/ - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - } -} - -static inline void FP_LOAD_IMM_Q(uint64_t v) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xc7); /*MOV ST[reg][EBP], v*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); - addlong(v & 0xffffffff); - addbyte(0xc7); /*MOV ST[reg][EBP]+4, v*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7]) + 4); - addlong(v >> 32); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP - 1) & 7); - addbyte(0xc6); /*MOVB tag[reg][EBP], 1:0*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); - addbyte(v ? 0 : 1); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x83); /*SUB EBX, 1*/ - addbyte(0xeb); - addbyte(1); - addbyte(0x83); /*AND EBX, 7*/ - addbyte(0xe3); - addbyte(7); - addbyte(0xc7); /*MOV ST[EBP+EBX*8], v*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addlong(v & 0xffffffff); - addbyte(0xc7); /*MOV ST[EBP+EBX*8]+4, v*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST) + 4); - addlong(v >> 32); - addbyte(0xc6); /*MOVB tag[reg][EBP], 1:0*/ - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(v ? 0 : 1); - addbyte(0x89); /*MOV TOP, EBX*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - } -} - -static inline int FP_LOAD_REG(int reg) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xdd); /*FLD ST[reg][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(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 inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xdd); /*FLD ST[reg][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(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 inline int FP_LOAD_REG_INT_W(int reg) -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - - addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(new_npxc)); - addbyte(0xdb); /*FISTP [ESP]*/ - addbyte(0x1c); - addbyte(0x24); - addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(old_npxc)); - addbyte(0x8b); /*MOV EBX, [ESP]*/ - addbyte(0x1c); - addbyte(0x24); - - return REG_EBX; -} -static inline int FP_LOAD_REG_INT(int reg) -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - - addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(new_npxc)); - addbyte(0xdb); /*FISTP [ESP]*/ - addbyte(0x1c); - addbyte(0x24); - addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(old_npxc)); - addbyte(0x8b); /*MOV EBX, [ESP]*/ - addbyte(0x1c); - addbyte(0x24); - - return REG_EBX; -} -static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) -{ - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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[cpu_state.TOP] && (cpu_state.tag[cpu_state.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(0x4c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)+4); - addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - - return; - } - - addbyte(0xf6); /*TEST TAG[EBX], TAG_UINT64*/ - addbyte(0x44); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(TAG_UINT64); - addbyte(0x74); /*JZ +*/ - addbyte(4+4+2); - - addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ - addbyte(0x4c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)+4); - addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(MM)); - - addbyte(0xeb); /*JMP done*/ - addbyte(4+3+3+3+3+4); - - addbyte(0xdd); /*FLD ST[EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - - addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(new_npxc)); - addbyte(0xdf); /*FISTPQ [ESP]*/ - addbyte(0x3c); - addbyte(0x24); - addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(old_npxc)); - addbyte(0x8b); /*MOV EBX, [ESP]*/ - addbyte(0x1c); - addbyte(0x24); - addbyte(0x8b); /*MOV ECX, 4[ESP]*/ - addbyte(0x4c); - addbyte(0x24); - addbyte(4); - - *host_reg1 = REG_EBX; - *host_reg2 = REG_ECX; -} - -static inline void FP_POP() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xc6); /*MOVB tag[0][EBP], 3*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(3); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP + 1) & 7); - } - else - { - addbyte(0x8b); /*MOV EAX, TOP*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xc6); /*MOVB tag[EAX], 3*/ - addbyte(0x44); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(3); - addbyte(0x04); /*ADD AL, 1*/ - addbyte(1); - addbyte(0x24); /*AND AL, 7*/ - addbyte(7); - addbyte(0x88); /*MOV TOP, AL*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - } -} -static inline void FP_POP2() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xc6); /*MOVB tag[0][EBP], 3*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(3); - addbyte(0xc6); /*MOVB tag[1][EBP], 3*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP+1)&7])); - addbyte(3); - addbyte(0xc6); /*MOVB TOP[EBP], (TOP+2) & 7*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte((cpu_state.TOP + 2) & 7); - } - else - { - addbyte(0x8b); /*MOV EAX, TOP*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0xc6); /*MOVB tag[EAX], 3*/ - addbyte(0x44); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(3); - addbyte(0x04); /*ADD AL, 2*/ - addbyte(2); - addbyte(0x24); /*AND AL, 7*/ - addbyte(7); - addbyte(0x88); /*MOV TOP, AL*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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 inline void FP_OP_S(int op) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[dst][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(~TAG_UINT64); - addbyte(0xd8); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP ST[dst][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xd8); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - } -} -static inline void FP_OP_D(int op) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0x89); /*MOV [ESP+4], EDX*/ - addbyte(0x54); - addbyte(0x24); - addbyte(0x04); - if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) - { - addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(new_npxc)); - } - addbyte(0xdd); /*FLD ST[dst][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(~TAG_UINT64); - addbyte(0xdc); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP ST[dst][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) - { - addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(old_npxc)); - } - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) - { - addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(new_npxc)); - } - addbyte(0x89); /*MOV [ESP+4], EDX*/ - addbyte(0x54); - addbyte(0x24); - addbyte(0x04); - addbyte(0xdd); /*FLD ST[EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xdc); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) - { - addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(old_npxc)); - } - } -} -static inline void FP_OP_IW(int op) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x66); /*MOV [ESP], AX*/ - addbyte(0x89); - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(~TAG_UINT64); - addbyte(0xde); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP ST[0][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xde); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - } -} -static inline void FP_OP_IL(int op) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(~TAG_UINT64); - addbyte(0xda); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP ST[0][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xda); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - } -} -#if 0 -static inline void FP_OP_IQ(int op) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_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[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(~TAG_UINT64); - addbyte(0xdc); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP ST[0][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xdc); /*FADD [ESP]*/ - addbyte(0x04 | op); - addbyte(0x24); - addbyte(0xdd); /*FSTP [ST+EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - } -} -#endif -#define C0 (1<<8) -#define C1 (1<<9) -#define C2 (1<<10) -#define C3 (1<<14) - -static inline void FP_COMPARE_S() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x8a); /*MOV BL, [npxs+1]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x8a); /*MOV BL, [npxs+1]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } -} -static inline void FP_COMPARE_D() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_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[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x8a); /*MOV BL, [npxs+1]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x8a); /*MOV BL, [npxs+1]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } -} -static inline void FP_COMPARE_IW() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x66); /*MOV [ESP], AX*/ - addbyte(0x89); - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x8a); /*MOV BL, [npxs+1]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x8a); /*MOV BL, [npxs+1]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } -} -static inline void FP_COMPARE_IL() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0x8a); /*MOV BL, [npxs+1]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } - else - { - addbyte(0x8b); /*MOV EBX, TOP*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV [ESP], EAX*/ - addbyte(0x04); - addbyte(0x24); - addbyte(0xdd); /*FLD ST[EBX*8]*/ - addbyte(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x8a); /*MOV BL, [npxs+1]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(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(0x5d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } -} - -static inline void FP_OP_REG(int op, int dst, int src) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xdd); /*FLD ST[dst][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); - addbyte(0xdc); /*FADD ST[src][EBP]*/ - addbyte(0x45 | op); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + src) & 7])); - addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + dst) & 7])); - addbyte(~TAG_UINT64); - addbyte(0xdd); /*FSTP ST[dst][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); - } - else - { - addbyte(0x8b); /*MOV EAX, TOP*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - 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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x1d); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xdc); /*FADD ST[EAX*8]*/ - addbyte(0x44 | op); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0xdd); /*FSTP ST[EBX*8]*/ - addbyte(0x5c); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - } - else - { - addbyte(0xdd); /*FLD [ESI+EAX*8]*/ - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xdc); /*FADD ST[EBX*8]*/ - addbyte(0x44 | op); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0xdd); /*FSTP ST[EAX*8]*/ - addbyte(0x5c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - } - } -} - -static inline void FP_COMPARE_REG(int dst, int src) -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0x8a); /*MOV CL, [npxs+1]*/ - addbyte(0x4d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - addbyte(0xdb); /*FCLEX*/ - addbyte(0xe2); - addbyte(0xdd); /*FLD ST[dst][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); - addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ - addbyte(0xe1); - addbyte((~(C0|C2|C3)) >> 8); - addbyte(0xdc); /*FCOMP ST[src][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + src) & 7])); - 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(0x4d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } - else - { - addbyte(0x8b); /*MOV EAX, TOP*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - 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(0x4d); - addbyte((uint8_t)cpu_state_offset(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(0x44); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0xdc); /*FCOMP ST[EAX*8]*/ - addbyte(0x44 | 0x18); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - } - else - { - addbyte(0xdd); /*FLD [ESI+EAX*8]*/ - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0xdc); /*FCOMP ST[EBX*8]*/ - addbyte(0x44 | 0x18); - addbyte(0xdd); - addbyte((uint8_t)cpu_state_offset(ST)); - } - - 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(0x4d); - addbyte((uint8_t)cpu_state_offset(npxs) + 1); - } -} - -static inline void FP_FCHS() -{ - if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) - { - addbyte(0xdd); /*FLD ST[0][EBP]*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - addbyte(0xd9); /*FCHS*/ - addbyte(0xe0); - addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); - addbyte(~TAG_UINT64); - addbyte(0xdd); /*FSTP ST[dst][EBP]*/ - addbyte(0x5d); - addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); - } - else - { - addbyte(0x8b); /*MOV EAX, TOP*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - - addbyte(0xdd); /*FLD [ESI+EAX*8]*/ - addbyte(0x44); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ - addbyte(0x64); - addbyte(0x05); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(~TAG_UINT64); - addbyte(0xd9); /*FCHS*/ - addbyte(0xe0); - addbyte(0xdd); /*FSTP ST[EAX*8]*/ - addbyte(0x5c); - addbyte(0xc5); - addbyte((uint8_t)cpu_state_offset(ST)); - } -} - -static inline void UPDATE_NPXC(int reg) -{ - addbyte(0x66); /*AND cpu_state.new_npxc, ~0xc00*/ - addbyte(0x81); - addbyte(0x65); - addbyte((uint8_t)cpu_state_offset(new_npxc)); - addword(~0xc00); - if (reg) - { - addbyte(0x66); /*AND reg, 0xc00*/ - addbyte(0x81); - addbyte(0xe0 | reg); - addword(0xc00); - } - else - { - addbyte(0x66); /*AND AX, 0xc00*/ - addbyte(0x25); - addword(0xc00); - } - addbyte(0x66); /*OR cpu_state.new_npxc, reg*/ - addbyte(0x09); - addbyte(0x45 | (reg << 3)); - addbyte((uint8_t)cpu_state_offset(new_npxc)); -} - -static inline int ZERO_EXTEND_W_B(int reg) -{ - addbyte(0x0f); /*MOVZX regl, regb*/ - addbyte(0xb6); - addbyte(0xc0 | reg | (reg << 3)); - return reg; -} -static inline int ZERO_EXTEND_L_B(int reg) -{ - addbyte(0x0f); /*MOVZX regl, regb*/ - addbyte(0xb6); - addbyte(0xc0 | reg | (reg << 3)); - return reg; -} -static inline int ZERO_EXTEND_L_W(int reg) -{ - addbyte(0x0f); /*MOVZX regl, regw*/ - addbyte(0xb7); - addbyte(0xc0 | reg | (reg << 3)); - return reg; -} - -static inline int SIGN_EXTEND_W_B(int reg) -{ - addbyte(0x0f); /*MOVSX regl, regb*/ - addbyte(0xbe); - addbyte(0xc0 | reg | (reg << 3)); - return reg; -} -static inline int SIGN_EXTEND_L_B(int reg) -{ - addbyte(0x0f); /*MOVSX regl, regb*/ - addbyte(0xbe); - addbyte(0xc0 | reg | (reg << 3)); - return reg; -} -static inline int SIGN_EXTEND_L_W(int reg) -{ - addbyte(0x0f); /*MOVSX regl, regw*/ - addbyte(0xbf); - addbyte(0xc0 | reg | (reg << 3)); - return reg; -} - -static inline int COPY_REG(int src_reg) -{ - return src_reg; -} - -static inline 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 inline 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 inline 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(7+7+5+5); - addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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(0xc6); /*MOV ISMMX, 1*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ismmx)); - addbyte(1); - addbyte(0x89); /*MOV TOP, EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(TOP)); - addbyte(0x89); /*MOV tag, EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[0])); - addbyte(0x89); /*MOV tag+4, EAX*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(tag[4])); - - codegen_mmx_entered = 1; -} - -extern int mmx_ebx_ecx_loaded; - -static inline 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(0x45 | (host_reg << 3)); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); - - return host_reg; -} -static inline void 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(0x45 | ((*host_reg1) << 3)); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); - addbyte(0x8b); /*MOV ECX, reg+4*/ - addbyte(0x45 | ((*host_reg2) << 3)); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); -} -static inline 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(0x45 | (dst_reg << 3)); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); - - return dst_reg; -} - -static inline 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 inline void STORE_MMX_LQ(int guest_reg, int host_reg1) -{ - addbyte(0xC7); /*MOVL [reg],0*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); - addlong(0); - addbyte(0x89); /*MOVL [reg],host_reg*/ - addbyte(0x45 | (host_reg1 << 3)); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); -} -static inline void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) -{ - addbyte(0x89); /*MOVL [reg],host_reg*/ - addbyte(0x45 | (host_reg1 << 3)); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); - addbyte(0x89); /*MOVL [reg],host_reg*/ - addbyte(0x45 | (host_reg2 << 3)); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); -} -static inline void STORE_MMX_Q_MMX(int guest_reg, int host_reg) -{ - addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ - addbyte(0x0f); - addbyte(0xd6); - addbyte(0x45 | (host_reg << 3)); - addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); -} - -#define MMX_x86_OP(name, opcode) \ -static inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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 inline 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); -} - - -static inline void SAVE_EA() -{ - addbyte(0x89); /*MOV [ESP+12], EAX*/ - addbyte(0x44); - addbyte(0x24); - addbyte(12); -} -static inline void LOAD_EA() -{ - addbyte(0x8b); /*MOV EAX, [ESP+12]*/ - addbyte(0x44); - addbyte(0x24); - addbyte(12); -} - -#define MEM_CHECK_WRITE_B MEM_CHECK_WRITE -static inline void MEM_CHECK_WRITE(x86seg *seg) -{ - CHECK_SEG_WRITE(seg); - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); - addbyte(0xe8); /*CALL mem_check_write*/ - addlong(mem_check_write - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - LOAD_EA(); -} -static inline void MEM_CHECK_WRITE_W(x86seg *seg) -{ - CHECK_SEG_WRITE(seg); - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); - addbyte(0xe8); /*CALL mem_check_write_w*/ - addlong(mem_check_write_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - LOAD_EA(); -} -static inline void MEM_CHECK_WRITE_L(x86seg *seg) -{ - CHECK_SEG_WRITE(seg); - addbyte(0x8b); /*MOVL ESI, seg->base*/ - addbyte(0x05 | (REG_ESI << 3)); - addlong((uint32_t)&seg->base); - addbyte(0xe8); /*CALL mem_check_write_l*/ - addlong(mem_check_write_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - LOAD_EA(); -} - -static inline void LOAD_SEG(int host_reg, void *seg) -{ - addbyte(0xc7); /*MOV [ESP+4], seg*/ - addbyte(0x44); - addbyte(0x24); - addbyte(4); - addlong((uint32_t)seg); - addbyte(0x89); /*MOV [ESP], host_reg*/ - addbyte(0x04 | (host_reg << 3)); - addbyte(0x24); - CALL_FUNC((uintptr_t)loadseg); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE end*/ - addbyte(0x85); - addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); -} diff --git a/src/codegen_ops_xchg.h b/src/codegen_ops_xchg.h deleted file mode 100644 index 25ff4c7..0000000 --- a/src/codegen_ops_xchg.h +++ /dev/null @@ -1,93 +0,0 @@ -#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_reg.c b/src/codegen_reg.c new file mode 100644 index 0000000..b8966b9 --- /dev/null +++ b/src/codegen_reg.c @@ -0,0 +1,932 @@ +#include "ibm.h" +#include "codegen.h" +#include "codegen_backend.h" +#include "codegen_ir_defs.h" +#include "codegen_reg.h" + +int max_version_refcount; +uint16_t reg_dead_list = 0; + +uint8_t reg_last_version[IREG_COUNT]; +reg_version_t reg_version[IREG_COUNT][256]; + +ir_reg_t invalid_ir_reg = {IREG_INVALID}; + +ir_reg_t _host_regs[CODEGEN_HOST_REGS]; +static uint8_t _host_reg_dirty[CODEGEN_HOST_REGS]; + +ir_reg_t host_fp_regs[CODEGEN_HOST_FP_REGS]; +static uint8_t host_fp_reg_dirty[CODEGEN_HOST_FP_REGS]; + +typedef struct host_reg_set_t +{ + ir_reg_t *regs; + uint8_t *dirty; + host_reg_def_t *reg_list; + uint16_t locked; + int nr_regs; +} host_reg_set_t; + +static host_reg_set_t host_reg_set, host_fp_reg_set; + +enum +{ + REG_BYTE, + REG_WORD, + REG_DWORD, + REG_QWORD, + REG_POINTER, + REG_DOUBLE, + REG_FPU_ST_BYTE, + REG_FPU_ST_DOUBLE, + REG_FPU_ST_QWORD +}; + +enum +{ + REG_INTEGER, + REG_FP +}; + +enum +{ + /*Register may be accessed outside of code block, and must be written + back before any control transfers*/ + REG_PERMANENT = 0, + /*Register will not be accessed outside of code block, and does not need + to be written back if there are no readers remaining*/ + REG_VOLATILE = 1 +}; + +struct +{ + int native_size; + void *p; + int type; + int is_volatile; +} ireg_data[IREG_COUNT] = +{ + [IREG_EAX] = {REG_DWORD, &EAX, REG_INTEGER, REG_PERMANENT}, + [IREG_ECX] = {REG_DWORD, &ECX, REG_INTEGER, REG_PERMANENT}, + [IREG_EDX] = {REG_DWORD, &EDX, REG_INTEGER, REG_PERMANENT}, + [IREG_EBX] = {REG_DWORD, &EBX, REG_INTEGER, REG_PERMANENT}, + [IREG_ESP] = {REG_DWORD, &ESP, REG_INTEGER, REG_PERMANENT}, + [IREG_EBP] = {REG_DWORD, &EBP, REG_INTEGER, REG_PERMANENT}, + [IREG_ESI] = {REG_DWORD, &ESI, REG_INTEGER, REG_PERMANENT}, + [IREG_EDI] = {REG_DWORD, &EDI, REG_INTEGER, REG_PERMANENT}, + + [IREG_flags_op] = {REG_DWORD, &cpu_state.flags_op, REG_INTEGER, REG_PERMANENT}, + [IREG_flags_res] = {REG_DWORD, &cpu_state.flags_res, REG_INTEGER, REG_PERMANENT}, + [IREG_flags_op1] = {REG_DWORD, &cpu_state.flags_op1, REG_INTEGER, REG_PERMANENT}, + [IREG_flags_op2] = {REG_DWORD, &cpu_state.flags_op2, REG_INTEGER, REG_PERMANENT}, + + [IREG_pc] = {REG_DWORD, &cpu_state.pc, REG_INTEGER, REG_PERMANENT}, + [IREG_oldpc] = {REG_DWORD, &cpu_state.oldpc, REG_INTEGER, REG_PERMANENT}, + + [IREG_eaaddr] = {REG_DWORD, &cpu_state.eaaddr, REG_INTEGER, REG_PERMANENT}, + [IREG_ea_seg] = {REG_POINTER, &cpu_state.ea_seg, REG_INTEGER, REG_PERMANENT}, + + [IREG_op32] = {REG_DWORD, &cpu_state.op32, REG_INTEGER, REG_PERMANENT}, + [IREG_ssegsx] = {REG_BYTE, &cpu_state.ssegs, REG_INTEGER, REG_PERMANENT}, + + [IREG_rm_mod_reg] = {REG_DWORD, &cpu_state.rm_data.rm_mod_reg_data, REG_INTEGER, REG_PERMANENT}, + + [IREG_ins] = {REG_DWORD, &cpu_state.cpu_recomp_ins, REG_INTEGER, REG_PERMANENT}, + [IREG_cycles] = {REG_DWORD, &cpu_state._cycles, REG_INTEGER, REG_PERMANENT}, + + [IREG_CS_base] = {REG_DWORD, &cpu_state.seg_cs.base, REG_INTEGER, REG_PERMANENT}, + [IREG_DS_base] = {REG_DWORD, &cpu_state.seg_ds.base, REG_INTEGER, REG_PERMANENT}, + [IREG_ES_base] = {REG_DWORD, &cpu_state.seg_es.base, REG_INTEGER, REG_PERMANENT}, + [IREG_FS_base] = {REG_DWORD, &cpu_state.seg_fs.base, REG_INTEGER, REG_PERMANENT}, + [IREG_GS_base] = {REG_DWORD, &cpu_state.seg_gs.base, REG_INTEGER, REG_PERMANENT}, + [IREG_SS_base] = {REG_DWORD, &cpu_state.seg_ss.base, REG_INTEGER, REG_PERMANENT}, + + [IREG_CS_seg] = {REG_WORD, &cpu_state.seg_cs.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_DS_seg] = {REG_WORD, &cpu_state.seg_ds.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_ES_seg] = {REG_WORD, &cpu_state.seg_es.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_FS_seg] = {REG_WORD, &cpu_state.seg_fs.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_GS_seg] = {REG_WORD, &cpu_state.seg_gs.seg, REG_INTEGER, REG_PERMANENT}, + [IREG_SS_seg] = {REG_WORD, &cpu_state.seg_ss.seg, REG_INTEGER, REG_PERMANENT}, + + [IREG_FPU_TOP] = {REG_DWORD, &cpu_state.TOP, REG_INTEGER, REG_PERMANENT}, + + [IREG_ST0] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST1] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST2] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST3] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST4] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST5] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST6] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + [IREG_ST7] = {REG_FPU_ST_DOUBLE, &cpu_state.ST[0], REG_FP, REG_PERMANENT}, + + [IREG_tag0] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag1] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag2] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag3] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag4] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag5] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag6] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + [IREG_tag7] = {REG_FPU_ST_BYTE, &cpu_state.tag[0], REG_INTEGER, REG_PERMANENT}, + + [IREG_ST0_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST1_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST2_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST3_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST4_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST5_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST6_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_ST7_i64] = {REG_FPU_ST_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + + [IREG_MM0x] = {REG_QWORD, &cpu_state.MM[0], REG_FP, REG_PERMANENT}, + [IREG_MM1x] = {REG_QWORD, &cpu_state.MM[1], REG_FP, REG_PERMANENT}, + [IREG_MM2x] = {REG_QWORD, &cpu_state.MM[2], REG_FP, REG_PERMANENT}, + [IREG_MM3x] = {REG_QWORD, &cpu_state.MM[3], REG_FP, REG_PERMANENT}, + [IREG_MM4x] = {REG_QWORD, &cpu_state.MM[4], REG_FP, REG_PERMANENT}, + [IREG_MM5x] = {REG_QWORD, &cpu_state.MM[5], REG_FP, REG_PERMANENT}, + [IREG_MM6x] = {REG_QWORD, &cpu_state.MM[6], REG_FP, REG_PERMANENT}, + [IREG_MM7x] = {REG_QWORD, &cpu_state.MM[7], REG_FP, REG_PERMANENT}, + + [IREG_NPXCx] = {REG_WORD, &cpu_state.npxc, REG_INTEGER, REG_PERMANENT}, + [IREG_NPXSx] = {REG_WORD, &cpu_state.npxs, REG_INTEGER, REG_PERMANENT}, + + [IREG_flagsx] = {REG_WORD, &cpu_state.flags, REG_INTEGER, REG_PERMANENT}, + [IREG_eflagsx] = {REG_WORD, &cpu_state.eflags, REG_INTEGER, REG_PERMANENT}, + + [IREG_CS_limit_low] = {REG_DWORD, &cpu_state.seg_cs.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_DS_limit_low] = {REG_DWORD, &cpu_state.seg_ds.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_ES_limit_low] = {REG_DWORD, &cpu_state.seg_es.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_FS_limit_low] = {REG_DWORD, &cpu_state.seg_fs.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_GS_limit_low] = {REG_DWORD, &cpu_state.seg_gs.limit_low, REG_INTEGER, REG_PERMANENT}, + [IREG_SS_limit_low] = {REG_DWORD, &cpu_state.seg_ss.limit_low, REG_INTEGER, REG_PERMANENT}, + + [IREG_CS_limit_high] = {REG_DWORD, &cpu_state.seg_cs.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_DS_limit_high] = {REG_DWORD, &cpu_state.seg_ds.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_ES_limit_high] = {REG_DWORD, &cpu_state.seg_es.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_FS_limit_high] = {REG_DWORD, &cpu_state.seg_fs.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_GS_limit_high] = {REG_DWORD, &cpu_state.seg_gs.limit_high, REG_INTEGER, REG_PERMANENT}, + [IREG_SS_limit_high] = {REG_DWORD, &cpu_state.seg_ss.limit_high, REG_INTEGER, REG_PERMANENT}, + + /*Temporary registers are stored on the stack, and are not guaranteed to + be preserved across uOPs. They will not be written back if they will + not be read again.*/ + [IREG_temp0] = {REG_DWORD, (void *)16, REG_INTEGER, REG_VOLATILE}, + [IREG_temp1] = {REG_DWORD, (void *)20, REG_INTEGER, REG_VOLATILE}, + [IREG_temp2] = {REG_DWORD, (void *)24, REG_INTEGER, REG_VOLATILE}, + [IREG_temp3] = {REG_DWORD, (void *)28, REG_INTEGER, REG_VOLATILE}, + + [IREG_temp0d] = {REG_DOUBLE, (void *)40, REG_FP, REG_VOLATILE}, + [IREG_temp1d] = {REG_DOUBLE, (void *)48, REG_FP, REG_VOLATILE}, +}; + +void codegen_reg_mark_as_required() +{ + int reg; + + for (reg = 0; reg < IREG_COUNT; reg++) + { + int last_version = reg_last_version[reg]; + + if (last_version > 0 && ireg_data[reg].is_volatile == REG_PERMANENT) + reg_version[reg][last_version].flags |= REG_FLAGS_REQUIRED; + } +} + +int reg_is_native_size(ir_reg_t ir_reg) +{ + int native_size = ireg_data[IREG_GET_REG(ir_reg.reg)].native_size; + int requested_size = IREG_GET_SIZE(ir_reg.reg); + + switch (native_size) + { + case REG_BYTE: case REG_FPU_ST_BYTE: + return (requested_size == IREG_SIZE_B); + case REG_WORD: + return (requested_size == IREG_SIZE_W); + case REG_DWORD: + return (requested_size == IREG_SIZE_L); + case REG_QWORD: case REG_FPU_ST_QWORD: case REG_DOUBLE: case REG_FPU_ST_DOUBLE: + return ((requested_size == IREG_SIZE_D) || (requested_size == IREG_SIZE_Q)); + case REG_POINTER: + if (sizeof(void *) == 4) + return (requested_size == IREG_SIZE_L); + return (requested_size == IREG_SIZE_Q); + + default: + fatal("get_reg_is_native_size: unknown native size %i\n", native_size); + } + + return 0; +} + +void codegen_reg_reset() +{ + int c; + + host_reg_set.regs = _host_regs; + host_reg_set.dirty = _host_reg_dirty; + host_reg_set.reg_list = codegen_host_reg_list; + host_reg_set.locked = 0; + host_reg_set.nr_regs = CODEGEN_HOST_REGS; + host_fp_reg_set.regs = host_fp_regs; + host_fp_reg_set.dirty = host_fp_reg_dirty; + host_fp_reg_set.reg_list = codegen_host_fp_reg_list; + host_fp_reg_set.locked = 0; + host_fp_reg_set.nr_regs = CODEGEN_HOST_FP_REGS; + + for (c = 0; c < IREG_COUNT; c++) + { + reg_last_version[c] = 0; + reg_version[c][0].refcount = 0; + } + for (c = 0; c < CODEGEN_HOST_REGS; c++) + { + host_reg_set.regs[c] = invalid_ir_reg; + host_reg_set.dirty[c] = 0; + } + for (c = 0; c < CODEGEN_HOST_FP_REGS; c++) + { + host_fp_reg_set.regs[c] = invalid_ir_reg; + host_fp_reg_set.dirty[c] = 0; + } + + reg_dead_list = 0; + max_version_refcount = 0; +} + +static inline int ir_get_refcount(ir_reg_t ir_reg) +{ + return reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version].refcount; +} + +static inline host_reg_set_t *get_reg_set(ir_reg_t ir_reg) +{ + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type == REG_INTEGER) + return &host_reg_set; + else + return &host_fp_reg_set; +} + +static void codegen_reg_load(host_reg_set_t *reg_set, codeblock_t *block, int c, ir_reg_t ir_reg) +{ + switch (ireg_data[IREG_GET_REG(ir_reg.reg)].native_size) + { + case REG_WORD: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_WORD !REG_INTEGER\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_16_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_16(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_DWORD: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_DWORD !REG_INTEGER\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_32_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_32(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_QWORD: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_QWORD !REG_FP\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_64_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_64(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_POINTER: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_POINTER !REG_INTEGER\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_pointer_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_pointer(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_DOUBLE: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_DOUBLE !REG_FP\n"); +#endif + if ((uintptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p < 256) + codegen_direct_read_double_stack(block, reg_set->reg_list[c].reg, (intptr_t)ireg_data[IREG_GET_REG(ir_reg.reg)].p); + else + codegen_direct_read_double(block, reg_set->reg_list[c].reg, ireg_data[IREG_GET_REG(ir_reg.reg)].p); + break; + + case REG_FPU_ST_BYTE: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_INTEGER) + fatal("codegen_reg_load - REG_FPU_ST_BYTE !REG_INTEGER\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_read_8(block, reg_set->reg_list[c].reg, &cpu_state.tag[ir_reg.reg & 7]); + else + codegen_direct_read_st_8(block, reg_set->reg_list[c].reg, &cpu_state.tag[0], ir_reg.reg & 7); + break; + + case REG_FPU_ST_QWORD: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_FPU_ST_QWORD !REG_FP\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_read_64(block, reg_set->reg_list[c].reg, &cpu_state.MM[ir_reg.reg & 7]); + else + codegen_direct_read_st_64(block, reg_set->reg_list[c].reg, &cpu_state.MM[0], ir_reg.reg & 7); + break; + + case REG_FPU_ST_DOUBLE: +#ifndef RELEASE_BUILD + if (ireg_data[IREG_GET_REG(ir_reg.reg)].type != REG_FP) + fatal("codegen_reg_load - REG_FPU_ST_DOUBLE !REG_FP\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_read_double(block, reg_set->reg_list[c].reg, &cpu_state.ST[ir_reg.reg & 7]); + else + codegen_direct_read_st_double(block, reg_set->reg_list[c].reg, &cpu_state.ST[0], ir_reg.reg & 7); + break; + + default: + fatal("codegen_reg_load - native_size=%i reg=%i\n", ireg_data[IREG_GET_REG(ir_reg.reg)].native_size, IREG_GET_REG(ir_reg.reg)); + } + + reg_set->regs[c] = ir_reg; + +//pclog(" codegen_reg_load: c=%i reg=%02x.%i\n", c, host_regs[c].reg,host_regs[c].version); +} + +static void codegen_reg_writeback(host_reg_set_t *reg_set, codeblock_t *block, int c, int invalidate) +{ + int ir_reg = IREG_GET_REG(reg_set->regs[c].reg); + void *p = ireg_data[ir_reg].p; + + if (!reg_version[ir_reg][reg_set->regs[c].version].refcount && + ireg_data[ir_reg].is_volatile) + return; + + switch (ireg_data[ir_reg].native_size) + { + case REG_BYTE: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_BYTE !REG_INTEGER\n"); + if ((uintptr_t)p < 256) + fatal("codegen_reg_writeback - REG_BYTE %p\n", p); +#endif + codegen_direct_write_8(block, p, reg_set->reg_list[c].reg); + break; + + case REG_WORD: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_WORD !REG_INTEGER\n"); + if ((uintptr_t)p < 256) + fatal("codegen_reg_writeback - REG_WORD %p\n", p); +#endif + codegen_direct_write_16(block, p, reg_set->reg_list[c].reg); + break; + + case REG_DWORD: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_DWORD !REG_INTEGER\n"); +#endif + if ((uintptr_t)p < 256) + codegen_direct_write_32_stack(block, (intptr_t)p, reg_set->reg_list[c].reg); + else + codegen_direct_write_32(block, p, reg_set->reg_list[c].reg); + break; + + case REG_QWORD: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_QWORD !REG_FP\n"); +#endif + if ((uintptr_t)p < 256) + codegen_direct_write_64_stack(block, (intptr_t)p, reg_set->reg_list[c].reg); + else + codegen_direct_write_64(block, p, reg_set->reg_list[c].reg); + break; + + case REG_POINTER: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_POINTER !REG_INTEGER\n"); + if ((uintptr_t)p < 256) + fatal("codegen_reg_writeback - REG_POINTER %p\n", p); +#endif + codegen_direct_write_ptr(block, p, reg_set->reg_list[c].reg); + break; + + case REG_DOUBLE: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_DOUBLE !REG_FP\n"); +#endif + if ((uintptr_t)p < 256) + codegen_direct_write_double_stack(block, (intptr_t)p, reg_set->reg_list[c].reg); + else + codegen_direct_write_double(block, p, reg_set->reg_list[c].reg); + break; + + case REG_FPU_ST_BYTE: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_INTEGER) + fatal("codegen_reg_writeback - REG_FPU_ST_BYTE !REG_INTEGER\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_write_8(block, &cpu_state.tag[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); + else + codegen_direct_write_st_8(block, &cpu_state.tag[0], reg_set->regs[c].reg & 7, reg_set->reg_list[c].reg); + break; + + case REG_FPU_ST_QWORD: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_FPU_ST_QWORD !REG_FP\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_write_64(block, &cpu_state.MM[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); + else + codegen_direct_write_st_64(block, &cpu_state.MM[0], reg_set->regs[c].reg & 7, reg_set->reg_list[c].reg); + break; + + case REG_FPU_ST_DOUBLE: +#ifndef RELEASE_BUILD + if (ireg_data[ir_reg].type != REG_FP) + fatal("codegen_reg_writeback - REG_FPU_ST_DOUBLE !REG_FP\n"); +#endif + if (block->flags & CODEBLOCK_STATIC_TOP) + codegen_direct_write_double(block, &cpu_state.ST[reg_set->regs[c].reg & 7], reg_set->reg_list[c].reg); + else + codegen_direct_write_st_double(block, &cpu_state.ST[0], reg_set->regs[c].reg & 7, reg_set->reg_list[c].reg); + break; + + default: + fatal("codegen_reg_flush - native_size=%i\n", ireg_data[ir_reg].native_size); + } + + if (invalidate) + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; +} + +#ifdef CODEGEN_BACKEND_HAS_MOV_IMM +void codegen_reg_write_imm(codeblock_t *block, ir_reg_t ir_reg, uint32_t imm_data) +{ + int reg_idx = IREG_GET_REG(ir_reg.reg); + void *p = ireg_data[reg_idx].p; + + switch (ireg_data[reg_idx].native_size) + { + case REG_BYTE: +#ifndef RELEASE_BUILD + if ((uintptr_t)p < 256) + fatal("codegen_reg_write_imm - REG_BYTE %p\n", p); +#endif + codegen_direct_write_8_imm(block, p, imm_data); + break; + + case REG_WORD: +#ifndef RELEASE_BUILD + if ((uintptr_t)p < 256) + fatal("codegen_reg_write_imm - REG_WORD %p\n", p); +#endif + codegen_direct_write_16_imm(block, p, imm_data); + break; + + case REG_DWORD: + if ((uintptr_t)p < 256) + codegen_direct_write_32_imm_stack(block, (int)p, imm_data); + else + codegen_direct_write_32_imm(block, p, imm_data); + break; + + case REG_POINTER: + case REG_QWORD: + case REG_DOUBLE: + case REG_FPU_ST_BYTE: + case REG_FPU_ST_QWORD: + case REG_FPU_ST_DOUBLE: + default: + fatal("codegen_reg_write_imm - native_size=%i\n", ireg_data[reg_idx].native_size); + } +} +#endif + +static void alloc_reg(ir_reg_t ir_reg) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int nr_regs = (reg_set == &host_reg_set) ? CODEGEN_HOST_REGS : CODEGEN_HOST_FP_REGS; + int c; + + for (c = 0; c < nr_regs; c++) + { + if (IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + { +#ifndef RELEASE_BUILD + if (reg_set->regs[c].version != ir_reg.version) + fatal("alloc_reg - host_regs[c].version != ir_reg.version %i %p %p %i %i\n", c, reg_set, &host_reg_set, reg_set->regs[c].reg, ir_reg.reg); +#endif + reg_set->locked |= (1 << c); + return; + } + } +} + +static void alloc_dest_reg(ir_reg_t ir_reg, int dest_reference) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int nr_regs = (reg_set == &host_reg_set) ? CODEGEN_HOST_REGS : CODEGEN_HOST_FP_REGS; + int c; + + for (c = 0; c < nr_regs; c++) + { + if (IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + { + if (reg_set->regs[c].version == ir_reg.version) + { + reg_set->locked |= (1 << c); + } + else + { + /*The immediate prior version may have been + optimised out, so search backwards to find the + last valid version*/ + int prev_version = ir_reg.version-1; +// pclog("prev_version search from %i\n", prev_version); + while (prev_version >= 0) + { + reg_version_t *regv = ®_version[IREG_GET_REG(reg_set->regs[c].reg)][prev_version]; + + if (!(regv->flags & REG_FLAGS_DEAD) && regv->refcount == dest_reference) + { + reg_set->locked |= (1 << c); + return; + } + prev_version--; + } + fatal("codegen_reg_alloc_register - host_regs[c].version != dest_reg_a.version %i,%i %i\n", reg_set->regs[c].version, ir_reg.version, dest_reference); + } + return; + } + } +} + +void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c) +{ + int dest_reference = 0; + + host_reg_set.locked = 0; + host_fp_reg_set.locked = 0; + +/* pclog("alloc_register: dst=%i.%i src_a=%i.%i src_b=%i.%i\n", dest_reg_a.reg, dest_reg_a.version, + src_reg_a.reg, src_reg_a.version, + src_reg_b.reg, src_reg_b.version);*/ + + if (!ir_reg_is_invalid(dest_reg_a)) + { + if (!ir_reg_is_invalid(src_reg_a) && IREG_GET_REG(src_reg_a.reg) == IREG_GET_REG(dest_reg_a.reg) && src_reg_a.version == dest_reg_a.version-1) + dest_reference++; + if (!ir_reg_is_invalid(src_reg_b) && IREG_GET_REG(src_reg_b.reg) == IREG_GET_REG(dest_reg_a.reg) && src_reg_b.version == dest_reg_a.version-1) + dest_reference++; + if (!ir_reg_is_invalid(src_reg_c) && IREG_GET_REG(src_reg_c.reg) == IREG_GET_REG(dest_reg_a.reg) && src_reg_c.version == dest_reg_a.version-1) + dest_reference++; + } + if (!ir_reg_is_invalid(src_reg_a)) + alloc_reg(src_reg_a); + if (!ir_reg_is_invalid(src_reg_b)) + alloc_reg(src_reg_b); + if (!ir_reg_is_invalid(src_reg_c)) + alloc_reg(src_reg_c); + if (!ir_reg_is_invalid(dest_reg_a)) + alloc_dest_reg(dest_reg_a, dest_reference); +} + +ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int c; + + /*Search for required register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version == ir_reg.version) + break; + + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_set->regs[c].version <= ir_reg.version) + { + reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount++; + break; + } +#ifndef RELEASE_BUILD + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg) && reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount) + fatal("codegen_reg_alloc_read_reg - version mismatch!\n"); +#endif + } + + if (c == reg_set->nr_regs) + { + /*No unused registers. Search for an unlocked register with no pending reads*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!(reg_set->locked & (1 << c)) && IREG_GET_REG(reg_set->regs[c].reg) != IREG_INVALID && !ir_get_refcount(reg_set->regs[c])) + break; + } + if (c == reg_set->nr_regs) + { + /*Search for any unlocked register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!(reg_set->locked & (1 << c))) + break; + } +#ifndef RELEASE_BUILD + if (c == reg_set->nr_regs) + fatal("codegen_reg_alloc_read_reg - out of registers\n"); +#endif + } + if (reg_set->dirty[c]) + codegen_reg_writeback(reg_set, block, c, 1); +// pclog(" load %i\n", c); + codegen_reg_load(reg_set, block, c, ir_reg); +// fatal("codegen_reg_alloc_read_reg - read %i.%i to %i\n", ir_reg.reg,ir_reg.version, c); + reg_set->locked |= (1 << c); +// codegen_reg_writeback(block, c); + reg_set->dirty[c] = 0; + } +// else +// pclog(" already loaded %i\n", c); + + reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount--; +#ifndef RELEASE_BUILD + if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount == (uint8_t)-1) + fatal("codegen_reg_alloc_read_reg - refcount < 0\n"); +#endif + + if (host_reg_idx) + *host_reg_idx = c; +// pclog(" codegen_reg_alloc_read_reg: %i.%i %i %02x.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c], reg_set->regs[c].reg,reg_set->regs[c].version, c); + return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); +} + +ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int c; + + if (!reg_is_native_size(ir_reg)) + { + /*Read in parent register so we can do partial accesses to it*/ + ir_reg_t parent_reg; + + parent_reg.reg = IREG_GET_REG(ir_reg.reg) | IREG_SIZE_L; + parent_reg.version = ir_reg.version - 1; + reg_version[IREG_GET_REG(ir_reg.reg)][ir_reg.version - 1].refcount++; + + codegen_reg_alloc_read_reg(block, parent_reg, &c); + +#ifndef RELEASE_BUILD + if (IREG_GET_REG(reg_set->regs[c].reg) != IREG_GET_REG(ir_reg.reg) || reg_set->regs[c].version > ir_reg.version-1) + fatal("codegen_reg_alloc_write_reg sub_reg - doesn't match %i %02x.%i %02x.%i\n", c, + reg_set->regs[c].reg,reg_set->regs[c].version, + ir_reg.reg,ir_reg.version); +#endif + + reg_set->regs[c].reg = ir_reg.reg; + reg_set->regs[c].version = ir_reg.version; + reg_set->dirty[c] = 1; +// pclog(" codegen_reg_alloc_write_reg: partial %i.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c]); + return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); + } + + /*Search for previous version in host register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + { + if (reg_set->regs[c].version <= ir_reg.version-1) + { +#ifndef RELEASE_BUILD + if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount != 0) + fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n"); +#endif + break; + } + } + } + + if (c == reg_set->nr_regs) + { + /*Search for unused registers*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (ir_reg_is_invalid(reg_set->regs[c])) + break; + } + + if (c == reg_set->nr_regs) + { + /*No unused registers. Search for an unlocked register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!(reg_set->locked & (1 << c))) + break; + } +#ifndef RELEASE_BUILD + if (c == reg_set->nr_regs) + fatal("codegen_reg_alloc_write_reg - out of registers\n"); +#endif + if (reg_set->dirty[c]) + codegen_reg_writeback(reg_set, block, c, 1); + } + } + + reg_set->regs[c].reg = ir_reg.reg; + reg_set->regs[c].version = ir_reg.version; + reg_set->dirty[c] = 1; +// pclog(" codegen_reg_alloc_write_reg: %i.%i %i\n", ir_reg.reg, ir_reg.version, codegen_host_reg_list[c]); + return reg_set->reg_list[c].reg | IREG_GET_SIZE(ir_reg.reg); +} + +#ifdef CODEGEN_BACKEND_HAS_MOV_IMM +int codegen_reg_is_loaded(ir_reg_t ir_reg) +{ + host_reg_set_t *reg_set = get_reg_set(ir_reg); + int c; + + /*Search for previous version in host register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(ir_reg.reg)) + { + if (reg_set->regs[c].version <= ir_reg.version-1) + { +#ifndef RELEASE_BUILD + if (reg_version[IREG_GET_REG(reg_set->regs[c].reg)][reg_set->regs[c].version].refcount != 0) + fatal("codegen_reg_alloc_write_reg - previous version refcount != 0\n"); +#endif + return 1; + } + } + } + return 0; +} +#endif + +void codegen_reg_rename(codeblock_t *block, ir_reg_t src, ir_reg_t dst) +{ + host_reg_set_t *reg_set = get_reg_set(src); + int c; + int target; + +// pclog("rename: %i.%i -> %i.%i\n", src.reg,src.version, dst.reg, dst.version); + /*Search for required register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(src.reg) && reg_set->regs[c].version == src.version) + break; + } +#ifndef RELEASE_BUILD + if (c == reg_set->nr_regs) + fatal("codegen_reg_rename: Can't find register to rename\n"); +#endif + target = c; + if (reg_set->dirty[target]) + codegen_reg_writeback(reg_set, block, target, 0); + reg_set->regs[target] = dst; + reg_set->dirty[target] = 1; +// pclog("renamed reg %i dest=%i.%i\n", target, dst.reg, dst.version); + + /*Invalidate any stale copies of the dest register*/ + for (c = 0; c < reg_set->nr_regs; c++) + { + if (c == target) + continue; + if (!ir_reg_is_invalid(reg_set->regs[c]) && IREG_GET_REG(reg_set->regs[c].reg) == IREG_GET_REG(dst.reg)) + { + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } + } +} + +void codegen_reg_flush(ir_data_t *ir, codeblock_t *block) +{ + host_reg_set_t *reg_set; + int c; + + reg_set = &host_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 0); + } + if (reg_set->reg_list[c].flags & HOST_REG_FLAG_VOLATILE) + { + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } + } + + reg_set = &host_fp_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 0); + } + if (reg_set->reg_list[c].flags & HOST_REG_FLAG_VOLATILE) + { + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } + } +} + +void codegen_reg_flush_invalidate(ir_data_t *ir, codeblock_t *block) +{ + host_reg_set_t *reg_set; + int c; + + reg_set = &host_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 1); + } + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } + + reg_set = &host_fp_reg_set; + for (c = 0; c < reg_set->nr_regs; c++) + { + if (!ir_reg_is_invalid(reg_set->regs[c]) && reg_set->dirty[c]) + { + codegen_reg_writeback(reg_set, block, c, 1); + } + reg_set->regs[c] = invalid_ir_reg; + reg_set->dirty[c] = 0; + } +} + +/*Process dead register list, and optimise out register versions and uOPs where + possible*/ +void codegen_reg_process_dead_list(ir_data_t *ir) +{ + while (reg_dead_list) + { + int version = reg_dead_list & 0xff; + int reg = reg_dead_list >> 8; + reg_version_t *regv = ®_version[reg][version]; + uop_t *uop = &ir->uops[regv->parent_uop]; + + /*Barrier uOPs should be preserved*/ + if (!(uop->type & (UOP_TYPE_BARRIER | UOP_TYPE_ORDER_BARRIER))) + { +// pclog(" codegen_process_dead_list: reg=%i version=%i uop=%i\n", reg, version, regv->parent_uop); + uop->type = UOP_INVALID; + /*Adjust refcounts on source registers. If these drop to + zero then those registers can be considered for removal*/ + if (uop->src_reg_a.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_a.reg)][uop->src_reg_a.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_a.reg), uop->src_reg_a.version); + } + if (uop->src_reg_b.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_b.reg)][uop->src_reg_b.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_b.reg), uop->src_reg_b.version); + } + if (uop->src_reg_c.reg != IREG_INVALID) + { + reg_version_t *src_regv = ®_version[IREG_GET_REG(uop->src_reg_c.reg)][uop->src_reg_c.version]; + src_regv->refcount--; + if (!src_regv->refcount) + add_to_dead_list(src_regv, IREG_GET_REG(uop->src_reg_c.reg), uop->src_reg_c.version); + } + regv->flags |= REG_FLAGS_DEAD; + } + + reg_dead_list = regv->next; + } +} diff --git a/src/codegen_reg.h b/src/codegen_reg.h new file mode 100644 index 0000000..4aaa231 --- /dev/null +++ b/src/codegen_reg.h @@ -0,0 +1,419 @@ +#ifndef _CODEGEN_REG_H_ +#define _CODEGEN_REG_H_ + +#define IREG_REG_MASK 0xff +#define IREG_SIZE_SHIFT 8 +#define IREG_SIZE_MASK (7 << IREG_SIZE_SHIFT) + +#define IREG_GET_REG(reg) ((reg) & IREG_REG_MASK) +#define IREG_GET_SIZE(reg) ((reg) & IREG_SIZE_MASK) + +#define IREG_SIZE_L (0 << IREG_SIZE_SHIFT) +#define IREG_SIZE_W (1 << IREG_SIZE_SHIFT) +#define IREG_SIZE_B (2 << IREG_SIZE_SHIFT) +#define IREG_SIZE_BH (3 << IREG_SIZE_SHIFT) +#define IREG_SIZE_D (4 << IREG_SIZE_SHIFT) +#define IREG_SIZE_Q (5 << IREG_SIZE_SHIFT) + +enum +{ + IREG_EAX = 0, + IREG_ECX = 1, + IREG_EDX = 2, + IREG_EBX = 3, + IREG_ESP = 4, + IREG_EBP = 5, + IREG_ESI = 6, + IREG_EDI = 7, + + IREG_flags_op = 8, + IREG_flags_res = 9, + IREG_flags_op1 = 10, + IREG_flags_op2 = 11, + + IREG_pc = 12, + IREG_oldpc = 13, + + IREG_eaaddr = 14, + IREG_ea_seg = 15, + IREG_op32 = 16, + IREG_ssegsx = 17, + + IREG_rm_mod_reg = 18, + + IREG_ins = 19, + IREG_cycles = 20, + + IREG_CS_base = 21, + IREG_DS_base = 22, + IREG_ES_base = 23, + IREG_FS_base = 24, + IREG_GS_base = 25, + IREG_SS_base = 26, + + IREG_CS_seg = 27, + IREG_DS_seg = 28, + IREG_ES_seg = 29, + IREG_FS_seg = 30, + IREG_GS_seg = 31, + IREG_SS_seg = 32, + + /*Temporary registers are stored on the stack, and are not guaranteed to + be preserved across uOPs. They will not be written back if they will + not be read again.*/ + IREG_temp0 = 33, + IREG_temp1 = 34, + IREG_temp2 = 35, + IREG_temp3 = 36, + + IREG_FPU_TOP = 37, + + IREG_temp0d = 38, + IREG_temp1d = 39, + + /*FPU stack registers are physical registers. Use IREG_ST() / IREG_tag() + to access. + When CODEBLOCK_STATIC_TOP is set, the physical register number will be + used directly to index the stack. When it is clear, the difference + between the current value of TOP and the value when the block was + first compiled will be added to adjust for any changes in TOP.*/ + IREG_ST0 = 40, + IREG_ST1 = 41, + IREG_ST2 = 42, + IREG_ST3 = 43, + IREG_ST4 = 44, + IREG_ST5 = 45, + IREG_ST6 = 46, + IREG_ST7 = 47, + + IREG_tag0 = 48, + IREG_tag1 = 49, + IREG_tag2 = 50, + IREG_tag3 = 51, + IREG_tag4 = 52, + IREG_tag5 = 53, + IREG_tag6 = 54, + IREG_tag7 = 55, + + IREG_ST0_i64 = 56, + IREG_ST1_i64 = 57, + IREG_ST2_i64 = 58, + IREG_ST3_i64 = 59, + IREG_ST4_i64 = 60, + IREG_ST5_i64 = 61, + IREG_ST6_i64 = 62, + IREG_ST7_i64 = 63, + + IREG_MM0x = 64, + IREG_MM1x = 65, + IREG_MM2x = 66, + IREG_MM3x = 67, + IREG_MM4x = 68, + IREG_MM5x = 69, + IREG_MM6x = 70, + IREG_MM7x = 71, + + IREG_NPXCx = 72, + IREG_NPXSx = 73, + + IREG_flagsx = 74, + IREG_eflagsx = 75, + + IREG_CS_limit_low = 76, + IREG_DS_limit_low = 77, + IREG_ES_limit_low = 78, + IREG_FS_limit_low = 79, + IREG_GS_limit_low = 80, + IREG_SS_limit_low = 81, + + IREG_CS_limit_high = 82, + IREG_DS_limit_high = 83, + IREG_ES_limit_high = 84, + IREG_FS_limit_high = 85, + IREG_GS_limit_high = 86, + IREG_SS_limit_high = 87, + + IREG_COUNT = 88, + + IREG_INVALID = 255, + + IREG_AX = IREG_EAX + IREG_SIZE_W, + IREG_CX = IREG_ECX + IREG_SIZE_W, + IREG_DX = IREG_EDX + IREG_SIZE_W, + IREG_BX = IREG_EBX + IREG_SIZE_W, + IREG_SP = IREG_ESP + IREG_SIZE_W, + IREG_BP = IREG_EBP + IREG_SIZE_W, + IREG_SI = IREG_ESI + IREG_SIZE_W, + IREG_DI = IREG_EDI + IREG_SIZE_W, + + IREG_AL = IREG_EAX + IREG_SIZE_B, + IREG_CL = IREG_ECX + IREG_SIZE_B, + IREG_DL = IREG_EDX + IREG_SIZE_B, + IREG_BL = IREG_EBX + IREG_SIZE_B, + + IREG_AH = IREG_EAX + IREG_SIZE_BH, + IREG_CH = IREG_ECX + IREG_SIZE_BH, + IREG_DH = IREG_EDX + IREG_SIZE_BH, + IREG_BH = IREG_EBX + IREG_SIZE_BH, + + IREG_flags_res_W = IREG_flags_res + IREG_SIZE_W, + IREG_flags_op1_W = IREG_flags_op1 + IREG_SIZE_W, + IREG_flags_op2_W = IREG_flags_op2 + IREG_SIZE_W, + + IREG_flags_res_B = IREG_flags_res + IREG_SIZE_B, + IREG_flags_op1_B = IREG_flags_op1 + IREG_SIZE_B, + IREG_flags_op2_B = IREG_flags_op2 + IREG_SIZE_B, + + IREG_temp0_W = IREG_temp0 + IREG_SIZE_W, + IREG_temp1_W = IREG_temp1 + IREG_SIZE_W, + IREG_temp2_W = IREG_temp2 + IREG_SIZE_W, + IREG_temp3_W = IREG_temp3 + IREG_SIZE_W, + + IREG_temp0_B = IREG_temp0 + IREG_SIZE_B, + IREG_temp1_B = IREG_temp1 + IREG_SIZE_B, + IREG_temp2_B = IREG_temp2 + IREG_SIZE_B, + IREG_temp3_B = IREG_temp3 + IREG_SIZE_B, + + IREG_temp0_D = IREG_temp0d + IREG_SIZE_D, + IREG_temp1_D = IREG_temp1d + IREG_SIZE_D, + + IREG_temp0_Q = IREG_temp0d + IREG_SIZE_Q, + IREG_temp1_Q = IREG_temp1d + IREG_SIZE_Q, + + IREG_eaaddr_W = IREG_eaaddr + IREG_SIZE_W, + + IREG_CS_seg_W = IREG_CS_seg + IREG_SIZE_W, + IREG_DS_seg_W = IREG_DS_seg + IREG_SIZE_W, + IREG_ES_seg_W = IREG_ES_seg + IREG_SIZE_W, + IREG_FS_seg_W = IREG_FS_seg + IREG_SIZE_W, + IREG_GS_seg_W = IREG_GS_seg + IREG_SIZE_W, + IREG_SS_seg_W = IREG_SS_seg + IREG_SIZE_W, + + IREG_MM0 = IREG_MM0x + IREG_SIZE_Q, + IREG_MM1 = IREG_MM1x + IREG_SIZE_Q, + IREG_MM2 = IREG_MM2x + IREG_SIZE_Q, + IREG_MM3 = IREG_MM3x + IREG_SIZE_Q, + IREG_MM4 = IREG_MM4x + IREG_SIZE_Q, + IREG_MM5 = IREG_MM5x + IREG_SIZE_Q, + IREG_MM6 = IREG_MM6x + IREG_SIZE_Q, + IREG_MM7 = IREG_MM7x + IREG_SIZE_Q, + + IREG_NPXC = IREG_NPXCx + IREG_SIZE_W, + IREG_NPXS = IREG_NPXSx + IREG_SIZE_W, + + IREG_ssegs = IREG_ssegsx + IREG_SIZE_B, + + IREG_flags = IREG_flagsx + IREG_SIZE_W, + IREG_eflags = IREG_eflagsx + IREG_SIZE_W +}; + +#define IREG_8(reg) (((reg) & 4) ? (((reg) & 3) + IREG_AH) : ((reg) + IREG_AL)) +#define IREG_16(reg) ((reg) + IREG_AX) +#define IREG_32(reg) ((reg) + IREG_EAX) + +#define IREG_ST(r) (IREG_ST0 + ((cpu_state.TOP + (r)) & 7) + IREG_SIZE_D) +#define IREG_ST_i64(r) (IREG_ST0_i64 + ((cpu_state.TOP + (r)) & 7) + IREG_SIZE_Q) +#define IREG_tag(r) (IREG_tag0 + ((cpu_state.TOP + (r)) & 7)) +#define IREG_tag_B(r) (IREG_tag0 + ((cpu_state.TOP + (r)) & 7) + IREG_SIZE_B) + +#define IREG_MM(reg) ((reg) + IREG_MM0) + +#define IREG_TOP_diff_stack_offset 32 + +static inline int ireg_seg_base(x86seg *seg) +{ + if (seg == &cpu_state.seg_cs) + return IREG_CS_base; + if (seg == &cpu_state.seg_ds) + return IREG_DS_base; + if (seg == &cpu_state.seg_es) + return IREG_ES_base; + if (seg == &cpu_state.seg_fs) + return IREG_FS_base; + if (seg == &cpu_state.seg_gs) + return IREG_GS_base; + if (seg == &cpu_state.seg_ss) + return IREG_SS_base; + fatal("ireg_seg_base : unknown segment\n"); + return 0; +} + +static inline int ireg_seg_limit_low(x86seg *seg) +{ + if (seg == &cpu_state.seg_cs) + return IREG_CS_limit_low; + if (seg == &cpu_state.seg_ds) + return IREG_DS_limit_low; + if (seg == &cpu_state.seg_es) + return IREG_ES_limit_low; + if (seg == &cpu_state.seg_fs) + return IREG_FS_limit_low; + if (seg == &cpu_state.seg_gs) + return IREG_GS_limit_low; + if (seg == &cpu_state.seg_ss) + return IREG_SS_limit_low; + fatal("ireg_seg_limit_low : unknown segment\n"); + return 0; +} +static inline int ireg_seg_limit_high(x86seg *seg) +{ + if (seg == &cpu_state.seg_cs) + return IREG_CS_limit_high; + if (seg == &cpu_state.seg_ds) + return IREG_DS_limit_high; + if (seg == &cpu_state.seg_es) + return IREG_ES_limit_high; + if (seg == &cpu_state.seg_fs) + return IREG_FS_limit_high; + if (seg == &cpu_state.seg_gs) + return IREG_GS_limit_high; + if (seg == &cpu_state.seg_ss) + return IREG_SS_limit_high; + fatal("ireg_seg_limit_high : unknown segment\n"); + return 0; +} + +extern uint8_t reg_last_version[IREG_COUNT]; + +/*This version of the register must be calculated, regardless of whether it is + apparently required or not. Do not optimise out.*/ +#define REG_FLAGS_REQUIRED (1 << 0) +/*This register and the parent uOP have been optimised out.*/ +#define REG_FLAGS_DEAD (1 << 1) + +typedef struct +{ + /*Refcount of pending reads on this register version*/ + uint8_t refcount; + /*Flags*/ + uint8_t flags; + /*uOP that generated this register version*/ + uint16_t parent_uop; + /*Pointer to next register version in dead register list*/ + uint16_t next; +} reg_version_t; + +extern reg_version_t reg_version[IREG_COUNT][256]; + +/*Head of dead register list; a list of register versions that are not used and + can be optimised out*/ +extern uint16_t reg_dead_list; + +static inline void add_to_dead_list(reg_version_t *regv, int reg, int version) +{ + regv->next = reg_dead_list; + reg_dead_list = version | (reg << 8); +} + +typedef struct +{ + uint16_t reg; + uint16_t version; +} ir_reg_t; + +extern ir_reg_t invalid_ir_reg; + +typedef uint16_t ir_host_reg_t; + +extern int max_version_refcount; + +#define REG_VERSION_MAX 250 +#define REG_REFCOUNT_MAX 250 + +static inline ir_reg_t codegen_reg_read(int reg) +{ + ir_reg_t ireg; + reg_version_t *version; + +#ifndef RELEASE_BUILD + if (IREG_GET_REG(reg) == IREG_INVALID) + fatal("codegen_reg_read - IREG_INVALID\n"); +#endif + ireg.reg = reg; + ireg.version = reg_last_version[IREG_GET_REG(reg)]; + version = ®_version[IREG_GET_REG(ireg.reg)][ireg.version]; + version->flags = 0; + version->refcount++; +#ifndef RELEASE_BUILD + if (!version->refcount) + fatal("codegen_reg_read - refcount overflow\n"); + else +#endif + if (version->refcount > REG_REFCOUNT_MAX) + CPU_BLOCK_END(); + if (version->refcount > max_version_refcount) + max_version_refcount = version->refcount; +// pclog("codegen_reg_read: %i %i %i\n", reg & IREG_REG_MASK, ireg.version, reg_version_refcount[IREG_GET_REG(ireg.reg)][ireg.version]); + return ireg; +} + +int reg_is_native_size(ir_reg_t ir_reg); + +static inline ir_reg_t codegen_reg_write(int reg, int uop_nr) +{ + ir_reg_t ireg; + int last_version = reg_last_version[IREG_GET_REG(reg)]; + reg_version_t *version; + +#ifndef RELEASE_BUILD + if (IREG_GET_REG(reg) == IREG_INVALID) + fatal("codegen_reg_write - IREG_INVALID\n"); +#endif + ireg.reg = reg; + ireg.version = last_version + 1; + + if (IREG_GET_REG(reg) > IREG_EBX && last_version && !reg_version[IREG_GET_REG(reg)][last_version].refcount && + !(reg_version[IREG_GET_REG(reg)][last_version].flags & REG_FLAGS_REQUIRED)) + { + if (reg_is_native_size(ireg)) /*Non-native size registers have an implicit dependency on the previous version, so don't add to dead list*/ + add_to_dead_list(®_version[IREG_GET_REG(reg)][last_version], IREG_GET_REG(reg), last_version); + } + + reg_last_version[IREG_GET_REG(reg)]++; +#ifndef RELEASE_BUILD + if (!reg_last_version[IREG_GET_REG(reg)]) + fatal("codegen_reg_write - version overflow\n"); + else +#endif + if (reg_last_version[IREG_GET_REG(reg)] > REG_VERSION_MAX) + CPU_BLOCK_END(); + if (reg_last_version[IREG_GET_REG(reg)] > max_version_refcount) + max_version_refcount = reg_last_version[IREG_GET_REG(reg)]; + + version = ®_version[IREG_GET_REG(reg)][ireg.version]; + version->refcount = 0; + version->flags = 0; + version->parent_uop = uop_nr; +// pclog("codegen_reg_write: %i\n", reg & IREG_REG_MASK); + return ireg; +} + +static inline int ir_reg_is_invalid(ir_reg_t ir_reg) +{ + return (IREG_GET_REG(ir_reg.reg) == IREG_INVALID); +} + +struct ir_data_t; + +void codegen_reg_reset(); +/*Write back all dirty registers*/ +void codegen_reg_flush(struct ir_data_t *ir, codeblock_t *block); +/*Write back and evict all registers*/ +void codegen_reg_flush_invalidate(struct ir_data_t *ir, codeblock_t *block); + +/*Register ir_reg usage for this uOP. This ensures that required registers aren't evicted*/ +void codegen_reg_alloc_register(ir_reg_t dest_reg_a, ir_reg_t src_reg_a, ir_reg_t src_reg_b, ir_reg_t src_reg_c); + +#ifdef CODEGEN_BACKEND_HAS_MOV_IMM +int codegen_reg_is_loaded(ir_reg_t ir_reg); +void codegen_reg_write_imm(codeblock_t *block, ir_reg_t ir_reg, uint32_t imm_data); +#endif + +ir_host_reg_t codegen_reg_alloc_read_reg(codeblock_t *block, ir_reg_t ir_reg, int *host_reg_idx); +ir_host_reg_t codegen_reg_alloc_write_reg(codeblock_t *block, ir_reg_t ir_reg); + +void codegen_reg_rename(codeblock_t *block, ir_reg_t src, ir_reg_t dst); + +void codegen_reg_mark_as_required(); +void codegen_reg_process_dead_list(struct ir_data_t *ir); +#endif diff --git a/src/codegen_timing_486.c b/src/codegen_timing_486.c index c88f9ca..6f9e3af 100644 --- a/src/codegen_timing_486.c +++ b/src/codegen_timing_486.c @@ -5,6 +5,8 @@ #include "x87.h" #include "mem.h" #include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" #define CYCLES(c) (int *)c #define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) @@ -247,9 +249,22 @@ static int *opcode_timings_8x[8] = { &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm }; +static int *opcode_timings_8x_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81_mod3[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 uint32_t regmask_modified; static inline int COUNT(int *c, int op_32) { @@ -266,6 +281,7 @@ static inline int COUNT(int *c, int op_32) void codegen_timing_486_block_start() { + regmask_modified = 0; } void codegen_timing_486_start() @@ -280,96 +296,143 @@ void codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat) last_prefix = prefix; } -void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) { int **timings; + uint64_t *deps; int mod3 = ((fetchdat & 0xc0) == 0xc0); - + int bit8 = !(opcode & 1); + switch (last_prefix) { case 0x0f: timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; +// pclog("timings 0f\n"); break; case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); break; case 0xd9: timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); break; case 0xda: timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); break; case 0xdb: timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); break; case 0xdc: timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); break; case 0xdd: timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); break; case 0xde: timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); break; case 0xdf: timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_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; + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + 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; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; +// pclog("timings c0\n"); break; case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); break; case 0xf7: timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); break; case 0xff: timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); break; default: timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; +// pclog("timings normal\n"); break; } } timing_count += COUNT(timings[opcode], op_32); + if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32)) + timing_count++; /*AGI stall*/ codegen_block_cycles += timing_count; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); } void codegen_timing_486_block_end() { } +int codegen_timing_486_jump_cycles() +{ + return 0; +} + 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 + codegen_timing_486_block_end, + codegen_timing_486_jump_cycles }; diff --git a/src/codegen_timing_686.c b/src/codegen_timing_686.c index efe7917..cc1e119 100644 --- a/src/codegen_timing_686.c +++ b/src/codegen_timing_686.c @@ -2,6 +2,7 @@ - X/Y pairing - FPU/FXCH pairing - Prefix decode delay + - AGI stalls Elements not taken into account : - Branch prediction (beyond most simplistic approximation) - FPU queue @@ -15,6 +16,7 @@ #include "x87.h" #include "mem.h" #include "codegen.h" +#include "codegen_timing_common.h" /*Instruction has different execution time for 16 and 32 bit data. Does not pair */ #define CYCLES_HAS_MULTI (1 << 31) @@ -33,11 +35,6 @@ #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*/ @@ -49,35 +46,6 @@ #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; @@ -85,119 +53,75 @@ static uint32_t prev_opcode; static uint32_t *prev_timings; static uint32_t prev_op_32; static uint32_t prev_regmask; +static uint64_t *prev_deps; +static uint32_t prev_fetchdat; -#define REGMASK_MMX (1 << 8) +static uint32_t last_regmask_modified; +static uint32_t regmask_modified; -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, +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), 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), +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), 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), +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, 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), +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, 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, +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, -/* 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, +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, -/* 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), +/* 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, PAIR_NP | CYCLES(10), PAIR_XY | CYCLES_REG, 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, @@ -205,37 +129,37 @@ static uint32_t opcode_timings[256] = 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), +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_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), +/* 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), PAIR_XY | CYCLES(9), 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 MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* 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, PAIR_XY | CYCLES_REG, 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, +/*b0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* RET imm RET*/ /*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), @@ -253,7 +177,7 @@ static uint32_t opcode_timings[256] = 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, +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, /* 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*/ @@ -273,68 +197,67 @@ static uint32_t opcode_timings[256] = 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, +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), 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), +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), 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), +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), -/* 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), +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, 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, +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, -/* 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, +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, -/* 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), +/* 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, PAIR_XY | CYCLES(10), PAIR_XY | CYCLES_REG, 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, @@ -342,13 +265,13 @@ static uint32_t opcode_timings_mod3[256] = 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), +/*80*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_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), @@ -357,22 +280,22 @@ static uint32_t opcode_timings_mod3[256] = /* 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), + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(9), 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, +/*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* 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), + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, 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, +/*b0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, /* RET imm RET*/ /*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), @@ -391,7 +314,7 @@ static uint32_t opcode_timings_mod3[256] = 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, +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, /* 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*/ @@ -441,15 +364,15 @@ static uint32_t opcode_timings_0f[256] = 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, +/*60*/ PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | 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, +/*70*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | 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, @@ -476,20 +399,20 @@ static uint32_t opcode_timings_0f[256] = 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, +/*d0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | 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, +/*e0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | 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, +/*f0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | 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] = { @@ -523,15 +446,15 @@ static uint32_t opcode_timings_0f_mod3[256] = 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, +/*60*/ PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | 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, +/*70*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | 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, @@ -557,20 +480,20 @@ static uint32_t opcode_timings_0f_mod3[256] = 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, +/*d0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + INVALID, PAIR_X | 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, +/*e0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, + INVALID, PAIR_X | 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, +/*f0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + INVALID, PAIR_X | 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] = @@ -580,8 +503,8 @@ static uint32_t opcode_timings_shift[8] = }; 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, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, }; static uint32_t opcode_timings_shift_imm[8] = { @@ -590,18 +513,18 @@ static uint32_t opcode_timings_shift_imm[8] = }; 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, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, }; 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, + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), }; 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, + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), }; static uint32_t opcode_timings_f6[8] = @@ -613,22 +536,22 @@ static uint32_t opcode_timings_f6[8] = }; 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), +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG, 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), + PAIR_XY | CYCLES_REG, 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), + PAIR_XY | CYCLES_REG, 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) }; @@ -637,14 +560,14 @@ 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 + PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(1), 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 +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, 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), INVALID }; static uint32_t opcode_timings_d8[8] = @@ -812,8 +735,23 @@ static uint32_t opcode_timings_df_mod3[8] = 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 + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM +}; +static uint32_t opcode_timings_8x_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG +}; +static uint32_t opcode_timings_81[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM +}; +static uint32_t opcode_timings_81_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG }; static int decode_delay; @@ -836,6 +774,7 @@ static inline int COUNT(uint32_t c, int op_32) void codegen_timing_686_block_start() { prev_full = decode_delay = 0; + regmask_modified = last_regmask_modified = 0; } void codegen_timing_686_start() @@ -846,6 +785,18 @@ void codegen_timing_686_start() void codegen_timing_686_prefix(uint8_t prefix, uint32_t fetchdat) { + if ((prefix & 0xf8) == 0xd8) + { + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) + { + /*0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + /*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*/ @@ -853,9 +804,29 @@ void codegen_timing_686_prefix(uint8_t prefix, uint32_t fetchdat) last_prefix = prefix; } -void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + if (addr_regmask & IMPL_ESP) + addr_regmask |= (1 << REG_ESP); + + if (regmask_modified & addr_regmask) + { + regmask_modified = 0; + return 2; + } + + if (last_regmask_modified & addr_regmask) + return 1; + + return 0; +} + +void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) { uint32_t *timings; + uint64_t *deps; int mod3 = ((fetchdat & 0xc0) == 0xc0); int bit8 = !(opcode & 1); @@ -863,46 +834,55 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) { case 0x0f: timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; // pclog("timings 0f\n"); break; case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; opcode = (opcode >> 3) & 7; // pclog("timings d8\n"); break; case 0xd9: timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; // pclog("timings d9\n"); break; case 0xda: timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; opcode = (opcode >> 3) & 7; // pclog("timings da\n"); break; case 0xdb: timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; // pclog("timings db\n"); break; case 0xdc: timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; opcode = (opcode >> 3) & 7; // pclog("timings dc\n"); break; case 0xdd: timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; opcode = (opcode >> 3) & 7; // pclog("timings dd\n"); break; case 0xde: timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; opcode = (opcode >> 3) & 7; // pclog("timings de\n"); break; case 0xdf: timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; opcode = (opcode >> 3) & 7; // pclog("timings df\n"); break; @@ -910,66 +890,92 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) 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; + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + 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; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; +// pclog("timings c0\n"); break; - + case 0xd0: case 0xd1: timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; +// pclog("timings d0\n"); break; - + case 0xd2: case 0xd3: timings = mod3 ? opcode_timings_shift_cl_mod3 : opcode_timings_shift_cl; + deps = mod3 ? opcode_deps_shift_cl_mod3 : opcode_deps_shift_cl; opcode = (fetchdat >> 3) & 7; +// pclog("timings d2\n"); break; case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; opcode = (fetchdat >> 3) & 7; // pclog("timings f6\n"); break; case 0xf7: timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; opcode = (fetchdat >> 3) & 7; // pclog("timings f7\n"); break; case 0xff: timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; opcode = (fetchdat >> 3) & 7; // pclog("timings ff\n"); break; default: timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; // pclog("timings normal\n"); break; } } - + + /*One prefix per instruction is free*/ + decode_delay--; if (decode_delay < 0) decode_delay = 0; if (prev_full) { - uint8_t regmask = get_srcdep_mask(timings[opcode], fetchdat, bit8); - + uint32_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, op_32); + int agi_stall = 0; + + if (regmask & IMPL_ESP) + regmask |= SRCDEP_ESP | DSTDEP_ESP; + + agi_stall = check_agi(prev_deps, prev_opcode, prev_fetchdat, prev_op_32); + /*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; + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; // 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) @@ -977,18 +983,22 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) { /*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; + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; // 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; + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; // pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); } else @@ -999,9 +1009,14 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) if (!t_pair) fatal("Pairable 0 cycles! %02x %02x\n", opcode, prev_opcode); - codegen_block_cycles += t_pair; - decode_delay = (-t_pair) + 1; + + agi_stall = check_agi(deps, opcode, fetchdat, op_32); + + codegen_block_cycles += t_pair + agi_stall; + decode_delay = (-t_pair) + 1 + agi_stall; + last_regmask_modified = regmask_modified; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | prev_regmask; prev_full = 0; // pclog("Pairable %i %i %i %02x %02x\n", t_pair, t1, t2, opcode, prev_opcode); return; @@ -1014,8 +1029,14 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) 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; + int agi_stall = 0; + + agi_stall = check_agi(deps, opcode, fetchdat, op_32); + + codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(timings[opcode], op_32)) + 1 + agi_stall; + last_regmask_modified = regmask_modified; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); // pclog("Not pairable %i\n", COUNT(timings[opcode], op_32) + decode_delay); } else @@ -1026,7 +1047,11 @@ void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) prev_opcode = opcode; prev_timings = timings; prev_op_32 = op_32; - prev_regmask = get_dstdep_mask(timings[opcode], fetchdat, bit8); + prev_regmask = get_dstdep_mask(deps[opcode], fetchdat, bit8); + if (prev_regmask & IMPL_ESP) + prev_regmask |= SRCDEP_ESP | DSTDEP_ESP; + prev_deps = deps; + prev_fetchdat = fetchdat; return; } } @@ -1042,11 +1067,17 @@ void codegen_timing_686_block_end() } } +int codegen_timing_686_jump_cycles() +{ + return 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 + codegen_timing_686_block_end, + codegen_timing_686_jump_cycles }; diff --git a/src/codegen_timing_common.c b/src/codegen_timing_common.c new file mode 100644 index 0000000..a74410f --- /dev/null +++ b/src/codegen_timing_common.c @@ -0,0 +1,843 @@ +#include "ibm.h" +#include "codegen_timing_common.h" + +uint64_t opcode_deps[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* ADD ADD PUSH ES POP ES*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, +/* OR OR OR OR*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* OR OR PUSH CS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, 0, + +/* ADC ADC ADC ADC*/ +/*10*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* ADC ADC PUSH SS POP SS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, +/* SBB SBB SBB SBB*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* SBB SBB PUSH DS POP DS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, + +/* AND AND AND AND*/ +/*20*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* AND AND DAA*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, +/* SUB SUB SUB SUB*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* SUB SUB DAS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* XOR XOR XOR XOR*/ +/*30*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* XOR XOR AAA*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, +/* CMP CMP CMP CMP*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, +/* CMP CMP AAS*/ + SRCDEP_EAX | HAS_IMM8, SRCDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ SRCDEP_EAX | IMPL_ESP, SRCDEP_ECX | IMPL_ESP, SRCDEP_EDX | IMPL_ESP, SRCDEP_EBX | IMPL_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + SRCDEP_ESP | IMPL_ESP, SRCDEP_EBP | IMPL_ESP, SRCDEP_ESI | IMPL_ESP, SRCDEP_EDI | IMPL_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + DSTDEP_EAX | IMPL_ESP, DSTDEP_ECX | IMPL_ESP, DSTDEP_EDX | IMPL_ESP, DSTDEP_EBX | IMPL_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + DSTDEP_ESP | IMPL_ESP, DSTDEP_EBP | IMPL_ESP, DSTDEP_ESI | IMPL_ESP, DSTDEP_EDI | IMPL_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ IMPL_ESP, IMPL_ESP, 0, 0, + 0, 0, 0, 0, +/* PUSH imm IMUL PUSH imm IMUL*/ + IMPL_ESP | HAS_IMM1632,DSTDEP_REG | MODRM, IMPL_ESP | HAS_IMM8, DSTDEP_REG | MODRM, +/* INSB INSW OUTSB OUTSW*/ + 0, 0, 0, 0, + +/* Jxx*/ +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, +/* TEST TEST XCHG XCHG*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* MOV MOV MOV MOV*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, +/* MOV from seg LEA MOV to seg POP*/ + MODRM, DSTDEP_REG | MODRM, MODRM, IMPL_ESP | MODRM, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ 0, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBX | DSTDEP_EBX, +/* XCHG XCHG XCHG XCHG*/ + SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBP | DSTDEP_EBP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDI | DSTDEP_EDI, +/* CBW CWD CALL far WAIT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EDX, 0, 0, +/* PUSHF POPF SAHF LAHF*/ + IMPL_ESP, IMPL_ESP, SRCDEP_EAX, DSTDEP_EAX, + +/* MOV MOV MOV MOV*/ +/*a0*/ DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + 0, 0, 0, 0, +/* TEST TEST STOSB STOSW*/ + SRCDEP_EAX, SRCDEP_EAX, 0, 0, +/* LODSB LODSW SCASB SCASW*/ + 0, 0, 0, 0, + +/* MOV*/ +/*b0*/ DSTDEP_EAX | HAS_IMM8, DSTDEP_ECX | HAS_IMM8, DSTDEP_EDX | HAS_IMM8, DSTDEP_EBX | HAS_IMM8, + DSTDEP_EAX | HAS_IMM8, DSTDEP_ECX | HAS_IMM8, DSTDEP_EDX | HAS_IMM8, DSTDEP_EBX | HAS_IMM8, + DSTDEP_EAX | HAS_IMM1632, DSTDEP_ECX | HAS_IMM1632, DSTDEP_EDX | HAS_IMM1632, DSTDEP_EBX | HAS_IMM1632, + DSTDEP_ESP | HAS_IMM1632, DSTDEP_EBP | HAS_IMM1632, DSTDEP_ESI | HAS_IMM1632, DSTDEP_EDI | HAS_IMM1632, + +/* RET imm RET*/ +/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, +/* LES LDS MOV MOV*/ + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, MODRM | HAS_IMM8, MODRM | HAS_IMM1632, +/* ENTER LEAVE RETF RETF*/ + IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, +/* INT3 INT INTO IRET*/ + 0, 0, 0, 0, + + +/*d0*/ 0, 0, 0, 0, +/* AAM AAD SETALC XLAT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX | SRCDEP_EBX, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* CALL JMP JMP JMP*/ + IMPL_ESP, 0, 0, 0, +/* IN AL IN AX OUT_AL OUT_AX*/ + SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, + +/* REPNE REPE*/ +/*f0*/ 0, 0, 0, 0, +/* HLT CMC*/ + 0, 0, 0, 0, +/* CLC STC CLI STI*/ + 0, 0, 0, 0, +/* CLD STD INCDEC*/ + 0, 0, MODRM, 0 +}; + +uint64_t opcode_deps_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* ADD ADD PUSH ES POP ES*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, +/* OR OR OR OR*/ + SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* OR OR PUSH CS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, 0, + +/* ADC ADC ADC ADC*/ +/*10*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* ADC ADC PUSH SS POP SS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, +/* SBB SBB SBB SBB*/ + SRCDEP_REG |SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* SBB SBB PUSH DS POP DS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, IMPL_ESP, IMPL_ESP, + +/* AND AND AND AND*/ +/*20*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* AND AND DAA*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, +/* SUB SUB SUB SUB*/ + SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* SUB SUB DAS*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* XOR XOR XOR XOR*/ +/*30*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* XOR XOR AAA*/ + SRCDEP_EAX | DSTDEP_EAX | HAS_IMM8, SRCDEP_EAX | DSTDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, +/* CMP CMP CMP CMP*/ + SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, +/* CMP CMP AAS*/ + SRCDEP_EAX | HAS_IMM8, SRCDEP_EAX | HAS_IMM1632, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ SRCDEP_EAX | IMPL_ESP, SRCDEP_ECX | IMPL_ESP, SRCDEP_EDX | IMPL_ESP, SRCDEP_EBX | IMPL_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + SRCDEP_ESP | IMPL_ESP, SRCDEP_EBP | IMPL_ESP, SRCDEP_ESI | IMPL_ESP, SRCDEP_EDI | IMPL_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + DSTDEP_EAX | IMPL_ESP, DSTDEP_ECX | IMPL_ESP, DSTDEP_EDX | IMPL_ESP, DSTDEP_EBX | IMPL_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + DSTDEP_ESP | IMPL_ESP, DSTDEP_EBP | IMPL_ESP, DSTDEP_ESI | IMPL_ESP, DSTDEP_EDI | IMPL_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ IMPL_ESP, IMPL_ESP, 0, 0, + 0, 0, 0, 0, +/* PUSH imm IMUL PUSH imm IMUL*/ + IMPL_ESP | HAS_IMM1632,DSTDEP_REG | SRCDEP_RM | MODRM, IMPL_ESP | HAS_IMM8, DSTDEP_REG | SRCDEP_RM | MODRM, +/* INSB INSW OUTSB OUTSW*/ + 0, 0, 0, 0, + +/* Jxx*/ +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, +/* TEST TEST XCHG XCHG*/ + SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, +/* MOV MOV MOV MOV*/ + SRCDEP_REG | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_REG | MODRM, SRCDEP_RM | DSTDEP_REG | MODRM, +/* MOV from seg LEA MOV to seg POP*/ + DSTDEP_RM | MODRM, DSTDEP_REG | MODRM, SRCDEP_RM | MODRM, IMPL_ESP | DSTDEP_RM | MODRM, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ 0, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBX | DSTDEP_EBX, +/* XCHG XCHG XCHG XCHG*/ + SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBP | DSTDEP_EBP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDI | DSTDEP_EDI, +/* CBW CWD CALL far WAIT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EDX, 0, 0, +/* PUSHF POPF SAHF LAHF*/ + IMPL_ESP, IMPL_ESP, SRCDEP_EAX, DSTDEP_EAX, + +/* MOV MOV MOV MOV*/ +/*a0*/ DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + 0, 0, 0, 0, +/* TEST TEST STOSB STOSW*/ + SRCDEP_EAX, SRCDEP_EAX, 0, 0, +/* LODSB LODSW SCASB SCASW*/ + 0, 0, 0, 0, + +/* MOV*/ +/*b0*/ DSTDEP_EAX | HAS_IMM8, DSTDEP_ECX | HAS_IMM8, DSTDEP_EDX | HAS_IMM8, DSTDEP_EBX | HAS_IMM8, + DSTDEP_EAX | HAS_IMM8, DSTDEP_ECX | HAS_IMM8, DSTDEP_EDX | HAS_IMM8, DSTDEP_EBX | HAS_IMM8, + DSTDEP_EAX | HAS_IMM1632, DSTDEP_ECX | HAS_IMM1632, DSTDEP_EDX | HAS_IMM1632, DSTDEP_EBX | HAS_IMM1632, + DSTDEP_ESP | HAS_IMM1632, DSTDEP_EBP | HAS_IMM1632, DSTDEP_ESI | HAS_IMM1632, DSTDEP_EDI | HAS_IMM1632, + +/* RET imm RET*/ +/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, +/* LES LDS MOV MOV*/ + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_RM | MODRM | HAS_IMM8, DSTDEP_RM | MODRM | HAS_IMM1632, +/* ENTER LEAVE RETF RETF*/ + IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, +/* INT3 INT INTO IRET*/ + 0, 0, 0, 0, + + +/*d0*/ 0, 0, 0, 0, +/* AAM AAD SETALC XLAT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX | SRCDEP_EBX, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* CALL JMP JMP JMP*/ + IMPL_ESP, 0, 0, 0, +/* IN AL IN AX OUT_AL OUT_AX*/ + SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, + +/* REPNE REPE*/ +/*f0*/ 0, 0, 0, 0, +/* HLT CMC*/ + 0, 0, 0, 0, +/* CLC STC CLI STI*/ + 0, 0, 0, 0, +/* CLD STD INCDEC*/ + 0, 0, SRCDEP_RM | DSTDEP_RM | MODRM, 0 +}; + +uint64_t opcode_deps_0f[256] = +{ +/*00*/ MODRM, MODRM, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, MODRM, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*20*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 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*/ MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, MODRM, + MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, 0, MODRM, MODRM, + +/*70*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, 0, + 0, 0, 0, 0, + 0, 0, MODRM, MODRM, + +/*80*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*90*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*a0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*b0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + 0, 0, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*c0*/ MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*e0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*f0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, MODRM, 0, + MODRM, MODRM, MODRM, 0, +}; +uint64_t opcode_deps_0f_mod3[256] = +{ +/*00*/ MODRM, MODRM, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, MODRM, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*20*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 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*/ MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, MODRM, + MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, 0, MODRM, MODRM, + +/*70*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, 0, + 0, 0, 0, 0, + 0, 0, MODRM, MODRM, + +/*80*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*90*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*a0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*b0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + 0, 0, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*c0*/ MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*e0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*f0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, MODRM, 0, + MODRM, MODRM, MODRM, 0, +}; + +uint64_t opcode_deps_0f0f[256] = +{ +/*00*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, 0, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 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*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*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*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, MODRM, 0, + 0, 0, MODRM, 0, + +/*a0*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*b0*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, MODRM, + +/*c0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, 0, 0, 0, + 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*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, +}; +uint64_t opcode_deps_0f0f_mod3[256] = +{ +/*00*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 0, 0, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, MODRM, 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*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*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*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, MODRM, 0, + 0, 0, MODRM, 0, + +/*a0*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*b0*/ MODRM, 0, 0, 0, + MODRM, 0, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, MODRM, + +/*c0*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, 0, 0, 0, + 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*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, +}; + +uint64_t opcode_deps_shift[8] = +{ + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, +}; +uint64_t opcode_deps_shift_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +}; + +uint64_t opcode_deps_shift_cl[8] = +{ + MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, + MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, +}; +uint64_t opcode_deps_shift_cl_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, + SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, +}; + +uint64_t opcode_deps_f6[8] = +{ +/* TST NOT NEG*/ + MODRM, 0, MODRM, MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f6_mod3[8] = +{ +/* TST NOT NEG*/ + SRCDEP_RM | MODRM, 0, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f7[8] = +{ +/* TST NOT NEG*/ + MODRM, 0, MODRM, MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f7_mod3[8] = +{ +/* TST NOT NEG*/ + SRCDEP_RM | MODRM, 0, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_ff[8] = +{ +/* INC DEC CALL CALL far*/ + MODRM, MODRM, MODRM | IMPL_ESP, MODRM, +/* JMP JMP far PUSH*/ + MODRM, MODRM, MODRM | IMPL_ESP, 0 +}; +uint64_t opcode_deps_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | MODRM | IMPL_ESP, MODRM, +/* JMP JMP far PUSH*/ + SRCDEP_RM | MODRM, MODRM, SRCDEP_RM | MODRM | IMPL_ESP, 0 +}; + +uint64_t opcode_deps_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_POP | FPU_READ_ST0 | MODRM, +/* FSUBs FSUBRs FDIVs FDIVRs*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_READ_ST0 | FPU_READ_STREG, FPU_POP | FPU_READ_ST0 | FPU_READ_STREG, +/* FSUB FSUBR FDIV FDIVR*/ + FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG +}; + +uint64_t opcode_deps_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_POP | MODRM, +/* FLDENV FLDCW FSTENV FSTCW*/ + MODRM, MODRM, MODRM, MODRM +}; +uint64_t opcode_deps_d9_mod3[64] = +{ + /*FLD*/ + FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, + FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, + /*FXCH*/ + FPU_FXCH, FPU_FXCH, FPU_FXCH, FPU_FXCH, + FPU_FXCH, FPU_FXCH, FPU_FXCH, FPU_FXCH, + /*FNOP*/ + 0, 0, 0, 0, 0, 0, 0, 0, + /*FSTP*/ + FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, + FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, +/* opFCHS opFABS*/ + 0, 0, 0, 0, +/* opFTST opFXAM*/ + 0, 0, 0, 0, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + FPU_PUSH, FPU_PUSH, FPU_PUSH, FPU_PUSH, +/* opFLDEG2 opFLDLN2 opFLDZ*/ + FPU_PUSH, FPU_PUSH, FPU_PUSH, 0, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + 0, 0, 0, 0, +/* opFDECSTP opFINCSTP,*/ + 0, 0, 0, 0, +/* opFPREM opFSQRT opFSINCOS*/ + 0, 0, 0, 0, +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + 0, 0, 0, 0 +}; + +uint64_t opcode_deps_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_da_mod3[8] = +{ + 0, 0, 0, 0, +/* FCOMPP*/ + 0, FPU_POP2, 0, 0 +}; + + +uint64_t opcode_deps_db[8] = +{ +/* FLDil FSTil FSTPil*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FLDe FSTPe*/ + 0, FPU_PUSH | MODRM, 0, FPU_READ_ST0 | FPU_POP | MODRM +}; +uint64_t opcode_deps_db_mod3[64] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + + 0, 0, 0, 0, 0, 0, 0, 0, + +/* opFNOP opFCLEX opFINIT*/ + 0, 0, 0, 0, +/* opFNOP opFNOP*/ + 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +uint64_t opcode_deps_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FSUBd FSUBRd FDIVd FDIVRd*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, 0, 0, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG +}; + +uint64_t opcode_deps_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FRSTOR FSAVE FSTSW*/ + MODRM, 0, MODRM, MODRM +}; +uint64_t opcode_deps_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + 0, 0, FPU_READ_ST0 | FPU_WRITE_STREG, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, +/* FUCOM FUCOMP*/ + FPU_READ_ST0 | FPU_READ_STREG, FPU_READ_ST0 | FPU_READ_STREG | FPU_POP, 0, 0 +}; + +uint64_t opcode_deps_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, 0, FPU_READ_ST0 | FPU_READ_ST1 | FPU_POP2, +/* FSUBP FSUBRP FDIVP FDIVRP*/ + FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP +}; + +uint64_t opcode_deps_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FILDiq FBSTP FISTPiq*/ + 0, FPU_PUSH | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, FPU_READ_ST0 | FPU_POP | MODRM +}; +uint64_t opcode_deps_df_mod3[8] = +{ + 0, 0, 0, 0, +/* FSTSW AX*/ + 0, 0, 0, 0 +}; + +uint64_t opcode_deps_81[8] = +{ + MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, + MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, MODRM | HAS_IMM1632, MODRM | HAS_IMM1632 +}; +uint64_t opcode_deps_81_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, + SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM1632, SRCDEP_RM | MODRM | HAS_IMM1632 +}; +uint64_t opcode_deps_8x[8] = +{ + MODRM | HAS_IMM8, MODRM | HAS_IMM8, MODRM | HAS_IMM8, MODRM | HAS_IMM8, + MODRM | HAS_IMM8, MODRM | HAS_IMM8, MODRM | HAS_IMM8, MODRM | HAS_IMM8 +}; +uint64_t opcode_deps_8x_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, + SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | DSTDEP_RM | MODRM | HAS_IMM8, SRCDEP_RM | MODRM | HAS_IMM8 +}; diff --git a/src/codegen_timing_common.h b/src/codegen_timing_common.h new file mode 100644 index 0000000..533a135 --- /dev/null +++ b/src/codegen_timing_common.h @@ -0,0 +1,231 @@ +#include "codegen_ops.h" + +/*Instruction has input dependency on register in REG field*/ +#define SRCDEP_REG (1ull << 0) +/*Instruction has input dependency on register in R/M field*/ +#define SRCDEP_RM (1ull << 1) +/*Instruction modifies register in REG field*/ +#define DSTDEP_REG (1ull << 2) +/*Instruction modifies register in R/M field*/ +#define DSTDEP_RM (1ull << 3) + +#define SRCDEP_SHIFT 4 +#define DSTDEP_SHIFT 12 + +/*Instruction has input dependency on given register*/ +#define SRCDEP_EAX (1ull << 4) +#define SRCDEP_ECX (1ull << 5) +#define SRCDEP_EDX (1ull << 6) +#define SRCDEP_EBX (1ull << 7) +#define SRCDEP_ESP (1ull << 8) +#define SRCDEP_EBP (1ull << 9) +#define SRCDEP_ESI (1ull << 10) +#define SRCDEP_EDI (1ull << 11) + +/*Instruction modifies given register*/ +#define DSTDEP_EAX (1ull << 12) +#define DSTDEP_ECX (1ull << 13) +#define DSTDEP_EDX (1ull << 14) +#define DSTDEP_EBX (1ull << 15) +#define DSTDEP_ESP (1ull << 16) +#define DSTDEP_EBP (1ull << 17) +#define DSTDEP_ESI (1ull << 18) +#define DSTDEP_EDI (1ull << 19) + +/*Instruction has ModR/M byte*/ +#define MODRM (1ull << 20) +/*Instruction implicitly uses ESP*/ +#define IMPL_ESP (1ull << 21) + +/*Instruction is MMX shift or pack/unpack instruction*/ +#define MMX_SHIFTPACK (1ull << 22) +/*Instruction is MMX multiply instruction*/ +#define MMX_MULTIPLY (1ull << 23) + +/*Instruction pops the FPU stack*/ +#define FPU_POP (1ull << 24) +/*Instruction pops the FPU stack twice*/ +#define FPU_POP2 (1ull << 25) +/*Instruction pushes onto the FPU stack*/ +#define FPU_PUSH (1ull << 26) + +/*Instruction writes to ST(0)*/ +#define FPU_WRITE_ST0 (1ull << 27) +/*Instruction reads from ST(0)*/ +#define FPU_READ_ST0 (1ull << 28) +/*Instruction reads from and writes to ST(0)*/ +#define FPU_RW_ST0 (3ull << 27) + +/*Instruction reads from ST(1)*/ +#define FPU_READ_ST1 (1ull << 29) +/*Instruction writes to ST(1)*/ +#define FPU_WRITE_ST1 (1ull << 30) +/*Instruction reads from and writes to ST(1)*/ +#define FPU_RW_ST1 (3ull << 29) + +/*Instruction reads from ST(reg)*/ +#define FPU_READ_STREG (1ull << 31) +/*Instruction writes to ST(reg)*/ +#define FPU_WRITE_STREG (1ull << 32) +/*Instruction reads from and writes to ST(reg)*/ +#define FPU_RW_STREG (3ull << 30) + +#define FPU_FXCH (1ull << 33) + +#define HAS_IMM8 (1ull << 34) +#define HAS_IMM1632 (1ull << 35) + + +#define REGMASK_IMPL_ESP (1 << 8) +#define REGMASK_SHIFTPACK (1 << 9) +#define REGMASK_MULTIPLY (1 << 9) + + +extern uint64_t opcode_deps[256]; +extern uint64_t opcode_deps_mod3[256]; +extern uint64_t opcode_deps_0f[256]; +extern uint64_t opcode_deps_0f_mod3[256]; +extern uint64_t opcode_deps_0f0f[256]; +extern uint64_t opcode_deps_0f0f_mod3[256]; +extern uint64_t opcode_deps_shift[8]; +extern uint64_t opcode_deps_shift_mod3[8]; +extern uint64_t opcode_deps_shift_cl[8]; +extern uint64_t opcode_deps_shift_cl_mod3[8]; +extern uint64_t opcode_deps_f6[8]; +extern uint64_t opcode_deps_f6_mod3[8]; +extern uint64_t opcode_deps_f7[8]; +extern uint64_t opcode_deps_f7_mod3[8]; +extern uint64_t opcode_deps_ff[8]; +extern uint64_t opcode_deps_ff_mod3[8]; +extern uint64_t opcode_deps_d8[8]; +extern uint64_t opcode_deps_d8_mod3[8]; +extern uint64_t opcode_deps_d9[8]; +extern uint64_t opcode_deps_d9_mod3[64]; +extern uint64_t opcode_deps_da[8]; +extern uint64_t opcode_deps_da_mod3[8]; +extern uint64_t opcode_deps_db[8]; +extern uint64_t opcode_deps_db_mod3[64]; +extern uint64_t opcode_deps_dc[8]; +extern uint64_t opcode_deps_dc_mod3[8]; +extern uint64_t opcode_deps_dd[8]; +extern uint64_t opcode_deps_dd_mod3[8]; +extern uint64_t opcode_deps_de[8]; +extern uint64_t opcode_deps_de_mod3[8]; +extern uint64_t opcode_deps_df[8]; +extern uint64_t opcode_deps_df_mod3[8]; +extern uint64_t opcode_deps_81[8]; +extern uint64_t opcode_deps_81_mod3[8]; +extern uint64_t opcode_deps_8x[8]; +extern uint64_t opcode_deps_8x_mod3[8]; + + + +static inline uint32_t get_addr_regmask(uint64_t data, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = 0; + + if (data & MODRM) + { + uint8_t modrm = fetchdat & 0xff; + + if ((modrm & 0xc0) != 0xc0) + { + if (op_32 & 0x200) + { + if ((modrm & 0x7) == 4) + { + uint8_t sib = (fetchdat >> 8) & 0xff; + + if ((modrm & 0xc0) != 0xc0 && (sib & 7) != 5) + { + addr_regmask = 1 << (sib & 7); + if ((sib & 0x38) != 0x20) + addr_regmask |= 1 << ((sib >> 3) & 7); + } + } + else if ((modrm & 0xc7) != 5) + { + addr_regmask = 1 << (modrm & 7); + } + } + else + { + if ((modrm & 0xc7) != 0x06) + { + switch (modrm & 7) + { + case 0: addr_regmask = REG_BX | REG_SI; break; + case 1: addr_regmask = REG_BX | REG_DI; break; + case 2: addr_regmask = REG_BP | REG_SI; break; + case 3: addr_regmask = REG_BP | REG_DI; break; + case 4: addr_regmask = REG_SI; break; + case 5: addr_regmask = REG_DI; break; + case 6: addr_regmask = REG_BP; break; + case 7: addr_regmask = REG_BX; break; + } + } + } + } + } + + if (data & IMPL_ESP) + addr_regmask |= REGMASK_IMPL_ESP; + + return addr_regmask; +} + +static inline uint32_t get_srcdep_mask(uint64_t data, uint32_t fetchdat, int bit8, int op_32) +{ + 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 >> SRCDEP_SHIFT) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + + mask |= get_addr_regmask(data, fetchdat, op_32); + + return mask; +} + +static inline uint32_t get_dstdep_mask(uint64_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 >> DSTDEP_SHIFT) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + if (data & IMPL_ESP) + mask |= REGMASK_IMPL_ESP | (1 << REG_ESP); + + return mask; +} diff --git a/src/codegen_timing_cyrixiii.c b/src/codegen_timing_cyrixiii.c new file mode 100644 index 0000000..c89defc --- /dev/null +++ b/src/codegen_timing_cyrixiii.c @@ -0,0 +1,679 @@ +/*Since VIA didn't document cycle timings in the Cyrix III/C3 datasheets, and + I don't currently own either chip to test against, most of the timing here is + a guess. This code makes the current (probably wrong) assumptions, based on the + few details in the Cyrix III datasheet : + - Most common integer instructions are 1 cycle, including register-memory and + memory-register versions + - Basic FPU instructions are 2 cycles. The datasheet claims "a non-dependent + add or multiply can start every two clocks"; it's not clear if this is referring + to CPU or FPU clocks, since the FPU runs at 1/2 CPU speed on these chips. + - MMX instructions are 1 cycle + - No instruction pairing of any kind (unlike WinChip 2) + - Prefixes other than 0x0f cost 1 cycle each + - AGI stalls cost 1 cycle, except for implicit references to ESP*/ +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 31) + +#define CYCLES_FPU (1 << 30) + +#define CYCLES_IS_MMX_MUL (1 << 29) +#define CYCLES_IS_MMX_SHIFT (1 << 28) +#define CYCLES_IS_MMX_ANY (1 << 27) +#define CYCLES_IS_3DNOW (1 << 26) + +#define CYCLES_MMX_MUL(c) (CYCLES_IS_MMX_MUL | c) +#define CYCLES_MMX_SHIFT(c) (CYCLES_IS_MMX_SHIFT | c) +#define CYCLES_MMX_ANY(c) (CYCLES_IS_MMX_ANY | c) +#define CYCLES_3DNOW(c) (CYCLES_IS_3DNOW | c) + +#define CYCLES_IS_MMX (CYCLES_IS_MMX_MUL | CYCLES_IS_MMX_SHIFT | CYCLES_IS_MMX_ANY | CYCLES_IS_3DNOW) + +#define GET_CYCLES(c) (c & ~(CYCLES_HAS_MULTI | CYCLES_FPU | CYCLES_IS_MMX)) + +#define CYCLES(c) c +#define CYCLES2(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*comp_time = cycles until instruction complete + i_overlap = cycles that overlap with integer + f_overlap = cycles that overlap with subsequent FPU*/ +#define FPU_CYCLES(comp_time, i_overlap, f_overlap) (comp_time) | (i_overlap << 8) | (f_overlap << 16) | CYCLES_FPU + +#define FPU_COMP_TIME(timing) (timing & 0xff) +#define FPU_I_OVERLAP(timing) ((timing >> 8) & 0xff) +#define FPU_F_OVERLAP(timing) ((timing >> 16) & 0xff) + +#define FPU_I_LATENCY(timing) (FPU_COMP_TIME(timing) - FPU_I_OVERLAP(timing)) + +#define FPU_F_LATENCY(timing) (FPU_I_OVERLAP(timing) - FPU_F_OVERLAP(timing)) + +#define FPU_RESULT_LATENCY(timing) ((timing >> 8) & 0xff) + +#define INVALID 0 + +static uint32_t opcode_timings[256] = +{ +/*00*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), INVALID, +/*10*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), +/*20*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), +/*30*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), + +/*40*/ 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), +/*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(1), CYCLES(1), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ 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), + +/*80*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(2), 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*/ 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), + +/*c0*/ CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*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), INVALID, INVALID, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/*00*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), INVALID, +/*10*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), +/*20*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), +/*30*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), + +/*40*/ 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), +/*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(1), CYCLES(1), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ 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), + +/*80*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), 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*/ 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), + +/*c0*/ CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*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), INVALID, INVALID, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), INVALID, +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), INVALID, CYCLES(195), CYCLES(7), INVALID, CYCLES(1000), CYCLES(10000), INVALID, INVALID, INVALID, CYCLES_3DNOW(1), CYCLES(1), CYCLES_3DNOW(1), +/*10*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*30*/ CYCLES(9), CYCLES(1), 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*/ CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), +/*70*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES(100), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), + +/*80*/ 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), +/*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), INVALID, INVALID, CYCLES(3), CYCLES(3), INVALID, CYCLES(13), CYCLES(3), CYCLES(3), INVALID, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), INVALID, INVALID, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), +/*e0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), +/*f0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(2), INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), INVALID, CYCLES(195), CYCLES(7), INVALID, CYCLES(1000), CYCLES(10000), INVALID, INVALID, INVALID, CYCLES_3DNOW(1), CYCLES(1), CYCLES_3DNOW(1), +/*10*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*30*/ CYCLES(9), CYCLES(1), 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*/ CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), +/*70*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES(100), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), + +/*80*/ 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), +/*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), INVALID, INVALID, CYCLES(3), CYCLES(3), INVALID, CYCLES(13), CYCLES(3), CYCLES(3), INVALID, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), INVALID, INVALID, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), +/*e0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), +/*f0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static uint32_t opcode_timings_f6[8] = +{ + CYCLES(2), INVALID, CYCLES(2), CYCLES(2), CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ + CYCLES(1), INVALID, CYCLES(1), CYCLES(1), CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static uint32_t opcode_timings_f7[8] = +{ + CYCLES(2), INVALID, CYCLES(2), CYCLES(2), CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ + CYCLES(1), INVALID, CYCLES(1), CYCLES(1), CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static uint32_t opcode_timings_ff[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ + CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FSUB FSUBR FDIV FDIVR*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + FPU_CYCLES(2,0,0), INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FLDENV FLDCW FSTENV FSTCW*/ + FPU_CYCLES(32,0,0), FPU_CYCLES(8,0,0), FPU_CYCLES(48,0,0), FPU_CYCLES(2,0,0) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), + /*FXCH*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), + /*FNOP*/ + FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* opFCHS opFABS*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), INVALID, INVALID, +/* opFTST opFXAM*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(21,4,0), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), FPU_CYCLES(2,0,0), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + FPU_CYCLES(53,2,2), FPU_CYCLES(103,2,2),FPU_CYCLES(120,36,0),FPU_CYCLES(112,2,2), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* opFPREM opFSQRT opFSINCOS*/ + FPU_CYCLES(64,2,2), INVALID, FPU_CYCLES(70,69,2),FPU_CYCLES(89,2,2), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + FPU_CYCLES(9,0,0), FPU_CYCLES(20,5,0), FPU_CYCLES(65,2,2), FPU_CYCLES(65,2,2) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(4,0,0), FPU_CYCLES(4,0,0), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(42,38,2), FPU_CYCLES(42,38,2) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, FPU_CYCLES(2,0,0), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + FPU_CYCLES(3,2,2), INVALID, FPU_CYCLES(6,0,0), FPU_CYCLES(6,0,0), +/* FLDe FSTPe*/ + INVALID, FPU_CYCLES(3,0,0), INVALID, FPU_CYCLES(3,0,0) +}; +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, FPU_CYCLES(2,0,0), FPU_CYCLES(7,0,0), FPU_CYCLES(17,0,0), +/* opFNOP opFNOP*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), 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*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2), FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2),INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2),FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + FPU_CYCLES(2,0,0), INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FRSTOR FSAVE FSTSW*/ + FPU_CYCLES(70,0,0), INVALID, FPU_CYCLES(127,0,0), FPU_CYCLES(6,0,0) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + FPU_CYCLES(2,0,0), INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FUCOM FUCOMP*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0),INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(4,0,0), FPU_CYCLES(4,0,0), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(42,38,2), FPU_CYCLES(42,38,2) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2), INVALID, FPU_CYCLES(2,0,0), +/* FSUBP FSUBRP FDIVP FDIVRP*/ + FPU_CYCLES(4,2,2), FPU_CYCLES(4,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + FPU_CYCLES(3,2,2), INVALID, FPU_CYCLES(6,0,0), FPU_CYCLES(6,0,0), +/* FILDiq FBSTP FISTPiq*/ + INVALID, FPU_CYCLES(3,2,2), FPU_CYCLES(148,0,0), FPU_CYCLES(6,0,0) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_8x_mod3[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_81[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_81_mod3[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; + +static int timing_count; +static uint8_t last_prefix; +static uint32_t regmask_modified; +static int decode_delay, decode_delay_offset; +static int fpu_latency; +static int fpu_st_latency[8]; + + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_FPU) + return FPU_I_LATENCY(c); + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return (c >> 8) & 0xff; + return c & 0xff; + } + return GET_CYCLES(c); +} + +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + /*Instructions that use ESP implicitly (eg PUSH, POP, CALL etc) do not + cause AGIs with each other, but do with instructions that use it explicitly*/ + if ((addr_regmask & REGMASK_IMPL_ESP) && (regmask_modified & (1 << REG_ESP)) && !(regmask_modified & REGMASK_IMPL_ESP)) + addr_regmask |= (1 << REG_ESP); + + return (regmask_modified & addr_regmask) & ~REGMASK_IMPL_ESP; +} + +static int codegen_fpu_latencies(uint64_t deps, int reg) +{ + int latency = fpu_latency; + + if ((deps & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency) + latency = fpu_st_latency[0]; + if ((deps & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency) + latency = fpu_st_latency[1]; + if ((deps & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency) + latency = fpu_st_latency[reg]; + + return latency; +} + +#define SUB_AND_CLAMP(latency, count) \ + latency -= count; \ + if (latency < 0) \ + latency = 0 + +static void codegen_fpu_latency_clock(int count) +{ + SUB_AND_CLAMP(fpu_latency, count); + SUB_AND_CLAMP(fpu_st_latency[0], count); + SUB_AND_CLAMP(fpu_st_latency[1], count); + SUB_AND_CLAMP(fpu_st_latency[2], count); + SUB_AND_CLAMP(fpu_st_latency[3], count); + SUB_AND_CLAMP(fpu_st_latency[4], count); + SUB_AND_CLAMP(fpu_st_latency[5], count); + SUB_AND_CLAMP(fpu_st_latency[6], count); + SUB_AND_CLAMP(fpu_st_latency[7], count); +} + +static void codegen_instruction(uint32_t *timings, uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int decode_delay_offset, int op_32, int exec_delay) +{ + int instr_cycles, latency = 0; + + if ((timings[opcode] & CYCLES_FPU) && !(deps[opcode] & FPU_FXCH)) + instr_cycles = latency = codegen_fpu_latencies(deps[opcode], fetchdat & 7); + else + instr_cycles = 0; + + if ((decode_delay + decode_delay_offset) > 0) + codegen_fpu_latency_clock(decode_delay + decode_delay_offset + instr_cycles); + else + codegen_fpu_latency_clock(instr_cycles); + instr_cycles += COUNT(timings[opcode], op_32); + instr_cycles += exec_delay; + if ((decode_delay + decode_delay_offset) > 0) + codegen_block_cycles += instr_cycles + decode_delay + decode_delay_offset; + else + codegen_block_cycles += instr_cycles; + decode_delay = (-instr_cycles) + 1; + + if (deps[opcode] & FPU_POP) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c] = fpu_st_latency[c+1]; + fpu_st_latency[7] = 0; + } + if (deps[opcode] & FPU_POP2) + { + int c; + + for (c = 0; c < 6; c++) + fpu_st_latency[c] = fpu_st_latency[c+2]; + fpu_st_latency[6] = fpu_st_latency[7] = 0; + } + if (timings[opcode] & CYCLES_FPU) + { + /* if (fpu_latency) + fatal("Bad latency FPU\n");*/ + fpu_latency = FPU_F_LATENCY(timings[opcode]); + } + + if (deps[opcode] & FPU_PUSH) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c+1] = fpu_st_latency[c]; + fpu_st_latency[0] = 0; + } + if (deps[opcode] & FPU_WRITE_ST0) + { +/* if (fpu_st_latency[0]) + fatal("Bad latency ST0\n");*/ + fpu_st_latency[0] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_ST1) + { +/* if (fpu_st_latency[1]) + fatal("Bad latency ST1\n");*/ + fpu_st_latency[1] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps[opcode] & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps[opcode] & FPU_WRITE_ST0)) && + !(reg == 1 && (deps[opcode] & FPU_WRITE_ST1))) + { +/* if (fpu_st_latency[reg]) + fatal("Bad latency STREG %i %08x %i %016llx %02x\n",fpu_st_latency[reg], fetchdat, reg, timings[opcode], opcode);*/ + fpu_st_latency[reg] = FPU_RESULT_LATENCY(timings[opcode]); + } + } +} + +static void codegen_timing_cyrixiii_block_start() +{ + regmask_modified = 0; + decode_delay = decode_delay_offset = 0; +} + +static void codegen_timing_cyrixiii_start() +{ + timing_count = 0; + last_prefix = 0; +} + +static void codegen_timing_cyrixiii_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if (prefix == 0x0f) + { + /*0fh prefix is 'free'*/ + last_prefix = prefix; + return; + } + /*On C3 all prefixes take 1 cycle to decode. Decode may be shadowed + by execution of previous instructions*/ + decode_delay_offset++; + last_prefix = prefix; +} + +static void codegen_timing_cyrixiii_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + uint32_t *timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + int agi_stall = 0; + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; +// pclog("timings 0f\n"); + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; +// pclog("timings df\n"); + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + 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; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; +// pclog("timings c0\n"); + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; +// pclog("timings normal\n"); + break; + } + } + + if (check_agi(deps, opcode, fetchdat, op_32)) + agi_stall = 1; + codegen_instruction(timings, deps, opcode, fetchdat, decode_delay_offset, op_32, agi_stall); + decode_delay_offset = 0; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); +} + +static void codegen_timing_cyrixiii_block_end() +{ +} + +int codegen_timing_cyrixiii_jump_cycles() +{ + return 0; +} + +codegen_timing_t codegen_timing_cyrixiii = +{ + codegen_timing_cyrixiii_start, + codegen_timing_cyrixiii_prefix, + codegen_timing_cyrixiii_opcode, + codegen_timing_cyrixiii_block_start, + codegen_timing_cyrixiii_block_end, + codegen_timing_cyrixiii_jump_cycles +}; diff --git a/src/codegen_timing_k6.c b/src/codegen_timing_k6.c new file mode 100644 index 0000000..5d5aa8e --- /dev/null +++ b/src/codegen_timing_k6.c @@ -0,0 +1,2365 @@ +/*Most of the vector instructions here are a total guess. + Some of the timings are based on http://users.atw.hu/instlatx64/AuthenticAMD0000562_K6_InstLatX86.txt*/ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.h" +#include "mem.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +typedef enum uop_type_t +{ + UOP_ALU = 0, /*Executes in Integer X or Y units*/ + UOP_ALUX, /*Executes in Integer X unit*/ + UOP_LOAD, /*Executes in Load unit*/ + UOP_STORE, /*Executes in Store unit*/ + UOP_FLOAD, /*Executes in Load unit*/ + UOP_FSTORE, /*Executes in Store unit*/ + UOP_MLOAD, /*Executes in Load unit*/ + UOP_MSTORE, /*Executes in Store unit*/ + UOP_FLOAT, /*Executes in Floating Point unit*/ + UOP_MEU, /*Executes in Multimedia unit*/ + UOP_MEU_SHIFT, /*Executes in Multimedia unit or ALU X/Y. Uses MMX shifter*/ + UOP_MEU_MUL, /*Executes in Multimedia unit or ALU X/Y. Uses MMX/3DNow multiplier*/ + UOP_MEU_3DN, /*Executes in Multimedia unit or ALU X/Y. Uses 3DNow ALU*/ + UOP_BRANCH, /*Executes in Branch unit*/ + UOP_LIMM /*Does not require an execution unit*/ +} uop_type_t; + +typedef enum decode_type_t +{ + DECODE_SHORT, + DECODE_LONG, + DECODE_VECTOR +} decode_type_t; + +#define MAX_UOPS 10 + +typedef struct risc86_uop_t +{ + uop_type_t type; + int throughput; + int latency; +} risc86_uop_t; + +typedef struct risc86_instruction_t +{ + int nr_uops; + decode_type_t decode_type; + risc86_uop_t uop[MAX_UOPS]; +} risc86_instruction_t; + +static const risc86_instruction_t alu_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t alux_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_alu_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_alux_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t alu_store_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t alux_store_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t branch_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t limm_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LIMM, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t load_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2} +}; + +static const risc86_instruction_t store_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; + + +static const risc86_instruction_t bswap_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t leave_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t lods_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t loop_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t mov_reg_seg_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, +}; +static const risc86_instruction_t movs_op = +{ + .nr_uops = 4, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t pop_reg_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t pop_mem_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t push_imm_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 2}, +}; +static const risc86_instruction_t push_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t push_seg_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t stos_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t test_reg_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t test_reg_b_op = +{ + .nr_uops = 1, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t test_mem_imm_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t test_mem_imm_b_op = +{ + .nr_uops = 2, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t xchg_op = +{ + .nr_uops = 3, + .decode_type = DECODE_LONG, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t m3dn_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU_3DN, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t mmx_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t mmx_mul_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU_MUL, .throughput = 1, .latency = 2} +}; +static const risc86_instruction_t mmx_shift_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU_SHIFT, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_3dn_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU_3DN, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_mmx_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t load_mmx_mul_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU_MUL, .throughput = 1, .latency = 2} +}; +static const risc86_instruction_t load_mmx_shift_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU_SHIFT, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t mload_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MLOAD, .throughput = 1, .latency = 2} +}; + +static const risc86_instruction_t mstore_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MSTORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t pmul_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_MEU_MUL, .throughput = 1, .latency = 2} +}; +static const risc86_instruction_t pmul_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_MEU_MUL, .throughput = 1, .latency = 2} +}; + +static const risc86_instruction_t float_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2} +}; +static const risc86_instruction_t load_float_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2} +}; +static const risc86_instruction_t fstore_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FSTORE, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t fdiv_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAT, .throughput = 40, .latency = 40} +}; +static const risc86_instruction_t fdiv_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 40, .latency = 40} +}; +static const risc86_instruction_t fsin_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAT, .throughput = 62, .latency = 62} +}; +static const risc86_instruction_t fsqrt_op = +{ + .nr_uops = 1, + .decode_type = DECODE_SHORT, + .uop[0] = {.type = UOP_FLOAT, .throughput = 41, .latency = 41} +}; + +static const risc86_instruction_t vector_fldcw_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAT, .throughput = 8, .latency = 8} +}; +static const risc86_instruction_t vector_float_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2} +}; +static const risc86_instruction_t vector_float_l_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAT, .throughput = 50, .latency = 50} +}; +static const risc86_instruction_t vector_flde_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2} +}; +static const risc86_instruction_t vector_fste_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_FLOAT, .throughput = 2, .latency = 2}, + .uop[1] = {.type = UOP_FSTORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_FSTORE, .throughput = 1, .latency = 1} +}; + +static const risc86_instruction_t vector_alu1_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alu2_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alu3_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alu6_op = +{ + .nr_uops = 6, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alux1_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alux3_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alux6_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alu_store_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_alux_store_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_arpl_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 3, .latency = 3}, + .uop[1] = {.type = UOP_ALU, .throughput = 3, .latency = 3} +}; +static const risc86_instruction_t vector_bound_op = +{ + .nr_uops = 4, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_bsx_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_call_far_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 3, .latency = 3}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_cli_sti_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 7, .latency = 7} +}; +static const risc86_instruction_t vector_cmps_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_cmpsb_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_cmpxchg_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, +}; +static const risc86_instruction_t vector_cmpxchg_b_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, +}; +static const risc86_instruction_t vector_cpuid_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 22, .latency = 22} +}; +static const risc86_instruction_t vector_div16_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_div16_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_div32_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 18, .latency = 18} +}; +static const risc86_instruction_t vector_div32_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 18, .latency = 18} +}; +static const risc86_instruction_t vector_emms_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 25, .latency = 25} +}; +static const risc86_instruction_t vector_enter_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_femms_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 6, .latency = 6} +}; +static const risc86_instruction_t vector_in_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 10, .latency = 11} +}; +static const risc86_instruction_t vector_ins_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 10, .latency = 11}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_int_op = +{ + .nr_uops = 5, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 20, .latency = 20}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_iret_op = +{ + .nr_uops = 5, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[3] = {.type = UOP_ALU, .throughput = 20, .latency = 20}, + .uop[4] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_invd_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1000, .latency = 1000} +}; +static const risc86_instruction_t vector_jmp_far_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 3, .latency = 3}, + .uop[1] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_load_alu_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_load_alux_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_loop_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_lss_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_ALU, .throughput = 3, .latency = 3} +}; +static const risc86_instruction_t vector_mov_mem_seg_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_mov_seg_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 3, .latency = 3} +}; +static const risc86_instruction_t vector_mov_seg_reg_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 3, .latency = 3} +}; +static const risc86_instruction_t vector_mul_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_mul_mem_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_mul64_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_mul64_mem_op = +{ + .nr_uops = 4, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_out_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_STORE, .throughput = 10, .latency = 10} +}; +static const risc86_instruction_t vector_outs_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STORE, .throughput = 10, .latency = 10}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_pusha_op = +{ + .nr_uops = 8, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_popa_op = +{ + .nr_uops = 8, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_LOAD, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_popf_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 17, .latency = 17} +}; +static const risc86_instruction_t vector_push_mem_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_pushf_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_ret_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_retf_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 3, .latency = 3}, + .uop[2] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_scas_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_scasb_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_setcc_mem_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_FSTORE, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_setcc_reg_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_test_mem_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_test_mem_b_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALUX, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_xchg_mem_op = +{ + .nr_uops = 3, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STORE, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU, .throughput = 1, .latency = 1} +}; +static const risc86_instruction_t vector_xlat_op = +{ + .nr_uops = 2, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2} +}; +static const risc86_instruction_t vector_wbinvd_op = +{ + .nr_uops = 1, + .decode_type = DECODE_VECTOR, + .uop[0] = {.type = UOP_ALU, .throughput = 10000, .latency = 10000} +}; + +#define INVALID NULL + +static const risc86_instruction_t *opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* ADD ADD PUSH ES POP ES*/ + &alux_op, &alu_op, &push_seg_op, &vector_mov_seg_mem_op, +/* OR OR OR OR*/ + &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* OR OR PUSH CS */ + &alux_op, &alu_op, &push_seg_op, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ &vector_alux_store_op, &vector_alu_store_op, &vector_load_alux_op, &vector_load_alu_op, +/* ADC ADC PUSH SS POP SS*/ + &vector_alux1_op, &vector_alu1_op, &push_seg_op, &vector_mov_seg_mem_op, +/* SBB SBB SBB SBB*/ +/*10*/ &vector_alux_store_op, &vector_alu_store_op, &vector_load_alux_op, &vector_load_alu_op, +/* SBB SBB PUSH DS POP DS*/ + &vector_alux1_op, &vector_alu1_op, &push_seg_op, &vector_mov_seg_mem_op, + +/* AND AND AND AND*/ +/*20*/ &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* AND AND DAA*/ + &alux_op, &alu_op, INVALID, &vector_alux1_op, +/* SUB SUB SUB SUB*/ + &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* SUB SUB DAS*/ + &alux_op, &alu_op, INVALID, &vector_alux1_op, + +/* XOR XOR XOR XOR*/ +/*30*/ &alux_store_op, &alu_store_op, &load_alux_op, &load_alu_op, +/* XOR XOR AAA*/ + &alux_op, &alu_op, INVALID, &vector_alux6_op, +/* CMP CMP CMP CMP*/ + &load_alux_op, &load_alu_op, &load_alux_op, &load_alu_op, +/* CMP CMP AAS*/ + &alux_op, &alu_op, INVALID, &vector_alux6_op, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* INC ESP INC EBP INC ESI INC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ &store_op, &store_op, &store_op, &store_op, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + &store_op, &store_op, &store_op, &store_op, +/* POP EAX POP ECX POP EDX POP EBX*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, +/* POP ESP POP EBP POP ESI POP EDI*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ &vector_pusha_op, &vector_popa_op, &vector_bound_op, &vector_arpl_op, + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + &push_imm_op, &vector_mul_op, &push_imm_op, &vector_mul_op, +/* INSB INSW OUTSB OUTSW*/ + &vector_ins_op, &vector_ins_op, &vector_outs_op, &vector_outs_op, + +/* Jxx*/ +/*70*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + &vector_test_mem_b_op, &vector_test_mem_op, &vector_xchg_mem_op, &vector_xchg_mem_op, +/* MOV MOV MOV MOV*/ + &store_op, &store_op, &load_op, &load_op, +/* MOV from seg LEA MOV to seg POP*/ + &vector_mov_mem_seg_op, &store_op, &vector_mov_seg_mem_op, &pop_mem_op, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ &limm_op, &xchg_op, &xchg_op, &xchg_op, +/* XCHG XCHG XCHG XCHG*/ + &xchg_op, &xchg_op, &xchg_op, &xchg_op, +/* CBW CWD CALL far WAIT*/ + &vector_alu1_op, &vector_alu1_op, &vector_call_far_op, &limm_op, +/* PUSHF POPF SAHF LAHF*/ + &vector_pushf_op, &vector_popf_op, &vector_alux1_op, &vector_alux1_op, + +/* MOV MOV MOV MOV*/ +/*a0*/ &load_op, &load_op, &store_op, &store_op, +/* MOVSB MOVSW CMPSB CMPSW*/ + &movs_op, &movs_op, &vector_cmpsb_op, &vector_cmps_op, +/* TEST TEST STOSB STOSW*/ + &test_reg_b_op, &test_reg_op, &stos_op, &stos_op, +/* LODSB LODSW SCASB SCASW*/ + &lods_op, &lods_op, &vector_scasb_op, &vector_scas_op, + +/* MOV*/ +/*b0*/ &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, &vector_ret_op, &vector_ret_op, +/* LES LDS MOV MOV*/ + &vector_lss_op, &vector_lss_op, &store_op, &store_op, +/* ENTER LEAVE RETF RETF*/ + &vector_enter_op, &leave_op, &vector_retf_op, &vector_retf_op, +/* INT3 INT INTO IRET*/ + &vector_int_op, &vector_int_op, &vector_int_op, &vector_iret_op, + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + &vector_alux6_op, &vector_alux3_op, &vector_alux1_op, &vector_xlat_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ &vector_loop_op, &vector_loop_op, &loop_op, &vector_loop_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &vector_in_op, &vector_in_op, &vector_out_op, &vector_out_op, +/* CALL JMP JMP JMP*/ + &store_op, &branch_op, &vector_jmp_far_op, &branch_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &vector_in_op, &vector_in_op, &vector_out_op, &vector_out_op, + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, INVALID, INVALID, +/* HLT CMC*/ + &vector_alux1_op, &vector_alu2_op, INVALID, INVALID, +/* CLC STC CLI STI*/ + &vector_alu1_op, &vector_alu1_op, &vector_cli_sti_op, &vector_cli_sti_op, +/* CLD STD INCDEC*/ + &vector_alu1_op, &vector_alu1_op, &alux_store_op, INVALID +}; + +static const risc86_instruction_t *opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ &alux_op, &alu_op, &alux_op, &alu_op, +/* ADD ADD PUSH ES POP ES*/ + &alux_op, &alu_op, &push_seg_op, &vector_mov_seg_mem_op, +/* OR OR OR OR*/ + &alux_op, &alu_op, &alux_op, &alu_op, +/* OR OR PUSH CS */ + &alux_op, &alu_op, &push_seg_op, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ &vector_alux1_op, &vector_alu1_op, &vector_alux1_op, &vector_alu1_op, +/* ADC ADC PUSH SS POP SS*/ + &vector_alux1_op, &vector_alu1_op, &push_seg_op, &vector_mov_seg_mem_op, +/* SBB SBB SBB SBB*/ + &vector_alux1_op, &vector_alu1_op, &vector_alux1_op, &vector_alu1_op, +/* SBB SBB PUSH DS POP DS*/ + &vector_alux1_op, &vector_alu1_op, &push_seg_op, &vector_mov_seg_mem_op, + +/* AND AND AND AND*/ +/*20*/ &alux_op, &alu_op, &alux_op, &alu_op, +/* AND AND DAA*/ + &alux_op, &alu_op, INVALID, &vector_alux1_op, +/* SUB SUB SUB SUB*/ + &alux_op, &alu_op, &alux_op, &alu_op, +/* SUB SUB DAS*/ + &alux_op, &alu_op, INVALID, &vector_alux1_op, + +/* XOR XOR XOR XOR*/ +/*30*/ &alux_op, &alu_op, &alux_op, &alu_op, +/* XOR XOR AAA*/ + &alux_op, &alu_op, INVALID, &vector_alux6_op, +/* CMP CMP CMP CMP*/ + &alux_op, &alu_op, &alux_op, &alu_op, +/* CMP CMP AAS*/ + &alux_op, &alu_op, INVALID, &vector_alux6_op, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* INC ESP INC EBP INC ESI INC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ &store_op, &store_op, &store_op, &store_op, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + &store_op, &store_op, &store_op, &store_op, +/* POP EAX POP ECX POP EDX POP EBX*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, +/* POP ESP POP EBP POP ESI POP EDI*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ &vector_pusha_op, &vector_popa_op, &vector_bound_op, &vector_arpl_op, + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + &push_imm_op, &vector_mul_op, &push_imm_op, &vector_mul_op, +/* INSB INSW OUTSB OUTSW*/ + &vector_ins_op, &vector_ins_op, &vector_outs_op, &vector_outs_op, + +/* Jxx*/ +/*70*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + &vector_alu1_op, &vector_alu1_op, &vector_alu3_op, &vector_alu3_op, +/* MOV MOV MOV MOV*/ + &store_op, &store_op, &load_op, &load_op, +/* MOV from seg LEA MOV to seg POP*/ + &mov_reg_seg_op, &store_op, &vector_mov_seg_reg_op, &pop_reg_op, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ &limm_op, &xchg_op, &xchg_op, &xchg_op, +/* XCHG XCHG XCHG XCHG*/ + &xchg_op, &xchg_op, &xchg_op, &xchg_op, +/* CBW CWD CALL far WAIT*/ + &vector_alu1_op, &vector_alu1_op, &vector_call_far_op, &limm_op, +/* PUSHF POPF SAHF LAHF*/ + &vector_pushf_op, &vector_popf_op, &vector_alux1_op, &vector_alux1_op, + +/* MOV MOV MOV MOV*/ +/*a0*/ &load_op, &load_op, &store_op, &store_op, +/* MOVSB MOVSW CMPSB CMPSW*/ + &movs_op, &movs_op, &vector_cmpsb_op, &vector_cmps_op, +/* TEST TEST STOSB STOSW*/ + &test_reg_b_op, &test_reg_op, &stos_op, &stos_op, +/* LODSB LODSW SCASB SCASW*/ + &lods_op, &lods_op, &vector_scasb_op, &vector_scas_op, + +/* MOV*/ +/*b0*/ &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + &limm_op, &limm_op, &limm_op, &limm_op, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, &vector_ret_op, &vector_ret_op, +/* LES LDS MOV MOV*/ + &vector_lss_op, &vector_lss_op, &store_op, &store_op, +/* ENTER LEAVE RETF RETF*/ + &vector_enter_op, &leave_op, &vector_retf_op, &vector_retf_op, +/* INT3 INT INTO IRET*/ + &vector_int_op, &vector_int_op, &vector_int_op, &vector_iret_op, + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + &vector_alux6_op, &vector_alux3_op, &vector_alux1_op, &vector_xlat_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ &vector_loop_op, &vector_loop_op, &loop_op, &vector_loop_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &vector_in_op, &vector_in_op, &vector_out_op, &vector_out_op, +/* CALL JMP JMP JMP*/ + &store_op, &branch_op, &vector_jmp_far_op, &branch_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &vector_in_op, &vector_in_op, &vector_out_op, &vector_out_op, + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, INVALID, INVALID, +/* HLT CMC*/ + &vector_alux1_op, &vector_alu2_op, INVALID, INVALID, +/* CLC STC CLI STI*/ + &vector_alu1_op, &vector_alu1_op, &vector_cli_sti_op, &vector_cli_sti_op, +/* CLD STD INCDEC*/ + &vector_alu1_op, &vector_alu1_op, &vector_alux1_op, INVALID +}; + +static const risc86_instruction_t *opcode_timings_0f[256] = +{ +/*00*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, + INVALID, &vector_alu6_op, &vector_alu6_op, INVALID, + &vector_invd_op, &vector_wbinvd_op, INVALID, INVALID, + INVALID, &load_op, &vector_femms_op, &load_3dn_op, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, + &vector_alu6_op, &vector_alu6_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, 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*/ &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + INVALID, INVALID, &mload_op, &mload_op, + +/*70*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &vector_emms_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, &mstore_op, &mstore_op, + +/*80*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*90*/ &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, + &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, + &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, + &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, &vector_setcc_reg_op, + +/*a0*/ &push_seg_op, &vector_mov_seg_mem_op, &vector_cpuid_op, &vector_load_alu_op, + &vector_alu_store_op, &vector_alu_store_op, INVALID, INVALID, + &push_seg_op, &vector_mov_seg_mem_op, INVALID, &vector_load_alu_op, + &vector_alu_store_op, &vector_alu_store_op, INVALID, &vector_mul_op, + +/*b0*/ &vector_cmpxchg_b_op, &vector_cmpxchg_op, &vector_lss_op, &vector_load_alu_op, + &vector_lss_op, &vector_lss_op, &load_alux_op, &load_alu_op, + INVALID, INVALID, &vector_load_alu_op, &vector_load_alu_op, + &vector_bsx_op, &vector_bsx_op, &load_alux_op, &load_alu_op, + +/*c0*/ &vector_alux_store_op, &vector_alu_store_op, INVALID, INVALID, + INVALID, INVALID, INVALID, &vector_cmpxchg_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + +/*d0*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + INVALID, &load_mmx_mul_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + +/*e0*/ &load_mmx_op, &load_mmx_shift_op, &load_mmx_shift_op, INVALID, + INVALID, &pmul_mem_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + +/*f0*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + INVALID, &pmul_mem_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, &load_mmx_op, INVALID, + &load_mmx_op, &load_mmx_op, &load_mmx_op, INVALID, +}; +static const risc86_instruction_t *opcode_timings_0f_mod3[256] = +{ +/*00*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, + INVALID, &vector_alu6_op, &vector_alu6_op, INVALID, + &vector_invd_op, &vector_wbinvd_op, INVALID, INVALID, + INVALID, INVALID, &vector_femms_op, &m3dn_op, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, + &vector_alu6_op, &vector_alu6_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ &vector_alu6_op, &vector_alu6_op, &vector_alu6_op, 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*/ &mmx_op, &mmx_op, &mmx_op, &mmx_op, + &mmx_op, &mmx_op, &mmx_op, &mmx_op, + &mmx_op, &mmx_op, &mmx_op, &mmx_op, + INVALID, INVALID, &mmx_op, &mmx_op, + +/*70*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + &mmx_op, &mmx_op, &mmx_op, &vector_emms_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, &mmx_op, &mmx_op, + +/*80*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*90*/ &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, + &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, + &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, + &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, &vector_setcc_mem_op, + +/*a0*/ &push_seg_op, &vector_mov_seg_mem_op, &vector_cpuid_op, &vector_alu1_op, + &vector_alu1_op, &vector_alu1_op, INVALID, INVALID, + &push_seg_op, &vector_mov_seg_mem_op, INVALID, &vector_alu1_op, + &vector_alu1_op, &vector_alu1_op, INVALID, &vector_mul_op, + +/*b0*/ &vector_cmpxchg_b_op, &vector_cmpxchg_op, &vector_lss_op, &vector_alu1_op, + &vector_lss_op, &vector_lss_op, &alux_op, &alu_op, + INVALID, INVALID, &vector_alu1_op, &vector_alu1_op, + &vector_bsx_op, &vector_bsx_op, &alux_op, &alu_op, + +/*c0*/ &vector_alux1_op, &vector_alu1_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + +/*d0*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + INVALID, &mmx_mul_op, INVALID, INVALID, + &mmx_op, &mmx_op, INVALID, &mmx_op, + &mmx_op, &mmx_op, INVALID, &mmx_op, + +/*e0*/ &mmx_op, &mmx_shift_op, &mmx_shift_op, INVALID, + INVALID, &pmul_op, INVALID, INVALID, + &mmx_op, &mmx_op, INVALID, &mmx_op, + &mmx_op, &mmx_op, INVALID, &mmx_op, + +/*f0*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + INVALID, &pmul_op, INVALID, INVALID, + &mmx_op, &mmx_op, &mmx_op, INVALID, + &mmx_op, &mmx_op, &mmx_op, INVALID, +}; + +static const risc86_instruction_t *opcode_timings_0f0f[256] = +{ +/*00*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, &load_3dn_op, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, &load_3dn_op, INVALID, INVALID, + +/*20*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ INVALID, INVALID, INVALID, 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*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*70*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*80*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*90*/ &load_3dn_op, INVALID, INVALID, INVALID, + &load_3dn_op, INVALID, &load_3dn_op, &load_3dn_op, + INVALID, INVALID, &load_3dn_op, INVALID, + INVALID, INVALID, &load_3dn_op, INVALID, + +/*a0*/ &load_3dn_op, INVALID, INVALID, INVALID, + &load_3dn_op, INVALID, &load_mmx_mul_op, &load_mmx_mul_op, + INVALID, INVALID, &load_3dn_op, INVALID, + INVALID, INVALID, &load_3dn_op, INVALID, + +/*b0*/ &load_3dn_op, INVALID, INVALID, INVALID, + &load_mmx_mul_op, INVALID, &load_mmx_mul_op, &load_mmx_mul_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, &load_mmx_op, + +/*c0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*d0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*e0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*f0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +}; +static const risc86_instruction_t *opcode_timings_0f0f_mod3[256] = +{ +/*00*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, &m3dn_op, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, &m3dn_op, INVALID, INVALID, + +/*20*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ INVALID, INVALID, INVALID, 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*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*70*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*80*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*90*/ &m3dn_op, INVALID, INVALID, INVALID, + &m3dn_op, INVALID, &m3dn_op, &m3dn_op, + INVALID, INVALID, &m3dn_op, INVALID, + INVALID, INVALID, &m3dn_op, INVALID, + +/*a0*/ &m3dn_op, INVALID, INVALID, INVALID, + &m3dn_op, INVALID, &mmx_mul_op, &mmx_mul_op, + INVALID, INVALID, &m3dn_op, INVALID, + INVALID, INVALID, &m3dn_op, INVALID, + +/*b0*/ &m3dn_op, INVALID, INVALID, INVALID, + &mmx_mul_op, INVALID, &mmx_mul_op, &mmx_mul_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, &mmx_op, + +/*c0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*d0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*e0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*f0*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +}; + +static const risc86_instruction_t *opcode_timings_shift[8] = +{ + &vector_alu_store_op, &vector_alu_store_op, &vector_alu_store_op, &vector_alu_store_op, + &vector_alu_store_op, &vector_alu_store_op, &vector_alu_store_op, &vector_alu_store_op +}; +static const risc86_instruction_t *opcode_timings_shift_b[8] = +{ + &vector_alux_store_op, &vector_alux_store_op, &vector_alux_store_op, &vector_alux_store_op, + &vector_alux_store_op, &vector_alux_store_op, &vector_alux_store_op, &vector_alux_store_op +}; +static const risc86_instruction_t *opcode_timings_shift_mod3[8] = +{ + &vector_alu1_op, &vector_alu1_op, &vector_alu1_op, &vector_alu1_op, + &alu_op, &alu_op, &alu_op, &alu_op +}; +static const risc86_instruction_t *opcode_timings_shift_b_mod3[8] = +{ + &vector_alux1_op, &vector_alux1_op, &vector_alux1_op, &vector_alux1_op, + &alux_op, &alux_op, &alux_op, &alux_op +}; + +static const risc86_instruction_t *opcode_timings_80[8] = +{ + &alux_store_op, &alux_store_op, &vector_alux_store_op, &vector_alux_store_op, + &alux_store_op, &alux_store_op, &alux_store_op, &alux_store_op, +}; +static const risc86_instruction_t *opcode_timings_80_mod3[8] = +{ + &alux_op, &alux_op, &alux_store_op, &alux_store_op, + &alux_op, &alux_op, &alux_op, &alux_op, +}; +static const risc86_instruction_t *opcode_timings_8x[8] = +{ + &alu_store_op, &alu_store_op, &vector_alu_store_op, &vector_alu_store_op, + &alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op, +}; +static const risc86_instruction_t *opcode_timings_8x_mod3[8] = +{ + &alu_op, &alu_op, &alu_store_op, &alu_store_op, + &alu_op, &alu_op, &alu_op, &alu_op, +}; + +static const risc86_instruction_t *opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + &test_mem_imm_b_op, INVALID, &vector_alux_store_op, &vector_alux_store_op, +/* MUL IMUL DIV IDIV*/ + &vector_mul_mem_op, &vector_mul_mem_op, &vector_div16_mem_op, &vector_div16_mem_op, +}; +static const risc86_instruction_t *opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + &test_reg_b_op, INVALID, &alux_op, &alux_op, +/* MUL IMUL DIV IDIV*/ + &vector_mul_op, &vector_mul_op, &vector_div16_op, &vector_div16_op, +}; +static const risc86_instruction_t *opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + &test_mem_imm_op, INVALID, &vector_alu_store_op, &vector_alu_store_op, +/* MUL IMUL DIV IDIV*/ + &vector_mul64_mem_op, &vector_mul64_mem_op, &vector_div32_mem_op, &vector_div32_mem_op, +}; +static const risc86_instruction_t *opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + &test_reg_op, INVALID, &alu_op, &alu_op, +/* MUL IMUL DIV IDIV*/ + &vector_mul64_op, &vector_mul64_op, &vector_div32_op, &vector_div32_op, +}; +static const risc86_instruction_t *opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + &alu_store_op, &alu_store_op, &store_op, &vector_call_far_op, +/* JMP JMP far PUSH*/ + &branch_op, &vector_jmp_far_op, &push_mem_op, INVALID +}; +static const risc86_instruction_t *opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + &vector_alu1_op, &vector_alu1_op, &store_op, &vector_call_far_op, +/* JMP JMP far PUSH*/ + &branch_op, &vector_jmp_far_op, &vector_push_mem_op, INVALID +}; + +static const risc86_instruction_t *opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + &load_float_op, &load_float_op, &load_float_op, &load_float_op, +/* FSUBs FSUBRs FDIVs FDIVRs*/ + &load_float_op, &load_float_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const risc86_instruction_t *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + &float_op, &float_op, &float_op, &float_op, +/* FSUB FSUBR FDIV FDIVR*/ + &float_op, &float_op, &fdiv_op, &fdiv_op, +}; + +static const risc86_instruction_t *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + &load_float_op, INVALID, &fstore_op, &fstore_op, +/* FLDENV FLDCW FSTENV FSTCW*/ + &vector_float_l_op, &vector_fldcw_op, &vector_float_l_op, &vector_float_op +}; +static const risc86_instruction_t *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + &float_op, &float_op, &float_op, &float_op, + &float_op, &float_op, &float_op, &float_op, + /*FXCH*/ + &float_op, &float_op, &float_op, &float_op, + &float_op, &float_op, &float_op, &float_op, + /*FNOP*/ + &float_op, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + &float_op, &float_op, &float_op, &float_op, + &float_op, &float_op, &float_op, &float_op, +/* opFCHS opFABS*/ + &float_op, &float_op, INVALID, INVALID, +/* opFTST opFXAM*/ + &float_op, &float_op, INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + &float_op, &float_op, &float_op, &float_op, +/* opFLDEG2 opFLDLN2 opFLDZ*/ + &float_op, &float_op, &float_op, INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + &fsin_op, &fsin_op, &fsin_op, &fsin_op, +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, &float_op, &float_op, +/* opFPREM opFSQRT opFSINCOS*/ + &fdiv_op, INVALID, &fsqrt_op, &fsin_op, +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + &float_op, &fdiv_op, &fsin_op, &fsin_op +}; + +static const risc86_instruction_t *opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + &load_float_op, &load_float_op, &load_float_op, &load_float_op, +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + &load_float_op, &load_float_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const risc86_instruction_t *opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, &float_op, INVALID, INVALID +}; + +static const risc86_instruction_t *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + &load_float_op, INVALID, &fstore_op, &fstore_op, +/* FLDe FSTPe*/ + INVALID, &vector_flde_op, INVALID, &vector_fste_op +}; +static const risc86_instruction_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, &float_op, &float_op, &float_op, +/* opFNOP opFNOP*/ + &float_op, &float_op, 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 const risc86_instruction_t *opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + &load_float_op, &load_float_op, &load_float_op, &load_float_op, +/* FSUBd FSUBRd FDIVd FDIVRd*/ + &load_float_op, &load_float_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const risc86_instruction_t *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + &float_op, &float_op, INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + &float_op, &float_op, &fdiv_op, &fdiv_op +}; + +static const risc86_instruction_t *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + &load_float_op, INVALID, &fstore_op, &fstore_op, +/* FRSTOR FSAVE FSTSW*/ + &vector_float_l_op, INVALID, &vector_float_l_op, &vector_float_l_op +}; +static const risc86_instruction_t *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + &float_op, INVALID, &float_op, &float_op, +/* FUCOM FUCOMP*/ + &float_op, &float_op, INVALID, INVALID +}; + +static const risc86_instruction_t *opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + &load_float_op, &load_float_op, &load_float_op, &load_float_op, +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + &load_float_op, &load_float_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const risc86_instruction_t *opcode_timings_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + &float_op, &float_op, INVALID, &float_op, +/* FSUBP FSUBRP FDIVP FDIVRP*/ + &float_op, &float_op, &fdiv_op, &fdiv_op, +}; + +static const risc86_instruction_t *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + &load_float_op, INVALID, &fstore_op, &fstore_op, +/* FILDiq FBSTP FISTPiq*/ + INVALID, &load_float_op, &vector_float_l_op, &fstore_op, +}; +static const risc86_instruction_t *opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + &float_op, INVALID, INVALID, INVALID +}; + + +static uint8_t last_prefix; +static int prefixes; + +static int decode_timestamp; +static int last_complete_timestamp; + +typedef struct k6_unit_t +{ + uint32_t uop_mask; + int first_available_cycle; +} k6_unit_t; + +static int nr_units; +static k6_unit_t *units; + +/*K6 has dedicated MMX unit*/ +static k6_unit_t k6_units[] = +{ + {.uop_mask = (1 << UOP_ALU) | (1 << UOP_ALUX)}, /*Integer X*/ + {.uop_mask = (1 << UOP_ALU)}, /*Integer Y*/ + {.uop_mask = (1 << UOP_MEU) | (1 << UOP_MEU_SHIFT) | (1 << UOP_MEU_MUL)}, /*Multimedia*/ + {.uop_mask = (1 << UOP_FLOAT)}, /*Floating point*/ + {.uop_mask = (1 << UOP_LOAD) | (1 << UOP_FLOAD) | (1 << UOP_MLOAD)}, /*Load*/ + {.uop_mask = (1 << UOP_STORE) | (1 << UOP_FSTORE) | (1 << UOP_MSTORE)}, /*Store*/ + {.uop_mask = (1 << UOP_BRANCH)} /*Branch*/ +}; +#define NR_K6_UNITS (sizeof(k6_units) / sizeof(k6_unit_t)) + +/*K6-2 and later integrate MMX into ALU X & Y, sharing multiplier, shifter and + 3DNow ALU between two execution units*/ +static k6_unit_t k6_2_units[] = +{ + {.uop_mask = (1 << UOP_ALU) | (1 << UOP_ALUX) | (1 << UOP_MEU) | /*Integer X*/ + (1 << UOP_MEU_SHIFT) | (1 << UOP_MEU_MUL) | (1 << UOP_MEU_3DN)}, + {.uop_mask = (1 << UOP_ALU) | (1 << UOP_MEU) | /*Integer Y*/ + (1 << UOP_MEU_SHIFT) | (1 << UOP_MEU_MUL) | (1 << UOP_MEU_3DN)}, + {.uop_mask = (1 << UOP_FLOAT)}, /*Floating point*/ + {.uop_mask = (1 << UOP_LOAD) | (1 << UOP_FLOAD) | (1 << UOP_MLOAD)}, /*Load*/ + {.uop_mask = (1 << UOP_STORE) | (1 << UOP_FSTORE) | (1 << UOP_MSTORE)}, /*Store*/ + {.uop_mask = (1 << UOP_BRANCH)} /*Branch*/ +}; +#define NR_K6_2_UNITS (sizeof(k6_2_units) / sizeof(k6_unit_t)) + +/*First available cycles of shared execution units. Each of these can be submitted + to by ALU X and Y*/ +static int mul_first_available_cycle; +static int shift_first_available_cycle; +static int m3dnow_first_available_cycle; + +static int uop_run(const risc86_uop_t *uop, int decode_time) +{ + int c; + k6_unit_t *best_unit = NULL; + int best_start_cycle = 99999; + + /*UOP_LIMM does not require execution*/ + if (uop->type == UOP_LIMM) + return decode_time; + + /*Handle shared units on K6-2 and later*/ + if (units == k6_2_units) + { + if (uop->type == UOP_MEU_MUL && decode_time < mul_first_available_cycle) + decode_time = mul_first_available_cycle; + else if (uop->type == UOP_MEU_SHIFT && decode_time < mul_first_available_cycle) + decode_time = shift_first_available_cycle; + else if (uop->type == UOP_MEU_3DN && decode_time < mul_first_available_cycle) + decode_time = m3dnow_first_available_cycle; + } + + /*Find execution unit for this uOP*/ + for (c = 0; c < nr_units; c++) + { + if (units[c].uop_mask & (1 << uop->type)) + { + if (units[c].first_available_cycle < best_start_cycle) + { + best_unit = &units[c]; + best_start_cycle = units[c].first_available_cycle; + } + } + } + if (!best_unit) + fatal("uop_run: can not find execution unit\n"); + + if (best_start_cycle < decode_time) + best_start_cycle = decode_time; + best_unit->first_available_cycle = best_start_cycle + uop->throughput; + + if (units == k6_2_units) + { + if (uop->type == UOP_MEU_MUL) + mul_first_available_cycle = best_start_cycle + uop->throughput; + else if (uop->type == UOP_MEU_SHIFT) + shift_first_available_cycle = best_start_cycle + uop->throughput; + else if (uop->type == UOP_MEU_3DN) + m3dnow_first_available_cycle = best_start_cycle + uop->throughput; + } + + return best_start_cycle + uop->throughput; +} + +/*The K6 decoder can decode, per clock : + - 1 or 2 'short' instructions, each up to 2 uOPs and 7 bytes long + - 1 'long' instruction, up to 4 uOPs + - 1 'vector' instruction, up to 4 uOPs per cycle, plus (I think) 1 cycle startup delay) +*/ +static struct +{ + int nr_uops; + const risc86_uop_t *uops[4]; + /*Earliest time a uop can start. If the timestamp is -1, then the uop is + part of a dependency chain and the start time is the completion time of + the previous uop*/ + int earliest_start[4]; +} decode_buffer; + +#define NR_OPQUADS 6 +/*Timestamps of when the last six opquads completed. The K6 scheduler retires + opquads in order, so this is needed to determine when the next can be scheduled*/ +static int opquad_completion_timestamp[NR_OPQUADS]; +static int next_opquad = 0; + +#define NR_REGS 8 +/*Timestamp of when last operation on an integer register completed*/ +static int reg_available_timestamp[NR_REGS]; +/*Timestamp of when last operation on an FPU register completed*/ +static int fpu_st_timestamp[8]; +/*Completion time of the last uop to be processed. Used to calculate timing of + dependent uop chains*/ +static int last_uop_timestamp = 0; + +void decode_flush() +{ + int c; + int uop_timestamp = 0; + + /*Decoded opquad can not be submitted if there are no free spaces in the + opquad buffer*/ + if (decode_timestamp < opquad_completion_timestamp[next_opquad]) + decode_timestamp = opquad_completion_timestamp[next_opquad]; + + /*Ensure that uops can not be submitted before they have been decoded*/ + if (decode_timestamp > last_uop_timestamp) + last_uop_timestamp = decode_timestamp; + + /*Submit uops to execution units, and determine the latest completion time*/ + for (c = 0; c < decode_buffer.nr_uops; c++) + { + int start_timestamp; + + if (decode_buffer.earliest_start[c] == -1) + start_timestamp = last_uop_timestamp; + else + start_timestamp = decode_buffer.earliest_start[c]; + + last_uop_timestamp = uop_run(decode_buffer.uops[c], start_timestamp); + if (last_uop_timestamp > uop_timestamp) + uop_timestamp = last_uop_timestamp; + } + + /*Calculate opquad completion time. Since opquads complete in order, it + must be after the last completion.*/ + if (uop_timestamp <= last_complete_timestamp) + last_complete_timestamp = last_complete_timestamp + 1; + else + last_complete_timestamp = uop_timestamp; + + /*Advance to next opquad in buffer*/ + opquad_completion_timestamp[next_opquad] = last_complete_timestamp; + next_opquad++; + if (next_opquad == NR_OPQUADS) + next_opquad = 0; + + decode_timestamp++; + decode_buffer.nr_uops = 0; +} + +/*The instruction is only of interest here if it's longer than 7 bytes, as that's the + limit on K6 short decoding*/ +static int codegen_timing_instr_length(uint64_t deps, uint32_t fetchdat, int op_32) +{ + int len = prefixes + 1; /*Opcode*/ + if (deps & MODRM) + { + len++; /*ModR/M*/ + if (deps & HAS_IMM8) + len++; + if (deps & HAS_IMM1632) + len += (op_32 & 0x100) ? 4 : 2; + + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /* Has SIB*/ + len++; + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0x700) == 0x500) + len += 4; + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0xc7) == 0x05) + len += 4; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 2; + else if ((fetchdat & 0xc7) == 0x06) + len += 2; + } + } + + return len; +} + +static void decode_instruction(const risc86_instruction_t *ins, uint64_t deps, uint32_t fetchdat, int op_32, int bit8) +{ + uint32_t regmask_required; + uint32_t regmask_modified; + int c, d; + int earliest_start = 0; + decode_type_t decode_type = ins->decode_type; + int instr_length = codegen_timing_instr_length(deps, fetchdat, op_32); + + /*Generate input register mask, and determine the earliest time this + instruction can start. This is not accurate, as this is calculated per + x86 instruction when it should be handled per uop*/ + regmask_required = get_dstdep_mask(deps, fetchdat, bit8); + regmask_required |= get_addr_regmask(deps, fetchdat, op_32); + for (c = 0; c < 8; c++) + { + if (regmask_required & (1 << c)) + { + if (reg_available_timestamp[c] > decode_timestamp) + earliest_start = reg_available_timestamp[c]; + } + } + if ((deps & FPU_RW_ST0) && fpu_st_timestamp[0] > decode_timestamp) + earliest_start = fpu_st_timestamp[0]; + if ((deps & FPU_RW_ST1) && fpu_st_timestamp[1] > decode_timestamp) + earliest_start = fpu_st_timestamp[1]; + if ((deps & FPU_RW_STREG)) + { + int reg = fetchdat & 7; + + if (fpu_st_timestamp[reg] > decode_timestamp) + earliest_start = fpu_st_timestamp[reg]; + } + + /*Short decoders are limited to 7 bytes*/ + if (decode_type == DECODE_SHORT && instr_length > 7) + decode_type = DECODE_LONG; + /*Long decoder is limited to 11 bytes*/ + else if (instr_length > 11) + decode_type = DECODE_VECTOR; + + switch (decode_type) + { + case DECODE_SHORT: + if (decode_buffer.nr_uops) + { + decode_buffer.uops[decode_buffer.nr_uops] = &ins->uop[0]; + decode_buffer.earliest_start[decode_buffer.nr_uops] = earliest_start; + if (ins->nr_uops > 1) + { + decode_buffer.uops[decode_buffer.nr_uops+1] = &ins->uop[1]; + decode_buffer.earliest_start[decode_buffer.nr_uops+1] = -1; + } + decode_buffer.nr_uops += ins->nr_uops; + + decode_flush(); + } + else + { + decode_buffer.nr_uops = ins->nr_uops; + decode_buffer.uops[0] = &ins->uop[0]; + decode_buffer.earliest_start[0] = earliest_start; + if (ins->nr_uops > 1) + { + decode_buffer.uops[1] = &ins->uop[1]; + decode_buffer.earliest_start[1] = -1; + } + } + break; + + case DECODE_LONG: + if (decode_buffer.nr_uops) + decode_flush(); + + decode_buffer.nr_uops = ins->nr_uops; + for (c = 0; c < ins->nr_uops; c++) + { + decode_buffer.uops[c] = &ins->uop[c]; + if (c == 0) + decode_buffer.earliest_start[c] = earliest_start; + else + decode_buffer.earliest_start[c] = -1; + } + decode_flush(); + break; + + case DECODE_VECTOR: + if (decode_buffer.nr_uops) + decode_flush(); + + decode_timestamp++; + d = 0; + + for (c = 0; c < ins->nr_uops; c++) + { + decode_buffer.uops[d] = &ins->uop[c]; + if (c == 0) + decode_buffer.earliest_start[d] = earliest_start; + else + decode_buffer.earliest_start[d] = -1; + d++; + + if (d == 4) + { + d = 0; + decode_buffer.nr_uops = 4; + decode_flush(); + } + } + if (d) + { + decode_buffer.nr_uops = d; + decode_flush(); + } + break; + } + + /*Update write timestamps for any output registers*/ + regmask_modified = get_dstdep_mask(deps, fetchdat, bit8); + for (c = 0; c < 8; c++) + { + if (regmask_modified & (1 << c)) + reg_available_timestamp[c] = last_complete_timestamp; + } + if (deps & FPU_POP) + { + for (c = 0; c < 7; c++) + fpu_st_timestamp[c] = fpu_st_timestamp[c+1]; + fpu_st_timestamp[7] = 0; + } + if (deps & FPU_POP2) + { + for (c = 0; c < 6; c++) + fpu_st_timestamp[c] = fpu_st_timestamp[c+2]; + fpu_st_timestamp[6] = fpu_st_timestamp[7] = 0; + } + if (deps & FPU_PUSH) + { + for (c = 0; c < 7; c++) + fpu_st_timestamp[c+1] = fpu_st_timestamp[c]; + fpu_st_timestamp[0] = 0; + } + if (deps & FPU_WRITE_ST0) + fpu_st_timestamp[0] = last_complete_timestamp; + if (deps & FPU_WRITE_ST1) + fpu_st_timestamp[1] = last_complete_timestamp; + if (deps & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps & FPU_WRITE_ST0)) && + !(reg == 1 && (deps & FPU_WRITE_ST1))) + fpu_st_timestamp[reg] = last_complete_timestamp; + } +} + +void codegen_timing_k6_block_start() +{ + int c; + + for (c = 0; c < nr_units; c++) + units[c].first_available_cycle = 0; + + mul_first_available_cycle = 0; + shift_first_available_cycle = 0; + m3dnow_first_available_cycle = 0; + + decode_timestamp = 0; + last_complete_timestamp = 0; + + for (c = 0; c < NR_OPQUADS; c++) + opquad_completion_timestamp[c] = 0; + next_opquad = 0; + + for (c = 0; c < NR_REGS; c++) + reg_available_timestamp[c] = 0; + for (c = 0; c < 8; c++) + fpu_st_timestamp[c] = 0; +} + +void codegen_timing_k6_start() +{ + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_K6) + { + units = k6_units; + nr_units = NR_K6_UNITS; + } + else + { + units = k6_2_units; + nr_units = NR_K6_2_UNITS; + } + last_prefix = 0; + prefixes = 0; +} + +void codegen_timing_k6_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if (prefix != 0x0f) + decode_timestamp++; + + last_prefix = prefix; + prefixes++; +} + +void codegen_timing_k6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + const risc86_instruction_t **ins_table; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int old_last_complete_timestamp = last_complete_timestamp; + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + if (opcode == 0x0f) + { + /*3DNow has the actual opcode after ModR/M, SIB and any offset*/ + uint32_t opcode_pc = op_pc + 1; /*Byte after ModR/M*/ + uint8_t modrm = fetchdat & 0xff; + uint8_t sib = (fetchdat >> 8) & 0xff; + + if ((modrm & 0xc0) != 0xc0) + { + if (op_32 & 0x200) + { + if ((modrm & 7) == 4) + { + /* Has SIB*/ + opcode_pc++; + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 4; + else if ((sib & 0x07) == 0x05) + opcode_pc += 4; + } + else + { + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 4; + else if ((modrm & 0xc7) == 0x05) + opcode_pc += 4; + } + } + else + { + if ((modrm & 0xc0) == 0x40) + opcode_pc++; + else if ((modrm & 0xc0) == 0x80) + opcode_pc += 2; + else if ((modrm & 0xc7) == 0x06) + opcode_pc += 2; + } + } + + opcode = fastreadb(cs + opcode_pc); + + ins_table = mod3 ? opcode_timings_0f0f_mod3 : opcode_timings_0f0f; + deps = mod3 ? opcode_deps_0f0f_mod3 : opcode_deps_0f0f; + } + else + { + ins_table = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + } +// pclog("timings 0f\n"); + break; + + case 0xd8: + ins_table = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); + break; + case 0xd9: + ins_table = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); + break; + case 0xda: + ins_table = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); + break; + case 0xdb: + ins_table = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); + break; + case 0xdc: + ins_table = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); + break; + case 0xdd: + ins_table = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); + break; + case 0xde: + ins_table = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); + break; + case 0xdf: + ins_table = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; +// pclog("timings df\n"); + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: + ins_table = mod3 ? opcode_timings_80_mod3 : opcode_timings_80; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + case 0x81: case 0x83: + ins_table = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; + 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 0xd0: case 0xd2: + ins_table = mod3 ? opcode_timings_shift_b_mod3 : opcode_timings_shift_b; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; +// pclog("timings c0\n"); + break; + + case 0xc1: case 0xd1: case 0xd3: + ins_table = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; +// pclog("timings c1\n"); + break; + + case 0xf6: + ins_table = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); + break; + case 0xf7: + ins_table = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); + break; + case 0xff: + ins_table = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); + break; + + default: + ins_table = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; +// pclog("timings normal\n"); + break; + } + } + + if (ins_table[opcode]) + decode_instruction(ins_table[opcode], deps[opcode], fetchdat, op_32, bit8); + else + decode_instruction(&vector_alu1_op, 0, fetchdat, op_32, bit8); + codegen_block_cycles += (last_complete_timestamp - old_last_complete_timestamp); +} + +void codegen_timing_k6_block_end() +{ + if (decode_buffer.nr_uops) + { + int old_last_complete_timestamp = last_complete_timestamp; + decode_flush(); + codegen_block_cycles += (last_complete_timestamp - old_last_complete_timestamp); + } +} + +int codegen_timing_k6_jump_cycles() +{ + if (decode_buffer.nr_uops) + return 1; + return 0; +} + +codegen_timing_t codegen_timing_k6 = +{ + codegen_timing_k6_start, + codegen_timing_k6_prefix, + codegen_timing_k6_opcode, + codegen_timing_k6_block_start, + codegen_timing_k6_block_end, + codegen_timing_k6_jump_cycles +}; diff --git a/src/codegen_timing_p6.c b/src/codegen_timing_p6.c new file mode 100644 index 0000000..a608164 --- /dev/null +++ b/src/codegen_timing_p6.c @@ -0,0 +1,2154 @@ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.h" +#include "mem.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +typedef enum uop_type_t +{ + UOP_ALU0 = 0, /*Executes in port 0 ALU*/ + UOP_ALU1, /*Executes in port 1 ALU*/ + UOP_ALU01, /*Executes in either port 0 or 1 ALU*/ + UOP_BRANCH, /*Executes in port 1 branch*/ + UOP_LOAD, /*Executes in port 2 Load unit*/ + UOP_STOREADDR, /*Executes in port 3 Store Address unit*/ + UOP_STOREDATA, /*Executes in port 4 Store Data unit*/ + UOP_FLOAT, /*Executes in port 0 Floating Point unit*/ + UOP_ALU0_SEG /*Executes in port 0 ALU, loads segment, causing pipeline flush on PPro*/ +} uop_type_t; + +#define MAX_UOPS 300 + +typedef struct p6_uop_t +{ + uop_type_t type; + int throughput; + int latency; +} p6_uop_t; + +typedef struct p6_instruction_t +{ + int nr_uops; + p6_uop_t uop[MAX_UOPS]; +} p6_instruction_t; + +static const p6_instruction_t alu_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t alu0_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t alu1_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU1, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t alu01_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t alu4_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t alu6_op = +{ + .nr_uops = 6, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t aluc_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t load_alu_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t load_aluc_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t alu_store_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t alu0_store_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t aluc_store_op = +{ + .nr_uops = 6, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; + +static const p6_instruction_t branch_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_BRANCH, .throughput = 1, .latency = 1} +}; + +static const p6_instruction_t load_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2} +}; + +static const p6_instruction_t store_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; + + +static const p6_instruction_t bswap_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t leave_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t lods_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t loop_op = +{ + .nr_uops = 11, + .uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU1, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, +}; +static const p6_instruction_t movs_op = +{ + .nr_uops = 6, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, +}; +static const p6_instruction_t pop_reg_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t pop_mem_op = +{ + .nr_uops = 8, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t push_imm_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t push_mem_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, +}; +static const p6_instruction_t push_seg_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t rcx_op = +{ + .nr_uops = 8, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, +}; +static const p6_instruction_t rcx_store_op = +{ + .nr_uops = 11, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[10] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t stos_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t xchg_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; + +static const p6_instruction_t mmx_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t mmx_mul_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 3} +}; +static const p6_instruction_t mmx_shift_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU1, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t load_mmx_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t load_mmx_mul_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t load_mmx_shift_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU1, .throughput = 1, .latency = 1} +}; + +static const p6_instruction_t faddsub_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 3} +}; +static const p6_instruction_t load_faddsub_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 3} +}; +static const p6_instruction_t fbstp_op = +{ + .nr_uops = 5, + .uop[0] = {.type = UOP_FLOAT, .throughput = 165, .latency = 165}, + .uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t fcom_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t load_fcom_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t fcompp_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t fild_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t load_fi_op = +{ + .nr_uops = 7, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t fmul_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 5} +}; +static const p6_instruction_t load_fmul_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 5} +}; + +static const p6_instruction_t fxch_op = +{ + .nr_uops = 0 +}; + +static const p6_instruction_t fist_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; + +static const p6_instruction_t fdiv_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 37, .latency = 38} +}; +static const p6_instruction_t fdiv_mem_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 37, .latency = 38} +}; +static const p6_instruction_t fsin_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 62, .latency = 62} +}; +static const p6_instruction_t fsqrt_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 69, .latency = 69} +}; + +static const p6_instruction_t float_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1} +}; + +static const p6_instruction_t fldcw_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_FLOAT, .throughput = 7, .latency = 7}, +}; +static const p6_instruction_t flde_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t frstor_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 72, .latency = 72} +}; +static const p6_instruction_t fsave_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_FLOAT, .throughput = 141, .latency = 141} +}; +static const p6_instruction_t fste_op = +{ + .nr_uops = 6, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t fstsw_ax_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t fstsw_mem_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_FLOAT, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; + +static const p6_instruction_t aad_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 4}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t aam_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 4}, + .uop[2] = {.type = UOP_ALU1, .throughput = 1, .latency = 9}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t arpl_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_ALU01, .throughput = 3, .latency = 3}, + .uop[1] = {.type = UOP_ALU01, .throughput = 3, .latency = 3} +}; +static const p6_instruction_t bound_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_ALU0, .throughput = 7, .latency = 7}, + .uop[3] = {.type = UOP_ALU01, .throughput = 6, .latency = 6} +}; +static const p6_instruction_t bsx_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU1, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t load_bsx_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU1, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t call_far_op = +{ + .nr_uops = 6, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU0_SEG, .throughput = 28, .latency = 28} +}; +static const p6_instruction_t load_call_far_op = +{ + .nr_uops = 7, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU0_SEG, .throughput = 28, .latency = 28} +}; +static const p6_instruction_t cli_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU01, .throughput = 9, .latency = 9} +}; +static const p6_instruction_t sti_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU01, .throughput = 17, .latency = 17} +}; +static const p6_instruction_t cmps_op = +{ + .nr_uops = 6, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t cmpxchg_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t cpuid_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU0, .throughput = 48, .latency = 48} +}; +/*static const p6_instruction_t div8_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_ALU0, .throughput = 12, .latency = 17}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +};*/ +/*static const p6_instruction_t div8_mem_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[0] = {.type = UOP_ALU0, .throughput = 12, .latency = 17}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +};*/ +static const p6_instruction_t div16_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_ALU0, .throughput = 21, .latency = 21}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t div16_mem_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[0] = {.type = UOP_ALU0, .throughput = 21, .latency = 21}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t div32_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_ALU0, .throughput = 35, .latency = 35}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t div32_mem_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[0] = {.type = UOP_ALU0, .throughput = 35, .latency = 35}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t emms_op = +{ + .nr_uops = 11, + .uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[10] = {.type = UOP_ALU0, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t enter_op = +{ + .nr_uops = 14, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[11] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[12] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[13] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t io_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_LOAD, .throughput = 18, .latency = 18} +}; +static const p6_instruction_t ins_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_ALU0, .throughput = 18, .latency = 18}, + .uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t int_op = +{ + .nr_uops = 7, + .uop[0] = {.type = UOP_ALU0, .throughput = 20, .latency = 20}, + .uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, +}; +static const p6_instruction_t iret_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[3] = {.type = UOP_ALU01, .throughput = 20, .latency = 20}, +}; +static const p6_instruction_t invd_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU01, .throughput = 1000, .latency = 1000} +}; +static const p6_instruction_t jmp_far_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU0_SEG, .throughput = 21, .latency = 21} +}; +static const p6_instruction_t load_jmp_far_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_ALU0_SEG, .throughput = 21, .latency = 21} +}; +static const p6_instruction_t lss_op = +{ + .nr_uops = 11, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[3] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +/*static const p6_instruction_t mov_mem_seg_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, +};*/ +static const p6_instruction_t mov_seg_mem_op = +{ + .nr_uops = 9, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU0, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t mov_seg_reg_op = +{ + .nr_uops = 8, + .uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0_SEG,.throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t mul_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU0, .throughput = 1, .latency = 4} +}; +static const p6_instruction_t mul_mem_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 4} +}; +static const p6_instruction_t outs_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0, .throughput = 18, .latency = 18}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t pusha_op = +{ + .nr_uops = 18, + .uop[0] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[10] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[11] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[12] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[13] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[14] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[15] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[16] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[17] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t popa_op = +{ + .nr_uops = 10, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t popf_op = +{ + .nr_uops = 17, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[11] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[12] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[13] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[14] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[15] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[16] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, +}; +static const p6_instruction_t pushf_op = +{ + .nr_uops = 16, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[7] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[8] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[9] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[10] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[11] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[12] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[13] = {.type = UOP_ALU0, .throughput = 1, .latency = 1}, + .uop[14] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[15] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t ret_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU1, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t reti_op = +{ + .nr_uops = 5, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_ALU1, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t retf_op = +{ + .nr_uops = 4, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[3] = {.type = UOP_ALU0, .throughput = 23, .latency = 23}, +}; +static const p6_instruction_t scas_op = +{ + .nr_uops = 3, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t xchg_mem_op = +{ + .nr_uops = 7, + .uop[0] = {.type = UOP_LOAD, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[2] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[3] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[4] = {.type = UOP_STOREADDR, .throughput = 1, .latency = 1}, + .uop[5] = {.type = UOP_STOREDATA, .throughput = 1, .latency = 1}, + .uop[6] = {.type = UOP_ALU01, .throughput = 1, .latency = 1} +}; +static const p6_instruction_t xlat_op = +{ + .nr_uops = 2, + .uop[0] = {.type = UOP_ALU01, .throughput = 1, .latency = 1}, + .uop[1] = {.type = UOP_LOAD, .throughput = 1, .latency = 2} +}; +static const p6_instruction_t wbinvd_op = +{ + .nr_uops = 1, + .uop[0] = {.type = UOP_ALU0, .throughput = 10000, .latency = 10000} +}; + +#define INVALID NULL + +static const p6_instruction_t *opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ &alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op, +/* ADD ADD PUSH ES POP ES*/ + &alu_op, &alu_op, &push_seg_op, &mov_seg_mem_op, +/* OR OR OR OR*/ + &alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op, +/* OR OR PUSH CS */ + &alu_op, &alu_op, &push_seg_op, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ &aluc_store_op, &aluc_store_op, &load_aluc_op, &load_aluc_op, +/* ADC ADC PUSH SS POP SS*/ + &aluc_op, &aluc_op, &push_seg_op, &mov_seg_mem_op, +/* SBB SBB SBB SBB*/ +/*10*/ &aluc_store_op, &aluc_store_op, &load_aluc_op, &load_aluc_op, +/* SBB SBB PUSH DS POP DS*/ + &aluc_op, &aluc_op, &push_seg_op, &mov_seg_mem_op, + +/* AND AND AND AND*/ +/*20*/ &alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op, +/* AND AND DAA*/ + &alu_op, &alu_op, INVALID, &alu1_op, +/* SUB SUB SUB SUB*/ + &alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op, +/* SUB SUB DAS*/ + &alu_op, &alu_op, INVALID, &alu1_op, + +/* XOR XOR XOR XOR*/ +/*30*/ &alu_store_op, &alu_store_op, &load_alu_op, &load_alu_op, +/* XOR XOR AAA*/ + &alu_op, &alu_op, INVALID, &alu1_op, +/* CMP CMP CMP CMP*/ + &load_alu_op, &load_alu_op, &load_alu_op, &load_alu_op, +/* CMP CMP AAS*/ + &alu_op, &alu_op, INVALID, &alu1_op, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* INC ESP INC EBP INC ESI INC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ &store_op, &store_op, &store_op, &store_op, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + &store_op, &store_op, &store_op, &store_op, +/* POP EAX POP ECX POP EDX POP EBX*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, +/* POP ESP POP EBP POP ESI POP EDI*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ &pusha_op, &popa_op, &bound_op, &arpl_op, + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + &push_imm_op, &mul_op, &push_imm_op, &mul_op, +/* INSB INSW OUTSB OUTSW*/ + &ins_op, &ins_op, &outs_op, &outs_op, + +/* Jxx*/ +/*70*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + &load_alu_op, &load_alu_op, &xchg_mem_op, &xchg_mem_op, +/* MOV MOV MOV MOV*/ + &store_op, &store_op, &load_op, &load_op, +/* MOV from seg LEA MOV to seg POP*/ + &store_op, &alu0_op, &mov_seg_mem_op, &pop_mem_op, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ &alu_op, &xchg_op, &xchg_op, &xchg_op, +/* XCHG XCHG XCHG XCHG*/ + &xchg_op, &xchg_op, &xchg_op, &xchg_op, +/* CBW CWD CALL far WAIT*/ + &alu_op, &alu0_op, &call_far_op, &alu_op, +/* PUSHF POPF SAHF LAHF*/ + &pushf_op, &popf_op, &alu_op, &alu_op, + +/* MOV MOV MOV MOV*/ +/*a0*/ &load_op, &load_op, &store_op, &store_op, +/* MOVSB MOVSW CMPSB CMPSW*/ + &movs_op, &movs_op, &cmps_op, &cmps_op, +/* TEST TEST STOSB STOSW*/ + &load_alu_op, &load_alu_op, &stos_op, &stos_op, +/* LODSB LODSW SCASB SCASW*/ + &lods_op, &lods_op, &scas_op, &scas_op, + +/* MOV*/ +/*b0*/ &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, &reti_op, &ret_op, +/* LES LDS MOV MOV*/ + &lss_op, &lss_op, &store_op, &store_op, +/* ENTER LEAVE RETF RETF*/ + &enter_op, &leave_op, &retf_op, &retf_op, +/* INT3 INT INTO IRET*/ + &int_op, &int_op, &int_op, &iret_op, + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + &aam_op, &aad_op, &alu_op, &xlat_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ &loop_op, &loop_op, &loop_op, &loop_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &io_op, &io_op, &io_op, &io_op, +/* CALL JMP JMP JMP*/ + &store_op, &branch_op, &jmp_far_op, &branch_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &io_op, &io_op, &io_op, &io_op, + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, INVALID, INVALID, +/* HLT CMC*/ + &alu4_op, &alu_op, INVALID, INVALID, +/* CLC STC CLI STI*/ + &alu_op, &alu_op, &cli_op, &sti_op, +/* CLD STD INCDEC*/ + &alu4_op, &alu4_op, &store_op, INVALID +}; + +static const p6_instruction_t *opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* ADD ADD PUSH ES POP ES*/ + &alu_op, &alu_op, &push_seg_op, &mov_seg_mem_op, +/* OR OR OR OR*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* OR OR PUSH CS */ + &alu_op, &alu_op, &push_seg_op, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ &aluc_op, &aluc_op, &aluc_op, &aluc_op, +/* ADC ADC PUSH SS POP SS*/ + &aluc_op, &aluc_op, &push_seg_op, &mov_seg_mem_op, +/* SBB SBB SBB SBB*/ + &aluc_op, &aluc_op, &aluc_op, &aluc_op, +/* SBB SBB PUSH DS POP DS*/ + &aluc_op, &aluc_op, &push_seg_op, &mov_seg_mem_op, + +/* AND AND AND AND*/ +/*20*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* AND AND DAA*/ + &alu_op, &alu_op, INVALID, &alu1_op, +/* SUB SUB SUB SUB*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* SUB SUB DAS*/ + &alu_op, &alu_op, INVALID, &alu1_op, + +/* XOR XOR XOR XOR*/ +/*30*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* XOR XOR AAA*/ + &alu_op, &alu_op, INVALID, &alu1_op, +/* CMP CMP CMP CMP*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* CMP CMP AAS*/ + &alu_op, &alu_op, INVALID, &alu1_op, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ &alu_op, &alu_op, &alu_op, &alu_op, +/* INC ESP INC EBP INC ESI INC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + &alu_op, &alu_op, &alu_op, &alu_op, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + &alu_op, &alu_op, &alu_op, &alu_op, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ &store_op, &store_op, &store_op, &store_op, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + &store_op, &store_op, &store_op, &store_op, +/* POP EAX POP ECX POP EDX POP EBX*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, +/* POP ESP POP EBP POP ESI POP EDI*/ + &pop_reg_op, &pop_reg_op, &pop_reg_op, &pop_reg_op, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ &pusha_op, &popa_op, &bound_op, &arpl_op, + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + &push_imm_op, &mul_op, &push_imm_op, &mul_op, +/* INSB INSW OUTSB OUTSW*/ + &ins_op, &ins_op, &outs_op, &outs_op, + +/* Jxx*/ +/*70*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + &alu_op, &alu_op, &xchg_op, &xchg_op, +/* MOV MOV MOV MOV*/ + &store_op, &store_op, &load_op, &load_op, +/* MOV from seg LEA MOV to seg POP*/ + &alu_op, &alu0_op, &mov_seg_reg_op, &pop_reg_op, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ &alu_op, &xchg_op, &xchg_op, &xchg_op, +/* XCHG XCHG XCHG XCHG*/ + &xchg_op, &xchg_op, &xchg_op, &xchg_op, +/* CBW CWD CALL far WAIT*/ + &alu_op, &alu0_op, &call_far_op, &alu_op, +/* PUSHF POPF SAHF LAHF*/ + &pushf_op, &popf_op, &alu_op, &alu_op, + +/* MOV MOV MOV MOV*/ +/*a0*/ &load_op, &load_op, &store_op, &store_op, +/* MOVSB MOVSW CMPSB CMPSW*/ + &movs_op, &movs_op, &cmps_op, &cmps_op, +/* TEST TEST STOSB STOSW*/ + &alu_op, &alu_op, &stos_op, &stos_op, +/* LODSB LODSW SCASB SCASW*/ + &lods_op, &lods_op, &scas_op, &scas_op, + +/* MOV*/ +/*b0*/ &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, &reti_op, &ret_op, +/* LES LDS MOV MOV*/ + &lss_op, &lss_op, &store_op, &store_op, +/* ENTER LEAVE RETF RETF*/ + &enter_op, &leave_op, &retf_op, &retf_op, +/* INT3 INT INTO IRET*/ + &int_op, &int_op, &int_op, &iret_op, + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + &aam_op, &aad_op, &alu_op, &xlat_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ &loop_op, &loop_op, &loop_op, &loop_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &io_op, &io_op, &io_op, &io_op, +/* CALL JMP JMP JMP*/ + &store_op, &branch_op, &jmp_far_op, &branch_op, +/* IN AL IN AX OUT_AL OUT_AX*/ + &io_op, &io_op, &io_op, &io_op, + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, INVALID, INVALID, +/* HLT CMC*/ + &alu4_op, &alu_op, INVALID, INVALID, +/* CLC STC CLI STI*/ + &alu_op, &alu_op, &cli_op, &sti_op, +/* CLD STD INCDEC*/ + &alu4_op, &alu4_op, &alu_op, INVALID +}; + +static const p6_instruction_t *opcode_timings_0f[256] = +{ +/*00*/ &alu6_op, &alu6_op, &alu6_op, &alu6_op, + INVALID, &alu6_op, &alu6_op, INVALID, + &invd_op, &wbinvd_op, INVALID, INVALID, + INVALID, &load_op, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ &alu6_op, &alu6_op, &alu6_op, &alu6_op, + &alu6_op, &alu6_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ &alu6_op, &alu6_op, &alu6_op, 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*/ &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &load_mmx_op, + INVALID, INVALID, &load_op, &load_op, + +/*70*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + &load_mmx_op, &load_mmx_op, &load_mmx_op, &emms_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, &store_op, &store_op, + +/*80*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*90*/ &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + +/*a0*/ &push_seg_op, &mov_seg_mem_op, &cpuid_op, &load_alu_op, + &alu_store_op, &alu_store_op, INVALID, INVALID, + &push_seg_op, &mov_seg_mem_op, INVALID, &load_alu_op, + &alu_store_op, &alu_store_op, INVALID, &mul_op, + +/*b0*/ &cmpxchg_op, &cmpxchg_op, &lss_op, &load_alu_op, + &lss_op, &lss_op, &load_alu_op, &load_alu_op, + INVALID, INVALID, &load_alu_op, &load_alu_op, + &load_bsx_op, &load_bsx_op, &load_alu_op, &load_alu_op, + +/*c0*/ &alu_store_op, &alu_store_op, INVALID, INVALID, + INVALID, INVALID, INVALID, &cmpxchg_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + +/*d0*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + INVALID, &load_mmx_mul_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + +/*e0*/ &load_mmx_op, &load_mmx_shift_op, &load_mmx_shift_op, INVALID, + INVALID, &load_mmx_mul_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + &load_mmx_op, &load_mmx_op, INVALID, &load_mmx_op, + +/*f0*/ INVALID, &load_mmx_shift_op, &load_mmx_shift_op, &load_mmx_shift_op, + INVALID, &load_mmx_mul_op, INVALID, INVALID, + &load_mmx_op, &load_mmx_op, &load_mmx_op, INVALID, + &load_mmx_op, &load_mmx_op, &load_mmx_op, INVALID, +}; +static const p6_instruction_t *opcode_timings_0f_mod3[256] = +{ +/*00*/ &alu6_op, &alu6_op, &alu6_op, &alu6_op, + INVALID, &alu6_op, &alu6_op, INVALID, + &invd_op, &wbinvd_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ &alu6_op, &alu6_op, &alu6_op, &alu6_op, + &alu6_op, &alu6_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ &alu6_op, &alu6_op, &alu6_op, 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*/ &mmx_op, &mmx_op, &mmx_op, &mmx_op, + &mmx_op, &mmx_op, &mmx_op, &mmx_op, + &mmx_op, &mmx_op, &mmx_op, &mmx_op, + INVALID, INVALID, &mmx_op, &mmx_op, + +/*70*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + &mmx_op, &mmx_op, &mmx_op, &emms_op, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, &mmx_op, &mmx_op, + +/*80*/ &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + &branch_op, &branch_op, &branch_op, &branch_op, + +/*90*/ &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + &alu_op, &alu_op, &alu_op, &alu_op, + +/*a0*/ &push_seg_op, &mov_seg_mem_op, &cpuid_op, &alu_op, + &alu_op, &alu_op, INVALID, INVALID, + &push_seg_op, &mov_seg_mem_op, INVALID, &alu_op, + &alu_op, &alu_op, INVALID, &mul_op, + +/*b0*/ &cmpxchg_op, &cmpxchg_op, &lss_op, &alu_op, + &lss_op, &lss_op, &alu_op, &alu_op, + INVALID, INVALID, &alu_op, &alu_op, + &bsx_op, &bsx_op, &alu_op, &alu_op, + +/*c0*/ &alu_op, &alu_op, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + &bswap_op, &bswap_op, &bswap_op, &bswap_op, + +/*d0*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + INVALID, &mmx_mul_op, INVALID, INVALID, + &mmx_op, &mmx_op, INVALID, &mmx_op, + &mmx_op, &mmx_op, INVALID, &mmx_op, + +/*e0*/ &mmx_op, &mmx_shift_op, &mmx_shift_op, INVALID, + INVALID, &mmx_mul_op, INVALID, INVALID, + &mmx_op, &mmx_op, INVALID, &mmx_op, + &mmx_op, &mmx_op, INVALID, &mmx_op, + +/*f0*/ INVALID, &mmx_shift_op, &mmx_shift_op, &mmx_shift_op, + INVALID, &mmx_mul_op, INVALID, INVALID, + &mmx_op, &mmx_op, &mmx_op, INVALID, + &mmx_op, &mmx_op, &mmx_op, INVALID, +}; + +static const p6_instruction_t *opcode_timings_shift[8] = +{ + &alu0_store_op, &alu0_store_op, &rcx_store_op, &rcx_store_op, + &alu0_store_op, &alu0_store_op, &alu0_store_op, &alu0_store_op +}; +static const p6_instruction_t *opcode_timings_shift_mod3[8] = +{ + &alu0_op, &alu0_op, &rcx_op, &rcx_op, + &alu0_op, &alu0_op, &alu0_op, &alu0_op +}; + +static const p6_instruction_t *opcode_timings_8x[8] = +{ + &alu_store_op, &alu_store_op, &aluc_store_op, &aluc_store_op, + &alu_store_op, &alu_store_op, &alu_store_op, &alu_store_op, +}; +static const p6_instruction_t *opcode_timings_8x_mod3[8] = +{ + &alu_op, &alu_op, &aluc_op, &aluc_op, + &alu_op, &alu_op, &alu_op, &alu_op, +}; + +static const p6_instruction_t *opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + &load_alu_op, INVALID, &alu_store_op, &alu_store_op, +/* MUL IMUL DIV IDIV*/ + &mul_mem_op, &mul_mem_op, &div16_mem_op, &div16_mem_op, +}; +static const p6_instruction_t *opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + &alu_op, INVALID, &alu_op, &alu_op, +/* MUL IMUL DIV IDIV*/ + &mul_op, &mul_op, &div16_op, &div16_op, +}; +static const p6_instruction_t *opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + &load_alu_op, INVALID, &alu_store_op, &alu_store_op, +/* MUL IMUL DIV IDIV*/ + &mul_mem_op, &mul_mem_op, &div32_mem_op, &div32_mem_op, +}; +static const p6_instruction_t *opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + &alu_op, INVALID, &alu_op, &alu_op, +/* MUL IMUL DIV IDIV*/ + &mul_op, &mul_op, &div32_op, &div32_op, +}; +static const p6_instruction_t *opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + &alu_store_op, &alu_store_op, &store_op, &load_call_far_op, +/* JMP JMP far PUSH*/ + &branch_op, &load_jmp_far_op, &push_mem_op, INVALID +}; +static const p6_instruction_t *opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + &alu_op, &alu_op, &store_op, &call_far_op, +/* JMP JMP far PUSH*/ + &branch_op, &load_jmp_far_op, &push_mem_op, INVALID +}; + +static const p6_instruction_t *opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + &load_faddsub_op, &load_fmul_op, &fcom_op, &load_fcom_op, +/* FSUBs FSUBRs FDIVs FDIVRs*/ + &load_faddsub_op, &load_faddsub_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const p6_instruction_t *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + &faddsub_op, &fmul_op, &fcom_op, &fcom_op, +/* FSUB FSUBR FDIV FDIVR*/ + &faddsub_op, &faddsub_op, &fdiv_op, &fdiv_op, +}; + +static const p6_instruction_t *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + &load_op, INVALID, &store_op, &store_op, +/* FLDENV FLDCW FSTENV FSTCW*/ + &flde_op, &fldcw_op, &fste_op, &fstsw_mem_op +}; +static const p6_instruction_t *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + &float_op, &float_op, &float_op, &float_op, + &float_op, &float_op, &float_op, &float_op, + /*FXCH*/ + &fxch_op, &fxch_op, &fxch_op, &fxch_op, + &fxch_op, &fxch_op, &fxch_op, &fxch_op, + /*FNOP*/ + &float_op, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + &float_op, &float_op, &float_op, &float_op, + &float_op, &float_op, &float_op, &float_op, +/* opFCHS opFABS*/ + &float_op, &float_op, INVALID, INVALID, +/* opFTST opFXAM*/ + &float_op, &float_op, INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + &float_op, &float_op, &float_op, &float_op, +/* opFLDEG2 opFLDLN2 opFLDZ*/ + &float_op, &float_op, &float_op, INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + &fsin_op, &fsin_op, &fsin_op, &fsin_op, +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, &float_op, &float_op, +/* opFPREM opFSQRT opFSINCOS*/ + &fdiv_op, INVALID, &fsqrt_op, &fsin_op, +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + &float_op, &fdiv_op, &fsin_op, &fsin_op +}; + +static const p6_instruction_t *opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + &load_fi_op, &load_fi_op, &load_fcom_op, &load_fcom_op, +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + &load_fi_op, &load_fi_op, &load_fi_op, &load_fi_op, +}; +static const p6_instruction_t *opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, &fcompp_op, INVALID, INVALID +}; + +static const p6_instruction_t *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + &fild_op, INVALID, &fist_op, &fist_op, +/* FLDe FSTPe*/ + INVALID, &flde_op, INVALID, &fste_op +}; +static const p6_instruction_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, &float_op, &float_op, &float_op, +/* opFNOP opFNOP*/ + &float_op, &float_op, 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 const p6_instruction_t *opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + &load_faddsub_op, &load_fmul_op, &load_fcom_op, &load_fcom_op, +/* FSUBd FSUBRd FDIVd FDIVRd*/ + &load_faddsub_op, &load_faddsub_op, &fdiv_mem_op, &fdiv_mem_op, +}; +static const p6_instruction_t *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + &faddsub_op, &fmul_op, INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + &faddsub_op, &faddsub_op, &fdiv_op, &fdiv_op +}; + +static const p6_instruction_t *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + &load_op, INVALID, &store_op, &store_op, +/* FRSTOR FSAVE FSTSW*/ + &frstor_op, INVALID, &fsave_op, &fstsw_mem_op +}; +static const p6_instruction_t *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + &float_op, INVALID, &float_op, &float_op, +/* FUCOM FUCOMP*/ + &float_op, &float_op, INVALID, INVALID +}; + +static const p6_instruction_t *opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + &load_fi_op, &load_fi_op, &load_fcom_op, &load_fcom_op, +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + &load_fi_op, &load_fi_op, &load_fi_op, &load_fi_op, +}; +static const p6_instruction_t *opcode_timings_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + &faddsub_op, &fmul_op, INVALID, &fcompp_op, +/* FSUBP FSUBRP FDIVP FDIVRP*/ + &faddsub_op, &faddsub_op, &fdiv_op, &fdiv_op, +}; + +static const p6_instruction_t *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + &fild_op, INVALID, &fist_op, &fist_op, +/* FILDiq FBSTP FISTPiq*/ + INVALID, &fild_op, &fbstp_op, &fist_op, +}; +static const p6_instruction_t *opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + &fstsw_ax_op, INVALID, INVALID, INVALID +}; + + +static uint8_t last_prefix; +static int prefixes; + +static int decode_timestamp; +static int last_complete_timestamp; + +typedef struct p6_unit_t +{ + const uint32_t uop_mask; + const int port; + int first_available_cycle; +} p6_unit_t; + +enum +{ + UNIT_INT0 = 0, + UNIT_INT1, + UNIT_FPU, + UNIT_MMX_ADD, + UNIT_MMX_MUL, + UNIT_JUMP, + UNIT_LOAD, + UNIT_STORE_ADDR, + UNIT_STORE_DATA +}; + +/*Each port can only be used once per clock*/ +typedef struct p6_port_t +{ + uint32_t unit_mask; +} p6_port_t; + +static int port_last_timestamps[5]; + +static const p6_port_t ports[] = +{ + {UNIT_INT0 | UNIT_FPU | UNIT_MMX_MUL}, + {UNIT_INT1 | UNIT_MMX_ADD | UNIT_JUMP}, + {UNIT_LOAD}, + {UNIT_STORE_ADDR}, + {UNIT_STORE_DATA} +}; +const int nr_ports = (sizeof(ports) / sizeof(p6_port_t)); + +static p6_unit_t units[] = +{ + [UNIT_INT0] = {.uop_mask = (1 << UOP_ALU0) | (1 << UOP_ALU0_SEG) | (1 << UOP_ALU01), .port = 0}, /*Integer 0*/ + [UNIT_INT1] = {.uop_mask = (1 << UOP_ALU1) | (1 << UOP_ALU01), .port = 1}, /*Integer 1*/ + [UNIT_FPU] = {.uop_mask = 1 << UOP_FLOAT, .port = 0}, + [UNIT_MMX_ADD] = {.uop_mask = 0, .port = 1}, + [UNIT_MMX_MUL] = {.uop_mask = 0, .port = 0}, + [UNIT_JUMP] = {.uop_mask = 1 << UOP_BRANCH, .port = 1}, + [UNIT_LOAD] = {.uop_mask = 1 << UOP_LOAD, .port = 2}, + [UNIT_STORE_ADDR] = {.uop_mask = 1 << UOP_STOREADDR, .port = 3}, + [UNIT_STORE_DATA] = {.uop_mask = 1 << UOP_STOREDATA, .port = 4} +}; +const int nr_units = (sizeof(units) / sizeof(p6_unit_t)); + +static int rat_timestamp = 0; +static int rat_uops = 0; + +static int uop_run(const p6_uop_t *uop, int decode_time) +{ + int c; + p6_unit_t *best_unit = NULL; + int best_start_cycle = 99999; + + /*Peak of 3 uOPs from decode to RAT per cycle*/ + if (decode_time < rat_timestamp) + decode_time = rat_timestamp; + else if (decode_time > rat_timestamp) + { + rat_timestamp = decode_time; + rat_uops = 0; + } + + rat_uops++; + if (rat_uops == 3) + { + rat_timestamp++; + rat_uops = 0; + } + + + /*Find execution unit for this uOP*/ + for (c = 0; c < nr_units; c++) + { + p6_unit_t *unit = &units[c]; + if (unit->uop_mask & (1 << uop->type)) + { + int start_cycle = MAX(unit->first_available_cycle, + port_last_timestamps[units[c].port]); + + if (start_cycle < best_start_cycle) + { + best_unit = unit; + best_start_cycle = start_cycle; + } + } + } + if (!best_unit) + fatal("uop_run: can not find execution unit %x\n", uop->type); + + if (cpu_s->cpu_type == CPU_PENTIUMPRO && uop->type == UOP_ALU0_SEG) + { + /*Pentium Pro will flush pipeline on a segment load. Find last + execution unit to complete, then set earliest start times on + _all_ execution units to after this point*/ + int last_start_cycle = 0; + + for (c = 0; c < nr_units; c++) + { + p6_unit_t *unit = &units[c]; + int start_cycle = unit->first_available_cycle; + + if (start_cycle > last_start_cycle) + last_start_cycle = start_cycle; + } + for (c = 0; c < nr_units; c++) + units[c].first_available_cycle = last_start_cycle+1; + } + if (best_start_cycle < decode_time) + best_start_cycle = decode_time; + best_unit->first_available_cycle = best_start_cycle + uop->throughput; + port_last_timestamps[best_unit->port] = best_start_cycle + 1; + + return best_start_cycle + uop->throughput; +// return decode_time+1; +} + +/*The P6 decoder can decode up to three instructions per clock + First can be up to 4 uOPs + Second and third must be 1 uOP each + Up to 16 bytes per cycle + 1 cycle per prefix beyond 1 prefix + 0x66 causes delays if instruction has immediate + 0x67 causes delays if modr/m present (and mod != 3) +*/ +static struct +{ + int nr_ins; + int nr_uops; + const p6_uop_t *uops[6]; + /*Earliest time a uop can start. If the timestamp is -1, then the uop is + part of a dependency chain and the start time is the completion time of + the previous uop*/ + int earliest_start[6]; +} decode_buffer; + +#define NR_REGS 8 +/*Timestamp of when last operation on an integer register completed*/ +static int reg_available_timestamp[NR_REGS]; +/*Timestamp of when last operation on an FPU register completed*/ +static int fpu_st_timestamp[8]; +/*Completion time of the last uop to be processed. Used to calculate timing of + dependent uop chains*/ +static int last_uop_timestamp = 0; + +static int ifetch_length = 0; +static int has_66_prefix, has_67_prefix; + +static void decode_flush() +{ + int c; + int uop_timestamp = 0; + + /*Ensure that uops can not be submitted before they have been decoded*/ + if (decode_timestamp > last_uop_timestamp) + last_uop_timestamp = decode_timestamp; + + /*Submit uops to execution units, and determine the latest completion time*/ + for (c = 0; c < decode_buffer.nr_uops; c++) + { + int start_timestamp; + +// pclog("uOP %i, %p\n", c, decode_buffer.uops[c]); + + if (decode_buffer.earliest_start[c] == -1) + start_timestamp = last_uop_timestamp; + else + start_timestamp = decode_buffer.earliest_start[c]; + + last_uop_timestamp = uop_run(decode_buffer.uops[c], start_timestamp); + if (last_uop_timestamp > uop_timestamp) + uop_timestamp = last_uop_timestamp; + } + + /*Calculate opquad completion time. Since opquads complete in order, it + must be after the last completion.*/ + if (uop_timestamp <= last_complete_timestamp) + last_complete_timestamp = last_complete_timestamp + 1; + else + last_complete_timestamp = uop_timestamp; + + decode_timestamp++; + decode_buffer.nr_uops = 0; + decode_buffer.nr_ins = 0; + ifetch_length = 0; +} + +/*The instruction is only of interest here if it's longer than 8 bytes, as that's the + limit on P6 short decoding*/ +static int codegen_timing_instr_length(uint64_t deps, uint32_t fetchdat, int op_32) +{ + int len = prefixes + 1; /*Opcode*/ + if (deps & MODRM) + { + len++; /*ModR/M*/ + if (deps & HAS_IMM8) + len++; + if (deps & HAS_IMM1632) + len += (op_32 & 0x100) ? 4 : 2; + + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /* Has SIB*/ + len++; + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0x700) == 0x500) + len += 4; + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0xc7) == 0x05) + len += 4; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 2; + else if ((fetchdat & 0xc7) == 0x06) + len += 2; + } + } + + return len; +} + +static void decode_instruction(const p6_instruction_t *ins, uint64_t deps, uint32_t fetchdat, int op_32, uint32_t op_pc, int bit8) +{ + uint32_t regmask_required; + uint32_t regmask_modified; + int c, d; + int earliest_start; + int instr_length = codegen_timing_instr_length(deps, fetchdat, op_32); + + if (has_66_prefix && (deps & HAS_IMM1632)) + decode_timestamp += 2; + if (has_67_prefix && (deps & MODRM)) + decode_timestamp += 4; + + earliest_start = decode_timestamp; + + /*Generate input register mask, and determine the earliest time this + instruction can start. This is not accurate, as this is calculated per + x86 instruction when it should be handled per uop*/ + regmask_required = get_dstdep_mask(deps, fetchdat, bit8); + regmask_required |= get_addr_regmask(deps, fetchdat, op_32); + for (c = 0; c < 8; c++) + { + if (regmask_required & (1 << c)) + { + if (reg_available_timestamp[c] > decode_timestamp) + earliest_start = reg_available_timestamp[c]; + } + } + if ((deps & FPU_RW_ST0) && fpu_st_timestamp[0] > decode_timestamp) + earliest_start = fpu_st_timestamp[0]; + if ((deps & FPU_RW_ST1) && fpu_st_timestamp[1] > decode_timestamp) + earliest_start = fpu_st_timestamp[1]; + if ((deps & FPU_RW_STREG)) + { + int reg = fetchdat & 7; + + if (fpu_st_timestamp[reg] > decode_timestamp) + earliest_start = fpu_st_timestamp[reg]; + } + +// pclog("ins->nr_uops=%i decode_buffer.nr_uops=%i decode_buffer.nr_ins=%i instr_length=%i\n", ins->nr_uops, decode_buffer.nr_uops, decode_buffer.nr_ins, instr_length); + + /*Can only decode 16 bytes per cycle*/ + if ((ifetch_length + instr_length) > 16) + decode_flush(); + else + ifetch_length += instr_length; + + if (ins->nr_uops > 4) + { +// pclog("Long decode\n"); + /*Multi-cycle decode (> 4 uOPs) instruction*/ + if (decode_buffer.nr_ins) + decode_flush(); + + d = 0; + + for (c = 0; c < ins->nr_uops; c++) + { + decode_buffer.uops[d] = &ins->uop[c]; + if (c == 0) + decode_buffer.earliest_start[d] = earliest_start; + else + decode_buffer.earliest_start[d] = -1; + d++; + + if (d == 4) + { + d = 0; + decode_buffer.nr_uops = 4; + decode_flush(); + } + } + if (d) + { + decode_buffer.nr_uops = d; + decode_flush(); + } + } + else if (ins->nr_uops > 1 || instr_length > 8) + { +// pclog("Mid decode\n"); + /*Long (> 1 uOPs) instruction*/ + if (decode_buffer.nr_ins) + decode_flush(); + + decode_buffer.nr_uops = ins->nr_uops; + + for (c = 0; c < ins->nr_uops; c++) + { + decode_buffer.uops[c] = &ins->uop[c]; + if (c == 0) + decode_buffer.earliest_start[c] = earliest_start; + else + decode_buffer.earliest_start[c] = -1; + } + decode_buffer.nr_ins++; + } + else if (ins->nr_uops == 1) + { +// pclog("Short decode\n"); + /*Short (1 uOP) instruction*/ + decode_buffer.uops[decode_buffer.nr_uops] = &ins->uop[0]; + decode_buffer.earliest_start[decode_buffer.nr_uops] = earliest_start; + decode_buffer.nr_ins++; + decode_buffer.nr_uops++; + + if (decode_buffer.nr_ins == 3) + decode_flush(); + } + + /*Update write timestamps for any output registers*/ + regmask_modified = get_dstdep_mask(deps, fetchdat, bit8); + for (c = 0; c < 8; c++) + { + if (regmask_modified & (1 << c)) + reg_available_timestamp[c] = last_complete_timestamp; + } + if (deps & FPU_POP) + { + for (c = 0; c < 7; c++) + fpu_st_timestamp[c] = fpu_st_timestamp[c+1]; + fpu_st_timestamp[7] = 0; + } + if (deps & FPU_POP2) + { + for (c = 0; c < 6; c++) + fpu_st_timestamp[c] = fpu_st_timestamp[c+2]; + fpu_st_timestamp[6] = fpu_st_timestamp[7] = 0; + } + if (deps & FPU_PUSH) + { + for (c = 0; c < 7; c++) + fpu_st_timestamp[c+1] = fpu_st_timestamp[c]; + fpu_st_timestamp[0] = 0; + } + if (deps & FPU_WRITE_ST0) + fpu_st_timestamp[0] = last_complete_timestamp; + if (deps & FPU_WRITE_ST1) + fpu_st_timestamp[1] = last_complete_timestamp; + if (deps & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps & FPU_WRITE_ST0)) && + !(reg == 1 && (deps & FPU_WRITE_ST1))) + fpu_st_timestamp[reg] = last_complete_timestamp; + } +} + +void codegen_timing_p6_block_start() +{ + int c; + + for (c = 0; c < nr_units; c++) + units[c].first_available_cycle = 0; + + decode_timestamp = 0; + last_complete_timestamp = 0; + + rat_timestamp = 0; + rat_uops = 0; + + for (c = 0; c < 5; c++) + port_last_timestamps[c] = 0; + + for (c = 0; c < NR_REGS; c++) + reg_available_timestamp[c] = 0; + for (c = 0; c < 8; c++) + fpu_st_timestamp[c] = 0; + + ifetch_length = 0; +} + +void codegen_timing_p6_start() +{ +// units = p6_units; +// nr_units = NR_P6_UNITS; + last_prefix = 0; + prefixes = 0; + has_66_prefix = 0; + has_67_prefix = 0; +} + +/*Prefixes : + - first is free + - operand size prefix has a penalty of 'a few clocks' if instruction has 16 or + 32 bit immediate + - address size prefix has penalty if instruction has explicit memory operand*/ +void codegen_timing_p6_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if (last_prefix) /*First prefix is free*/ + decode_timestamp++; + if (prefix == 0x66) + has_66_prefix = 1; + if (prefix == 0x67) + has_67_prefix = 1; + + last_prefix = prefix; + prefixes++; +} + +void codegen_timing_p6_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + const p6_instruction_t **ins_table; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int old_last_complete_timestamp = last_complete_timestamp; + int bit8 = !(opcode & 1); + +// pclog("timing_opcode %02x\n", opcode); + switch (last_prefix) + { + case 0x0f: + ins_table = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; +// pclog("timings 0f\n"); + break; + + case 0xd8: + ins_table = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); + break; + case 0xd9: + ins_table = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); + break; + case 0xda: + ins_table = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); + break; + case 0xdb: + ins_table = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); + break; + case 0xdc: + ins_table = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); + break; + case 0xdd: + ins_table = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); + break; + case 0xde: + ins_table = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); + break; + case 0xdf: + ins_table = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; +// pclog("timings df\n"); + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + ins_table = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x; + 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 0xd0: case 0xd2: + case 0xc1: case 0xd1: case 0xd3: + ins_table = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; +// pclog("timings c1\n"); + break; + + case 0xf6: + ins_table = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); + break; + case 0xf7: + ins_table = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); + break; + case 0xff: + ins_table = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); + break; + + default: + ins_table = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; +// pclog("timings normal\n"); + break; + } + } + + if (ins_table[opcode]) + decode_instruction(ins_table[opcode], deps[opcode], fetchdat, op_32, op_pc, bit8); + else + decode_instruction(&alu01_op, 0, fetchdat, op_32, op_pc, bit8); + codegen_block_cycles += (last_complete_timestamp - old_last_complete_timestamp); +} + +void codegen_timing_p6_block_end() +{ + if (decode_buffer.nr_ins) + { + int old_last_complete_timestamp = last_complete_timestamp; + decode_flush(); + codegen_block_cycles += (last_complete_timestamp - old_last_complete_timestamp); + } +// pclog("codegen_block_cycles=%i\n", codegen_block_cycles); +} + +int codegen_timing_p6_jump_cycles() +{ + if (decode_buffer.nr_uops) + return 1; + return 0; +} + +codegen_timing_t codegen_timing_p6 = +{ + codegen_timing_p6_start, + codegen_timing_p6_prefix, + codegen_timing_p6_opcode, + codegen_timing_p6_block_start, + codegen_timing_p6_block_end, + codegen_timing_p6_jump_cycles +}; + diff --git a/src/codegen_timing_pentium.c b/src/codegen_timing_pentium.c index 0fbf5e6..9690087 100644 --- a/src/codegen_timing_pentium.c +++ b/src/codegen_timing_pentium.c @@ -2,10 +2,11 @@ - U/V integer pairing - FPU/FXCH pairing - Prefix decode delay (including shadowing) + - FPU latencies + - AGI stalls Elements not taken into account : - Branch prediction (beyond most simplistic approximation) - PMMX decode queue - - FPU latencies - MMX latencies */ @@ -16,6 +17,10 @@ #include "x87.h" #include "mem.h" #include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + + /*Instruction has different execution time for 16 and 32 bit data. Does not pair */ #define CYCLES_HAS_MULTI (1 << 28) @@ -37,179 +42,126 @@ static int pair_timings[4][4] = /*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_REG (0ull << 0) +#define CYCLES_RM (1ull << 0) +#define CYCLES_RMW (2ull << 0) +#define CYCLES_BRANCH (3ull << 0) -#define CYCLES_MASK ((1 << 7) - 1) +/*Instruction has immediate data. Can only be used with PAIR_U/PAIR_V/PAIR_UV*/ +#define CYCLES_HASIMM (3ull << 2) +#define CYCLES_IMM8 (1ull << 2) +#define CYCLES_IMM1632 (2ull << 2) + +#define CYCLES_MASK ((1ull << 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) +#define PAIR_NP (0ull << 29) /*Instruction pairs in U pipe only*/ -#define PAIR_U (1 << 29) +#define PAIR_U (1ull << 29) /*Instruction pairs in V pipe only*/ -#define PAIR_V (2 << 29) +#define PAIR_V (2ull << 29) /*Instruction pairs in both U and V pipes*/ -#define PAIR_UV (3 << 29) +#define PAIR_UV (3ull << 29) /*Instruction pairs in U pipe only and only with FXCH*/ -#define PAIR_FX (5 << 29) +#define PAIR_FX (5ull << 29) /*Instruction is FXCH and only pairs in V pipe with FX pairable instruction*/ -#define PAIR_FXCH (6 << 29) +#define PAIR_FXCH (6ull << 29) -#define PAIR_MASK (7 << 29) +#define PAIR_FPU (4ull << 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) +#define PAIR_MASK (7ull << 29) -/*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) +/*comp_time = cycles until instruction complete + i_overlap = cycles that overlap with integer + f_overlap = cycles that overlap with subsequent FPU*/ +#define FPU_CYCLES(comp_time, i_overlap, f_overlap) ((uint64_t)comp_time) | ((uint64_t)i_overlap << 41) | ((uint64_t)f_overlap << 49) | PAIR_FPU + +#define FPU_COMP_TIME(timing) (timing & 0xff) +#define FPU_I_OVERLAP(timing) ((timing >> 41) & 0xff) +#define FPU_F_OVERLAP(timing) ((timing >> 49) & 0xff) + +#define FPU_I_LATENCY(timing) (FPU_COMP_TIME(timing) - FPU_I_OVERLAP(timing)) + +#define FPU_F_LATENCY(timing) (FPU_I_OVERLAP(timing) - FPU_F_OVERLAP(timing)) + +#define FPU_RESULT_LATENCY(timing) ((timing >> 41) & 0xff) + #define INVALID 0 static int u_pipe_full; static uint32_t u_pipe_opcode; -static uint32_t *u_pipe_timings; +static uint64_t *u_pipe_timings; static uint32_t u_pipe_op_32; static uint32_t u_pipe_regmask; +static uint32_t u_pipe_fetchdat; +static int u_pipe_decode_delay_offset; +static uint64_t *u_pipe_deps; -#define REGMASK_SHIFTPACK (1 << 8) -#define REGMASK_MULTIPLY (1 << 8) +static uint32_t regmask_modified; -static uint32_t get_srcdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +static uint32_t addr_regmask; + +static int fpu_latency; +static int fpu_st_latency[8]; + +static uint64_t opcode_timings[256] = { - 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; -} +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, -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, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), -/* 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), +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, 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), +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, 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, +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, -/* 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, +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* PUSHA POPA BOUND ARPL*/ /*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), @@ -225,13 +177,13 @@ static uint32_t opcode_timings[256] = 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), +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_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), @@ -243,19 +195,19 @@ static uint32_t opcode_timings[256] = 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, +/*a0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* 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), + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, 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, +/*b0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* RET imm RET*/ /*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), @@ -291,61 +243,61 @@ static uint32_t opcode_timings[256] = PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_RMW, INVALID }; -static uint32_t opcode_timings_mod3[256] = +static uint64_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, +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, 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), +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, 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), +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, 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), +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, 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, +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, -/* 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, +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* PUSHA POPA BOUND ARPL*/ /*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), @@ -361,13 +313,13 @@ static uint32_t opcode_timings_mod3[256] = 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), +/*80*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG, PAIR_NP | 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), @@ -379,19 +331,19 @@ static uint32_t opcode_timings_mod3[256] = 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, +/*a0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* 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), + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, 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, +/*b0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, /* RET imm RET*/ /*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), @@ -428,22 +380,22 @@ static uint32_t opcode_timings_mod3[256] = PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_REG, INVALID }; -static uint32_t opcode_timings_0f[256] = +static uint64_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, +/*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, +/*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, @@ -460,15 +412,15 @@ static uint32_t opcode_timings_0f[256] = 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, +/*60*/ PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | 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, +/*70*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | 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), @@ -495,22 +447,22 @@ static uint32_t opcode_timings_0f[256] = 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, +/*d0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | 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, +/*e0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | 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, +/*f0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | 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] = +static uint64_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, @@ -542,15 +494,15 @@ static uint32_t opcode_timings_0f_mod3[256] = 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, +/*60*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | 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, +/*70*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | 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), @@ -577,152 +529,153 @@ static uint32_t opcode_timings_0f_mod3[256] = 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, +/*d0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + INVALID, PAIR_UV | 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, +/*e0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, + INVALID, PAIR_UV | 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, +/*f0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + INVALID, PAIR_UV | 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] = +static uint64_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] = +static uint64_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, + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, }; -static uint32_t opcode_timings_f6[8] = +static uint64_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] = +static uint64_t opcode_timings_f6_mod3[8] = { /* TST NOT NEG*/ - PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_UV | CYCLES_REG, 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] = +static uint64_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) +/* 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] = +static uint64_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) +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG, 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] = +static uint64_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 uint64_t opcode_timings_ff_mod3[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), + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, 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] = +static uint64_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) +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_d8_mod3[8] = +static uint64_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) +/* FADD FMUL FCOM FCOMP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_d9[8] = +static uint64_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) +/* FLDs FSTs FSTPs*/ + PAIR_FX | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_NP | FPU_CYCLES(32,0,0), PAIR_NP | FPU_CYCLES(8,0,0), PAIR_NP | FPU_CYCLES(48,0,0), PAIR_NP | FPU_CYCLES(2,0,0) }; -static uint32_t opcode_timings_d9_mod3[64] = +static uint64_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), + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), /*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), + PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), + PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), /*FNOP*/ - PAIR_NP | CYCLES(3), INVALID, INVALID, INVALID, - INVALID, INVALID, INVALID, INVALID, + PAIR_NP | FPU_CYCLES(3,0,0), 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) + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), +/* opFCHS opFABS*/ + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), INVALID, INVALID, +/* opFTST opFXAM*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(21,4,0), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(2,0,0), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_NP | FPU_CYCLES(53,2,2), PAIR_NP | FPU_CYCLES(103,2,2), PAIR_NP | FPU_CYCLES(120,36,0), PAIR_NP | FPU_CYCLES(112,2,2), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_NP | FPU_CYCLES(64,2,2), INVALID, PAIR_NP | FPU_CYCLES(70,69,2), PAIR_NP | FPU_CYCLES(89,2,2), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_NP | FPU_CYCLES(9,0,0), PAIR_NP | FPU_CYCLES(20,5,0), PAIR_NP | FPU_CYCLES(65,2,2), PAIR_NP | FPU_CYCLES(65,2,2) }; -static uint32_t opcode_timings_da[8] = +static uint64_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) +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(4,0,0), PAIR_NP | FPU_CYCLES(4,0,0), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(42,38,2), PAIR_NP | FPU_CYCLES(42,38,2) }; -static uint32_t opcode_timings_da_mod3[8] = +static uint64_t opcode_timings_da_mod3[8] = { - INVALID, INVALID, INVALID, INVALID, - INVALID, PAIR_NP | CYCLES(5), INVALID, INVALID + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID }; -static uint32_t opcode_timings_db[8] = +static uint64_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) +/* FLDil FSTil FSTPil*/ + PAIR_NP | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_CYCLES(6,0,0), PAIR_NP | FPU_CYCLES(6,0,0), +/* FLDe FSTPe*/ + INVALID, PAIR_NP | FPU_CYCLES(3,0,0), INVALID, PAIR_NP | FPU_CYCLES(3,0,0) }; -static uint32_t opcode_timings_db_mod3[64] = +static uint64_t opcode_timings_db_mod3[64] = { INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, @@ -736,10 +689,10 @@ static uint32_t opcode_timings_db_mod3[64] = 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, +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(7,0,0), PAIR_NP | FPU_CYCLES(17,0,0), +/* opFNOP opFNOP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, @@ -751,87 +704,109 @@ static uint32_t opcode_timings_db_mod3[64] = INVALID, INVALID, INVALID, INVALID, }; -static uint32_t opcode_timings_dc[8] = +static uint64_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) +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_dc_mod3[8] = +static uint64_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) +/* opFADDr opFMULr*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_dd[8] = +static uint64_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) +/* FLDd FSTd FSTPd*/ + PAIR_FX | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* FRSTOR FSAVE FSTSW*/ + PAIR_NP | FPU_CYCLES(70,0,0), INVALID, PAIR_NP | FPU_CYCLES(127,0,0), PAIR_NP | FPU_CYCLES(6,0,0) }; -static uint32_t opcode_timings_dd_mod3[8] = +static uint64_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 +/* FFFREE FST FSTP*/ + PAIR_NP | FPU_CYCLES(2,0,0), INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), +/* FUCOM FUCOMP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID }; -static uint32_t opcode_timings_de[8] = +static uint64_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) +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(4,0,0), PAIR_NP | FPU_CYCLES(4,0,0), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(42,38,2), PAIR_NP | FPU_CYCLES(42,38,2) }; -static uint32_t opcode_timings_de_mod3[8] = +static uint64_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) +/* FADDP FMULP FCOMPP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), INVALID, PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBP FSUBRP FDIVP FDIVRP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) }; -static uint32_t opcode_timings_df[8] = +static uint64_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) +/* FILDiw FISTiw FISTPiw*/ + PAIR_NP | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_CYCLES(6,0,0), PAIR_NP | FPU_CYCLES(6,0,0), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_NP | FPU_CYCLES(3,2,2), PAIR_NP | FPU_CYCLES(148,0,0), PAIR_NP | FPU_CYCLES(6,0,0) }; -static uint32_t opcode_timings_df_mod3[8] = +static uint64_t opcode_timings_df_mod3[8] = { - INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, /* FSTSW AX*/ - PAIR_NP | CYCLES(2), INVALID, INVALID, INVALID + PAIR_NP | FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID }; -static uint32_t opcode_timings_8x[8] = +static uint64_t opcode_timings_81[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 + PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, + PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RM | CYCLES_IMM1632 +}; +static uint64_t opcode_timings_81_mod3[8] = +{ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG +}; +static uint64_t opcode_timings_8x[8] = +{ + PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, + PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RM | CYCLES_IMM8 +}; +static uint64_t opcode_timings_8x_mod3[8] = +{ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG }; -static int decode_delay; +static int decode_delay, decode_delay_offset; static uint8_t last_prefix; +static int prefixes; -static inline int COUNT(uint32_t c, int op_32) +static inline int COUNT(uint64_t timings, uint64_t deps, int op_32) { - if (c & CYCLES_HAS_MULTI) + if ((timings & PAIR_FPU) && !(deps & FPU_FXCH)) + return FPU_I_LATENCY(timings); + if (timings & CYCLES_HAS_MULTI) { if (op_32 & 0x100) - return ((uintptr_t)c >> 8) & 0xff; - return (uintptr_t)c & 0xff; + return ((uintptr_t)timings >> 8) & 0xff; + return (uintptr_t)timings & 0xff; } - if (!(c & PAIR_MASK)) - return c & 0xffff; - if ((c & PAIR_MASK) == PAIR_FX) - return c & 0xffff; - switch (c & CYCLES_MASK) + if (!(timings & PAIR_MASK)) + return timings & 0xffff; + if ((timings & PAIR_MASK) == PAIR_FX) + return timings & 0xffff; + if ((timings & PAIR_MASK) == PAIR_FXCH) + return timings & 0xffff; + if ((timings & PAIR_UV) && !(timings & PAIR_FPU)) + timings &= 3; + switch (timings & CYCLES_MASK) { case CYCLES_REG: return 1; @@ -840,41 +815,154 @@ static inline int COUNT(uint32_t c, int op_32) case CYCLES_RMW: return 3; case CYCLES_BRANCH: - return cpu_hasMMX ? 1 : 2; + return cpu_has_feature(CPU_FEATURE_MMX) ? 1 : 2; } - fatal("Illegal COUNT %08x\n", c); + fatal("Illegal COUNT %016llx\n", timings); - return c; + return timings; +} + +static int codegen_fpu_latencies(uint64_t deps, int reg) +{ + int latency = fpu_latency; + + if ((deps & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency) + latency = fpu_st_latency[0]; + if ((deps & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency) + latency = fpu_st_latency[1]; + if ((deps & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency) + latency = fpu_st_latency[reg]; + + return latency; +} + +#define SUB_AND_CLAMP(latency, count) \ + latency -= count; \ + if (latency < 0) \ + latency = 0 + +static void codegen_fpu_latency_clock(int count) +{ + SUB_AND_CLAMP(fpu_latency, count); + SUB_AND_CLAMP(fpu_st_latency[0], count); + SUB_AND_CLAMP(fpu_st_latency[1], count); + SUB_AND_CLAMP(fpu_st_latency[2], count); + SUB_AND_CLAMP(fpu_st_latency[3], count); + SUB_AND_CLAMP(fpu_st_latency[4], count); + SUB_AND_CLAMP(fpu_st_latency[5], count); + SUB_AND_CLAMP(fpu_st_latency[6], count); + SUB_AND_CLAMP(fpu_st_latency[7], count); +} + +static inline int codegen_timing_has_displacement(uint32_t fetchdat, int op_32) +{ + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /*Has SIB*/ + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0x700) == 0x500) + return 1; + } + else + { + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0xc7) == 0x05) + return 1; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0xc7) == 0x06) + return 1; + } + return 0; +} + +/*The instruction is only of interest here if it's longer than 7 bytes, as that's the + limit on Pentium MMX parallel decoding*/ +static inline int codegen_timing_instr_length(uint64_t timing, uint32_t fetchdat, int op_32) +{ + int len = prefixes; + if ((timing & CYCLES_MASK) == CYCLES_RM || (timing & CYCLES_MASK) == CYCLES_RMW) + { + len += 2; /*Opcode + ModR/M*/ + if ((timing & CYCLES_HASIMM) == CYCLES_IMM8) + len++; + if ((timing & CYCLES_HASIMM) == CYCLES_IMM1632) + len += (op_32 & 0x100) ? 4 : 2; + + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /* Has SIB*/ + len++; + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0x700) == 0x500) + len += 4; + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0xc7) == 0x05) + len += 4; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 2; + else if ((fetchdat & 0xc7) == 0x06) + len += 2; + } + } + + return len; } void codegen_timing_pentium_block_start() { - u_pipe_full = decode_delay = 0; + u_pipe_full = decode_delay = decode_delay_offset = 0; } void codegen_timing_pentium_start() { // decode_delay = 0; last_prefix = 0; + prefixes = 0; } void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) { - if (cpu_hasMMX && prefix == 0x0f) + prefixes++; + if ((prefix & 0xf8) == 0xd8) + { + last_prefix = prefix; + return; + } + if (cpu_has_feature(CPU_FEATURE_MMX) && prefix == 0x0f) { /*On Pentium MMX 0fh prefix is 'free'*/ last_prefix = prefix; return; } - if (cpu_hasMMX && (prefix == 0x66 || prefix == 0x67)) + if (cpu_has_feature(CPU_FEATURE_MMX) && (prefix == 0x66 || prefix == 0x67)) { /*On Pentium MMX 66h and 67h prefixes take 2 clocks*/ - decode_delay += 2; + decode_delay_offset += 2; last_prefix = prefix; return; } - if (prefix == 0x0f && (opcode & 0xf0) == 0x80) + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) { /*On Pentium 0fh prefix is 'free' when used on conditional jumps*/ last_prefix = prefix; @@ -882,60 +970,172 @@ void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) } /*On Pentium all prefixes take 1 cycle to decode. Decode may be shadowed by execution of previous instructions*/ - decode_delay++; + decode_delay_offset++; last_prefix = prefix; } -void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) { - uint32_t *timings; + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + /*Instructions that use ESP implicitly (eg PUSH, POP, CALL etc) do not + cause AGIs with each other, but do with instructions that use it explicitly*/ + if ((addr_regmask & REGMASK_IMPL_ESP) && (regmask_modified & (1 << REG_ESP)) && !(regmask_modified & REGMASK_IMPL_ESP)) + addr_regmask |= (1 << REG_ESP); + + return (regmask_modified & addr_regmask) & ~REGMASK_IMPL_ESP; +} + +static void codegen_instruction(uint64_t *timings, uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int decode_delay_offset, int op_32, int exec_delay) +{ + int instr_cycles, latency = 0; + + if ((timings[opcode] & PAIR_FPU) && !(deps[opcode] & FPU_FXCH)) + instr_cycles = latency = codegen_fpu_latencies(deps[opcode], fetchdat & 7); + else + { +/* if (timings[opcode] & FPU_WRITE_ST0) + fatal("FPU_WRITE_ST0\n"); + if (timings[opcode] & FPU_WRITE_ST1) + fatal("FPU_WRITE_ST1\n"); + if (timings[opcode] & FPU_WRITE_STREG) + fatal("FPU_WRITE_STREG\n");*/ + instr_cycles = 0; + } + + if ((decode_delay + decode_delay_offset) > 0) + codegen_fpu_latency_clock(decode_delay + decode_delay_offset + instr_cycles); + else + codegen_fpu_latency_clock(instr_cycles); + instr_cycles += COUNT(timings[opcode], deps[opcode], op_32); + instr_cycles += exec_delay; + if ((decode_delay + decode_delay_offset) > 0) + codegen_block_cycles += instr_cycles + decode_delay + decode_delay_offset; + else + codegen_block_cycles += instr_cycles; + + decode_delay = (-instr_cycles) + 1; + + if (deps[opcode] & FPU_POP) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c] = fpu_st_latency[c+1]; + fpu_st_latency[7] = 0; + } + if (deps[opcode] & FPU_POP2) + { + int c; + + for (c = 0; c < 6; c++) + fpu_st_latency[c] = fpu_st_latency[c+2]; + fpu_st_latency[6] = fpu_st_latency[7] = 0; + } + if ((timings[opcode] & PAIR_FPU) && !(deps[opcode] & FPU_FXCH)) + { + /* if (fpu_latency) + fatal("Bad latency FPU\n");*/ + fpu_latency = FPU_F_LATENCY(timings[opcode]); + } + + if (deps[opcode] & FPU_PUSH) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c+1] = fpu_st_latency[c]; + fpu_st_latency[0] = 0; + } + if (deps[opcode] & FPU_WRITE_ST0) + { +/* if (fpu_st_latency[0]) + fatal("Bad latency ST0\n");*/ + fpu_st_latency[0] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_ST1) + { +/* if (fpu_st_latency[1]) + fatal("Bad latency ST1\n");*/ + fpu_st_latency[1] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps[opcode] & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps[opcode] & FPU_WRITE_ST0)) && + !(reg == 1 && (deps[opcode] & FPU_WRITE_ST1))) + { +/* if (fpu_st_latency[reg]) + fatal("Bad latency STREG %i %08x %i %016llx %02x\n",fpu_st_latency[reg], fetchdat, reg, timings[opcode], opcode);*/ + fpu_st_latency[reg] = FPU_RESULT_LATENCY(timings[opcode]); + } + } +} + +void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + uint64_t *timings; + uint64_t *deps; int mod3 = ((fetchdat & 0xc0) == 0xc0); int bit8 = !(opcode & 1); + int agi_stall = 0; switch (last_prefix) { case 0x0f: timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; // pclog("timings 0f\n"); break; case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_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; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; // pclog("timings d9\n"); + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; break; case 0xda: timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; opcode = (opcode >> 3) & 7; // pclog("timings da\n"); break; case 0xdb: timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; // pclog("timings db\n"); break; case 0xdc: timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; opcode = (opcode >> 3) & 7; // pclog("timings dc\n"); break; case 0xdd: timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; opcode = (opcode >> 3) & 7; // pclog("timings dd\n"); break; case 0xde: timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; opcode = (opcode >> 3) & 7; // pclog("timings de\n"); break; case 0xdf: timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; opcode = (opcode >> 3) & 7; // pclog("timings df\n"); break; @@ -943,49 +1143,64 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) 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; + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + 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: + case 0xc0: case 0xc1: case 0xd0: case 0xd1: timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; // pclog("timings c0\n"); break; + case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_cl_mod3 : opcode_deps_shift_cl; + opcode = (fetchdat >> 3) & 7; +// pclog("timings d2\n"); + break; + case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; opcode = (fetchdat >> 3) & 7; // pclog("timings f6\n"); break; case 0xf7: timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; opcode = (fetchdat >> 3) & 7; // pclog("timings f7\n"); break; case 0xff: timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; opcode = (fetchdat >> 3) & 7; // pclog("timings ff\n"); break; default: timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; // 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); - + uint8_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, u_pipe_op_32); + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && (timings[opcode] & PAIR_MASK) != PAIR_FXCH) goto nopair; @@ -993,52 +1208,112 @@ void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) 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*/ + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && + (timings[opcode] & PAIR_MASK) == PAIR_FXCH) + { + int temp; + + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + + temp = fpu_st_latency[fetchdat & 7]; + fpu_st_latency[fetchdat & 7] = fpu_st_latency[0]; + fpu_st_latency[0] = temp; + u_pipe_full = 0; + decode_delay_offset = 0; + regmask_modified = u_pipe_regmask; + addr_regmask = 0; return; } + + if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && (decode_delay+decode_delay_offset+u_pipe_decode_delay_offset) <= 0) + { + int has_displacement; + + if (timings[opcode] & CYCLES_HASIMM) + has_displacement = codegen_timing_has_displacement(fetchdat, op_32); + else + has_displacement = 0; + + if (!has_displacement && (!cpu_has_feature(CPU_FEATURE_MMX) || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + { + int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; + int t2 = timings[opcode] & CYCLES_MASK; + int t_pair; + uint64_t temp_timing; + uint64_t temp_deps = 0; + + if (!(u_pipe_timings[u_pipe_opcode] & PAIR_FPU)) + t1 &= 3; + if (!(timings[opcode] & PAIR_FPU)) + t2 &= 3; + + 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); + + /*Instruction can pair with previous*/ + temp_timing = t_pair; + if (check_agi(deps, opcode, fetchdat, op_32) || check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(&temp_timing, &temp_deps, 0, 0, 0, 0, agi_stall); + u_pipe_full = 0; + decode_delay_offset = 0; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | u_pipe_regmask; + addr_regmask = 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; + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); 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); + regmask_modified = u_pipe_regmask; + addr_regmask = 0; } - if ((timings[opcode] & PAIR_U) && !decode_delay) + if ((timings[opcode] & PAIR_U) && (decode_delay + decode_delay_offset) <= 0) { - /*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; + int has_displacement; + + if (timings[opcode] & CYCLES_HASIMM) + has_displacement = codegen_timing_has_displacement(fetchdat, op_32); + else + has_displacement = 0; + + if ((!has_displacement || cpu_has_feature(CPU_FEATURE_MMX)) && (!cpu_has_feature(CPU_FEATURE_MMX) || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + { + /*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(deps[opcode], fetchdat, bit8); + u_pipe_fetchdat = fetchdat; + u_pipe_decode_delay_offset = decode_delay_offset; + u_pipe_deps = deps; + decode_delay_offset = 0; + 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); + if (check_agi(deps, opcode, fetchdat, op_32)) + agi_stall = 1; + codegen_instruction(timings, deps, opcode, fetchdat, decode_delay_offset, op_32, agi_stall); + decode_delay_offset = 0; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); + addr_regmask = 0; } void codegen_timing_pentium_block_end() @@ -1046,16 +1321,24 @@ 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; + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + codegen_block_cycles++; + codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_deps[u_pipe_opcode], u_pipe_op_32) + decode_delay + decode_delay_offset; u_pipe_full = 0; } } +int codegen_timing_pentium_jump_cycles() +{ + return 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 + codegen_timing_pentium_block_end, + codegen_timing_pentium_jump_cycles }; diff --git a/src/codegen_timing_winchip.c b/src/codegen_timing_winchip.c index 160650e..c23b30b 100644 --- a/src/codegen_timing_winchip.c +++ b/src/codegen_timing_winchip.c @@ -5,6 +5,8 @@ #include "x87.h" #include "mem.h" #include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" #define CYCLES(c) (int *)c #define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) @@ -72,7 +74,7 @@ static int *opcode_timings_0f[256] = /*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), +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, CYCLES(3), 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, @@ -94,7 +96,7 @@ static int *opcode_timings_0f_mod3[256] = /*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), +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, CYCLES(3), 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, @@ -247,9 +249,22 @@ static int *opcode_timings_8x[8] = { &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm }; +static int *opcode_timings_8x_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81_mod3[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 uint32_t regmask_modified; static inline int COUNT(int *c, int op_32) { @@ -266,6 +281,7 @@ static inline int COUNT(int *c, int op_32) void codegen_timing_winchip_block_start() { + regmask_modified = 0; } void codegen_timing_winchip_start() @@ -280,96 +296,143 @@ void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat) last_prefix = prefix; } -void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) { int **timings; + uint64_t *deps; int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); switch (last_prefix) { case 0x0f: timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; +// pclog("timings 0f\n"); break; case 0xd8: timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); break; case 0xd9: timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); break; case 0xda: timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); break; case 0xdb: timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); break; case 0xdc: timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); break; case 0xdd: timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); break; case 0xde: timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); break; case 0xdf: timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_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; + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + 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; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; opcode = (fetchdat >> 3) & 7; +// pclog("timings c0\n"); break; case 0xf6: timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); break; case 0xf7: timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); break; case 0xff: timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); break; default: timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; +// pclog("timings normal\n"); break; } } timing_count += COUNT(timings[opcode], op_32); + if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32)) + timing_count++; /*AGI stall*/ codegen_block_cycles += timing_count; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); } void codegen_timing_winchip_block_end() { } +int codegen_timing_winchip_jump_cycles() +{ + return 0; +} + 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 + codegen_timing_winchip_block_end, + codegen_timing_winchip_jump_cycles }; diff --git a/src/codegen_timing_winchip2.c b/src/codegen_timing_winchip2.c new file mode 100644 index 0000000..c85a0e9 --- /dev/null +++ b/src/codegen_timing_winchip2.c @@ -0,0 +1,759 @@ +/*Since IDT/Centaur didn't document cycle timings in the WinChip datasheets, and + I don't currently own a WinChip 2 to test against, most of the timing here is + a guess. This code makes the current (probably wrong) assumptions : + - FPU uses same timings as a Pentium, except for FXCH (which doesn't pair) + - 3DNow! instructions perfectly pair + - MMX follows mostly Pentium rules - one pipeline has shift/pack, one has + multiply, and other instructions can execute in either pipeline + - Instructions with prefixes can pair if both instructions are fully decoded + when the first instruction starts execution.*/ +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 31) + +#define CYCLES_FPU (1 << 30) + +#define CYCLES_IS_MMX_MUL (1 << 29) +#define CYCLES_IS_MMX_SHIFT (1 << 28) +#define CYCLES_IS_MMX_ANY (1 << 27) +#define CYCLES_IS_3DNOW (1 << 26) + +#define CYCLES_MMX_MUL(c) (CYCLES_IS_MMX_MUL | c) +#define CYCLES_MMX_SHIFT(c) (CYCLES_IS_MMX_SHIFT | c) +#define CYCLES_MMX_ANY(c) (CYCLES_IS_MMX_ANY | c) +#define CYCLES_3DNOW(c) (CYCLES_IS_3DNOW | c) + +#define CYCLES_IS_MMX (CYCLES_IS_MMX_MUL | CYCLES_IS_MMX_SHIFT | CYCLES_IS_MMX_ANY | CYCLES_IS_3DNOW) + +#define GET_CYCLES(c) (c & ~(CYCLES_HAS_MULTI | CYCLES_FPU | CYCLES_IS_MMX)) + +#define CYCLES(c) c +#define CYCLES2(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*comp_time = cycles until instruction complete + i_overlap = cycles that overlap with integer + f_overlap = cycles that overlap with subsequent FPU*/ +#define FPU_CYCLES(comp_time, i_overlap, f_overlap) (comp_time) | (i_overlap << 8) | (f_overlap << 16) | CYCLES_FPU + +#define FPU_COMP_TIME(timing) (timing & 0xff) +#define FPU_I_OVERLAP(timing) ((timing >> 8) & 0xff) +#define FPU_F_OVERLAP(timing) ((timing >> 16) & 0xff) + +#define FPU_I_LATENCY(timing) (FPU_COMP_TIME(timing) - FPU_I_OVERLAP(timing)) + +#define FPU_F_LATENCY(timing) (FPU_I_OVERLAP(timing) - FPU_F_OVERLAP(timing)) + +#define FPU_RESULT_LATENCY(timing) ((timing >> 8) & 0xff) + +#define INVALID 0 + +static uint32_t opcode_timings[256] = +{ +/*00*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(2), INVALID, +/*10*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), +/*20*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), +/*30*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), + +/*40*/ 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), +/*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(1), CYCLES(1), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ 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), + +/*80*/ CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), 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*/ 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), + +/*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), CYCLES(0), CYCLES(0), CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*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), INVALID, INVALID, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/*00*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), INVALID, +/*10*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(3), +/*20*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), +/*30*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), + +/*40*/ 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), +/*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(1), CYCLES(1), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ 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), + +/*80*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), 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*/ 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), + +/*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), CYCLES(0), CYCLES(0), CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*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), INVALID, INVALID, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), INVALID, +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), INVALID, CYCLES(195), CYCLES(7), INVALID, CYCLES(1000), CYCLES(10000), INVALID, INVALID, INVALID, CYCLES_3DNOW(1), CYCLES(1), CYCLES_3DNOW(1), +/*10*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*30*/ CYCLES(9), CYCLES(1), 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*/ CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), +/*70*/ INVALID, CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES(100), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), + +/*80*/ 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), +/*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), INVALID, INVALID, CYCLES(3), CYCLES(3), INVALID, CYCLES(13), CYCLES(3), CYCLES(3), INVALID, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), INVALID, INVALID, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ INVALID, CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), INVALID, CYCLES_MMX_MUL(2), INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), +/*e0*/ INVALID, CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), INVALID, INVALID, CYCLES_MMX_MUL(2), INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), +/*f0*/ INVALID, CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), CYCLES_MMX_SHIFT(2), INVALID, CYCLES_MMX_MUL(2), INVALID, INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), CYCLES_MMX_ANY(2), INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), INVALID, CYCLES(195), CYCLES(7), INVALID, CYCLES(1000), CYCLES(10000), INVALID, INVALID, INVALID, CYCLES_3DNOW(1), CYCLES(1), CYCLES_3DNOW(1), +/*10*/ INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, +/*30*/ CYCLES(9), CYCLES(1), 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*/ CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), +/*70*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES(100), INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), + +/*80*/ 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), +/*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), INVALID, INVALID, CYCLES(3), CYCLES(3), INVALID, CYCLES(13), CYCLES(3), CYCLES(3), INVALID, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), INVALID, INVALID, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), INVALID, INVALID, INVALID, INVALID, INVALID, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), +/*e0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), +/*f0*/ INVALID, CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), CYCLES_MMX_SHIFT(1), INVALID, CYCLES_MMX_MUL(1), INVALID, INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), CYCLES_MMX_ANY(1), INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static uint32_t opcode_timings_f6[8] = +{ + CYCLES(2), INVALID, CYCLES(2), CYCLES(2), CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ + CYCLES(1), INVALID, CYCLES(1), CYCLES(1), CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static uint32_t opcode_timings_f7[8] = +{ + CYCLES(2), INVALID, CYCLES(2), CYCLES(2), CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ + CYCLES(1), INVALID, CYCLES(1), CYCLES(1), CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static uint32_t opcode_timings_ff[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ + CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* FSUB FSUBR FDIV FDIVR*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + FPU_CYCLES(1,0,0), INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FLDENV FLDCW FSTENV FSTCW*/ + FPU_CYCLES(32,0,0), FPU_CYCLES(8,0,0), FPU_CYCLES(48,0,0), FPU_CYCLES(2,0,0) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + /*FXCH*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + /*FNOP*/ + FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* opFCHS opFABS*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), INVALID, INVALID, +/* opFTST opFXAM*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(21,4,0), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + FPU_CYCLES(2,0,0), FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + FPU_CYCLES(5,2,2), FPU_CYCLES(5,2,2), FPU_CYCLES(2,0,0), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + FPU_CYCLES(53,2,2), FPU_CYCLES(103,2,2),FPU_CYCLES(120,36,0),FPU_CYCLES(112,2,2), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* opFPREM opFSQRT opFSINCOS*/ + FPU_CYCLES(64,2,2), INVALID, FPU_CYCLES(70,69,2),FPU_CYCLES(89,2,2), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + FPU_CYCLES(9,0,0), FPU_CYCLES(20,5,0), FPU_CYCLES(65,2,2), FPU_CYCLES(65,2,2) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(4,0,0), FPU_CYCLES(4,0,0), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(42,38,2), FPU_CYCLES(42,38,2) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, FPU_CYCLES(1,0,0), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + FPU_CYCLES(3,2,2), INVALID, FPU_CYCLES(6,0,0), FPU_CYCLES(6,0,0), +/* FLDe FSTPe*/ + INVALID, FPU_CYCLES(3,0,0), INVALID, FPU_CYCLES(3,0,0) +}; +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, FPU_CYCLES(1,0,0), FPU_CYCLES(7,0,0), FPU_CYCLES(17,0,0), +/* opFNOP opFNOP*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), 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*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2),INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2),FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + FPU_CYCLES(1,0,0), INVALID, FPU_CYCLES(2,0,0), FPU_CYCLES(2,0,0), +/* FRSTOR FSAVE FSTSW*/ + FPU_CYCLES(70,0,0), INVALID, FPU_CYCLES(127,0,0), FPU_CYCLES(6,0,0) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + FPU_CYCLES(2,0,0), INVALID, FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0), +/* FUCOM FUCOMP*/ + FPU_CYCLES(1,0,0), FPU_CYCLES(1,0,0),INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(4,0,0), FPU_CYCLES(4,0,0), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + FPU_CYCLES(6,2,2), FPU_CYCLES(6,2,2), FPU_CYCLES(42,38,2), FPU_CYCLES(42,38,2) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), INVALID, FPU_CYCLES(1,0,0), +/* FSUBP FSUBRP FDIVP FDIVRP*/ + FPU_CYCLES(3,2,2), FPU_CYCLES(3,2,2), FPU_CYCLES(39,38,2), FPU_CYCLES(39,38,2) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + FPU_CYCLES(3,2,2), INVALID, FPU_CYCLES(6,0,0), FPU_CYCLES(6,0,0), +/* FILDiq FBSTP FISTPiq*/ + INVALID, FPU_CYCLES(3,2,2), FPU_CYCLES(148,0,0), FPU_CYCLES(6,0,0) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_8x_mod3[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_81[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; +static uint32_t opcode_timings_81_mod3[8] = +{ + CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(2) +}; + +static int timing_count; +static uint8_t last_prefix; +static uint32_t regmask_modified; +static int decode_delay, decode_delay_offset; +static int fpu_latency; +static int fpu_st_latency[8]; + +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; +static uint32_t u_pipe_fetchdat; +static int u_pipe_decode_delay_offset; +static uint64_t *u_pipe_deps; + +int can_pair(uint32_t timing_a, uint32_t timing_b, uint8_t regmask_b) +{ + /*Only MMX/3DNow instructions can pair*/ + if (!(timing_b & CYCLES_IS_MMX)) + return 0; + /*Only one MMX multiply per cycle*/ + if ((timing_a & CYCLES_IS_MMX_MUL) && (timing_b & CYCLES_IS_MMX_MUL)) + return 0; + /*Only one MMX shift/pack per cycle*/ + if ((timing_a & CYCLES_IS_MMX_SHIFT) && (timing_b & CYCLES_IS_MMX_SHIFT)) + return 0; + /*Second instruction can not access registers written by first*/ + if (u_pipe_regmask & regmask_b) + return 0; + /*Must have had enough time to decode prefixes*/ + if ((decode_delay+decode_delay_offset+u_pipe_decode_delay_offset) > 0) + return 0; + + return 1; +} + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_FPU) + return FPU_I_LATENCY(c); + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return (c >> 8) & 0xff; + return c & 0xff; + } + return GET_CYCLES(c); +} + +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + /*Instructions that use ESP implicitly (eg PUSH, POP, CALL etc) do not + cause AGIs with each other, but do with instructions that use it explicitly*/ + if ((addr_regmask & REGMASK_IMPL_ESP) && (regmask_modified & (1 << REG_ESP)) && !(regmask_modified & REGMASK_IMPL_ESP)) + addr_regmask |= (1 << REG_ESP); + + return (regmask_modified & addr_regmask) & ~REGMASK_IMPL_ESP; +} + +static int codegen_fpu_latencies(uint64_t deps, int reg) +{ + int latency = fpu_latency; + + if ((deps & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency) + latency = fpu_st_latency[0]; + if ((deps & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency) + latency = fpu_st_latency[1]; + if ((deps & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency) + latency = fpu_st_latency[reg]; + + return latency; +} + +#define SUB_AND_CLAMP(latency, count) \ + latency -= count; \ + if (latency < 0) \ + latency = 0 + +static void codegen_fpu_latency_clock(int count) +{ + SUB_AND_CLAMP(fpu_latency, count); + SUB_AND_CLAMP(fpu_st_latency[0], count); + SUB_AND_CLAMP(fpu_st_latency[1], count); + SUB_AND_CLAMP(fpu_st_latency[2], count); + SUB_AND_CLAMP(fpu_st_latency[3], count); + SUB_AND_CLAMP(fpu_st_latency[4], count); + SUB_AND_CLAMP(fpu_st_latency[5], count); + SUB_AND_CLAMP(fpu_st_latency[6], count); + SUB_AND_CLAMP(fpu_st_latency[7], count); +} + +static void codegen_instruction(uint32_t *timings, uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int decode_delay_offset, int op_32, int exec_delay) +{ + int instr_cycles, latency = 0; + + if ((timings[opcode] & CYCLES_FPU) && !(deps[opcode] & FPU_FXCH)) + instr_cycles = latency = codegen_fpu_latencies(deps[opcode], fetchdat & 7); + else + instr_cycles = 0; + + if ((decode_delay + decode_delay_offset) > 0) + codegen_fpu_latency_clock(decode_delay + decode_delay_offset + instr_cycles); + else + codegen_fpu_latency_clock(instr_cycles); + instr_cycles += COUNT(timings[opcode], op_32); + instr_cycles += exec_delay; + if ((decode_delay + decode_delay_offset) > 0) + codegen_block_cycles += instr_cycles + decode_delay + decode_delay_offset; + else + codegen_block_cycles += instr_cycles; + decode_delay = (-instr_cycles) + 1; + + if (deps[opcode] & FPU_POP) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c] = fpu_st_latency[c+1]; + fpu_st_latency[7] = 0; + } + if (deps[opcode] & FPU_POP2) + { + int c; + + for (c = 0; c < 6; c++) + fpu_st_latency[c] = fpu_st_latency[c+2]; + fpu_st_latency[6] = fpu_st_latency[7] = 0; + } + if (timings[opcode] & CYCLES_FPU) + { + /* if (fpu_latency) + fatal("Bad latency FPU\n");*/ + fpu_latency = FPU_F_LATENCY(timings[opcode]); + } + + if (deps[opcode] & FPU_PUSH) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c+1] = fpu_st_latency[c]; + fpu_st_latency[0] = 0; + } + if (deps[opcode] & FPU_WRITE_ST0) + { +/* if (fpu_st_latency[0]) + fatal("Bad latency ST0\n");*/ + fpu_st_latency[0] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_ST1) + { +/* if (fpu_st_latency[1]) + fatal("Bad latency ST1\n");*/ + fpu_st_latency[1] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps[opcode] & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps[opcode] & FPU_WRITE_ST0)) && + !(reg == 1 && (deps[opcode] & FPU_WRITE_ST1))) + { +/* if (fpu_st_latency[reg]) + fatal("Bad latency STREG %i %08x %i %016llx %02x\n",fpu_st_latency[reg], fetchdat, reg, timings[opcode], opcode);*/ + fpu_st_latency[reg] = FPU_RESULT_LATENCY(timings[opcode]); + } + } +} + +static void codegen_timing_winchip2_block_start() +{ + regmask_modified = 0; + decode_delay = decode_delay_offset = 0; + u_pipe_full = 0; +} + +static void codegen_timing_winchip2_start() +{ + timing_count = 0; + last_prefix = 0; +} + +static void codegen_timing_winchip2_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if (prefix == 0x0f) + { + /*0fh prefix is 'free'*/ + last_prefix = prefix; + return; + } + /*On WinChip all prefixes take 1 cycle to decode. Decode may be shadowed + by execution of previous instructions*/ + decode_delay_offset++; + last_prefix = prefix; +} + +static void codegen_timing_winchip2_opcode(uint8_t opcode, uint32_t fetchdat, int op_32, uint32_t op_pc) +{ + uint32_t *timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + int agi_stall = 0; + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; +// pclog("timings 0f\n"); + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; +// pclog("timings df\n"); + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + 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; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; +// pclog("timings c0\n"); + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; +// pclog("timings normal\n"); + break; + } + } + + if (u_pipe_full) + { + uint8_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, u_pipe_op_32); + + if (can_pair(u_pipe_timings[u_pipe_opcode], timings[opcode], regmask)) + { + int cycles_a = u_pipe_timings[u_pipe_opcode] & 0xff; + int cycles_b = timings[opcode] & 0xff; + uint32_t timing = (cycles_a > cycles_b) ? u_pipe_timings[u_pipe_opcode] : timings[opcode]; + uint64_t temp_deps = 0; + + if (check_agi(deps, opcode, fetchdat, op_32) || check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + + codegen_instruction(&timing, &temp_deps, 0, 0, 0, 0, agi_stall); + u_pipe_full = 0; + decode_delay_offset = 0; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | u_pipe_regmask; + return; + } + else + { + /*No pairing, run first instruction now*/ + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + u_pipe_full = 0; + regmask_modified = u_pipe_regmask; + } + } + if (timings[opcode] & CYCLES_IS_MMX) + { + /*Might pair with next instruction*/ + u_pipe_full = 1; + u_pipe_opcode = opcode; + u_pipe_timings = timings; + u_pipe_op_32 = op_32; + u_pipe_regmask = get_dstdep_mask(deps[opcode], fetchdat, bit8); + u_pipe_fetchdat = fetchdat; + u_pipe_decode_delay_offset = decode_delay_offset; + u_pipe_deps = deps; + decode_delay_offset = 0; + return; + } + + if (check_agi(deps, opcode, fetchdat, op_32)) + agi_stall = 1; + codegen_instruction(timings, deps, opcode, fetchdat, decode_delay_offset, op_32, agi_stall); + decode_delay_offset = 0; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); +} + +static void codegen_timing_winchip2_block_end() +{ + if (u_pipe_full) + { + int agi_stall = 0; + + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + u_pipe_full = 0; + } +} + +int codegen_timing_winchip2_jump_cycles() +{ + return 0; +} + +codegen_timing_t codegen_timing_winchip2 = +{ + codegen_timing_winchip2_start, + codegen_timing_winchip2_prefix, + codegen_timing_winchip2_opcode, + codegen_timing_winchip2_block_start, + codegen_timing_winchip2_block_end, + codegen_timing_winchip2_jump_cycles +}; diff --git a/src/codegen_x86-64.c b/src/codegen_x86-64.c index d421c7f..2c599f0 100644 --- a/src/codegen_x86-64.c +++ b/src/codegen_x86-64.c @@ -15,7 +15,7 @@ #include "codegen_ops.h" #include "codegen_ops_x86-64.h" -#ifdef __linux__ +#if defined(__linux__) || defined(__APPLE__) #include #include #endif @@ -23,7 +23,7 @@ #include #endif - +int codegen_flat_ds, codegen_flat_ss; int codegen_flags_changed = 0; int codegen_fpu_entered = 0; int codegen_fpu_loaded_iq[8]; @@ -61,7 +61,9 @@ static int last_ssegs; void codegen_init() { -#ifdef __linux__ + int c; + +#if defined(__linux__) || defined(__APPLE__) void *start; size_t len; long pagesize = sysconf(_SC_PAGESIZE); @@ -78,7 +80,10 @@ void codegen_init() memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); -#ifdef __linux__ + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].pc = BLOCK_PC_INVALID; + +#if defined(__linux__) || defined(__APPLE__) start = (void *)((long)codeblock & pagemask); len = ((BLOCK_SIZE * sizeof(codeblock_t)) + pagesize) & pagemask; if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) @@ -92,14 +97,19 @@ void codegen_init() void codegen_reset() { + int c; + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); mem_reset_page_blocks(); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].pc = BLOCK_PC_INVALID; } void dump_block() { - codeblock_t *block = pages[0x119000 >> 12].block; +/* codeblock_t *block = pages[0x119000 >> 12].block; pclog("dump_block:\n"); while (block) @@ -112,12 +122,12 @@ void dump_block() block = block->next; } - pclog("dump_block done\n"); + pclog("dump_block done\n");*/ } static void add_to_block_list(codeblock_t *block) { - codeblock_t *block_prev = pages[block->phys >> 12].block; + codeblock_t *block_prev = pages[block->phys >> 12].block[(block->phys >> 10) & 3]; if (!block->page_mask) fatal("add_to_block_list - mask = 0\n"); @@ -126,34 +136,34 @@ static void add_to_block_list(codeblock_t *block) { block->next = block_prev; block_prev->prev = block; - pages[block->phys >> 12].block = block; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; } else { block->next = NULL; - pages[block->phys >> 12].block = block; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; } if (block->next) { - if (!block->next->pc) - fatal("block->next->pc=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); + if (block->next->pc == BLOCK_PC_INVALID) + fatal("block->next->pc=BLOCK_PC_INVALID %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); } if (block->page_mask2) { - block_prev = pages[block->phys_2 >> 12].block_2; + block_prev = pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]; if (block_prev) { block->next_2 = block_prev; block_prev->prev_2 = block; - pages[block->phys_2 >> 12].block_2 = block; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; } else { block->next_2 = NULL; - pages[block->phys_2 >> 12].block_2 = block; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; } } } @@ -171,7 +181,7 @@ static void remove_from_block_list(codeblock_t *block, uint32_t pc) } else { - pages[block->phys >> 12].block = block->next; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block->next; if (block->next) block->next->prev = NULL; else @@ -193,7 +203,7 @@ static void remove_from_block_list(codeblock_t *block, uint32_t pc) 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; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block->next_2; if (block->next_2) block->next_2->prev_2 = NULL; else @@ -208,9 +218,9 @@ static void delete_block(codeblock_t *block) if (block == codeblock_hash[HASH(block->phys)]) codeblock_hash[HASH(block->phys)] = NULL; - if (!block->pc) + if (block->pc == BLOCK_PC_INVALID) fatal("Deleting deleted block\n"); - block->pc = 0; + block->pc = BLOCK_PC_INVALID; codeblock_tree_delete(block); remove_from_block_list(block, old_pc); @@ -218,7 +228,7 @@ static void delete_block(codeblock_t *block) void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) { - struct codeblock_t *block = page->block; + struct codeblock_t *block = page->block[(phys_addr >> 10) & 3]; while (block) { @@ -232,7 +242,7 @@ void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) block = block->next; } - block = page->block_2; + block = page->block_2[(phys_addr >> 10) & 3]; while (block) { @@ -252,7 +262,7 @@ void codegen_block_init(uint32_t phys_addr) codeblock_t *block; page_t *page = &pages[phys_addr >> 12]; - if (!page->block) + if (!page->block[(phys_addr >> 10) & 3]) mem_flush_write_page(phys_addr, cs+cpu_state.pc); block_current = (block_current + 1) & BLOCK_MASK; @@ -260,7 +270,7 @@ void codegen_block_init(uint32_t phys_addr) // if (block->pc == 0xb00b4ff5) // pclog("Init target block\n"); - if (block->pc != 0) + if (block->pc != BLOCK_PC_INVALID) { // pclog("Reuse block : was %08x now %08x\n", block->pc, cs+pc); delete_block(block); @@ -274,13 +284,14 @@ void codegen_block_init(uint32_t phys_addr) block->_cs = cs; block->pnt = block_current; block->phys = phys_addr; - block->use32 = use32; - block->stack32 = stack32; + block->dirty_mask = &page->dirty_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; + block->dirty_mask2 = NULL; block->next = block->prev = NULL; block->next_2 = block->prev_2 = NULL; block->page_mask = 0; block->flags = 0; - + block->status = cpu_cur_status; + block->was_recompiled = 0; recomp_page = block->phys & ~0xfff; @@ -292,7 +303,7 @@ void codegen_block_start_recompile(codeblock_t *block) { page_t *page = &pages[block->phys >> 12]; - if (!page->block) + if (!page->block[(block->phys >> 10) & 3]) mem_flush_write_page(block->phys, cs+cpu_state.pc); block_num = HASH(block->phys); @@ -301,6 +312,8 @@ void codegen_block_start_recompile(codeblock_t *block) if (block->pc != cs + cpu_state.pc || block->was_recompiled) fatal("Recompile to used block!\n"); + block->status = cpu_cur_status; + block_pos = BLOCK_GPF_OFFSET; #if WIN64 addbyte(0x48); /*XOR RCX, RCX*/ @@ -385,6 +398,9 @@ void codegen_block_start_recompile(codeblock_t *block) codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; block->was_recompiled = 1; + + codegen_flat_ds = !(cpu_cur_status & CPU_STATUS_NOTFLATDS); + codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); } void codegen_block_remove() @@ -400,17 +416,19 @@ void codegen_block_remove() void codegen_block_generate_end_mask() { codeblock_t *block = &codeblock[block_current]; - uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); - uint32_t end_pc = ((codegen_endpc + 3) & 0xffc) | (block->phys & ~0xfff); + uint32_t start_pc; + uint32_t end_pc; block->endpc = codegen_endpc; 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 = (block->pc & 0x3ff) & ~15; + if ((block->pc ^ block->endpc) & ~0x3ff) + end_pc = 0x3ff & ~15; + else + end_pc = (block->endpc & 0x3ff) & ~15; + if (end_pc < start_pc) + end_pc = 0x3ff; start_pc >>= PAGE_MASK_SHIFT; end_pc >>= PAGE_MASK_SHIFT; @@ -421,34 +439,37 @@ void codegen_block_generate_end_mask() // pclog(" %08x %llx\n", start_pc, block->page_mask); } - pages[block->phys >> 12].code_present_mask |= block->page_mask; + pages[block->phys >> 12].code_present_mask[(block->phys >> 10) & 3] |= block->page_mask; block->phys_2 = -1; block->page_mask2 = 0; block->next_2 = block->prev_2 = NULL; - if ((block->pc ^ block->endpc) & ~0xfff) + if ((block->pc ^ block->endpc) & ~0x3ff) { 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); + page_t *page_2 = &pages[block->phys_2 >> 12]; start_pc = 0; - end_pc = (block->endpc & 0xfff) >> PAGE_MASK_SHIFT; + end_pc = (block->endpc & 0x3ff) >> 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) + page_2->code_present_mask[(block->phys_2 >> 10) & 3] |= block->page_mask2; + + if (!pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]) 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); + if (block->next_2->pc == BLOCK_PC_INVALID) + fatal("block->next_2->pc=BLOCK_PC_INVALID %p\n", (void *)block->next_2); } + + block->dirty_mask2 = &page_2->dirty_mask[(block->phys_2 >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; } } @@ -1050,6 +1071,15 @@ void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t case 0xf0: /*LOCK*/ break; + case 0xf2: /*REPNE*/ + op_table = x86_dynarec_opcodes_REPNE; + recomp_op_table = recomp_opcodes_REPNE; + break; + case 0xf3: /*REPE*/ + op_table = x86_dynarec_opcodes_REPE; + recomp_op_table = recomp_opcodes_REPE; + break; + default: goto generate_call; } @@ -1101,6 +1131,13 @@ generate_call: } #endif } + + if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) + { + op_table = x86_dynarec_opcodes; + recomp_op_table = recomp_opcodes; + } + 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); diff --git a/src/codegen_x86.c b/src/codegen_x86.c deleted file mode 100644 index b9893ba..0000000 --- a/src/codegen_x86.c +++ /dev/null @@ -1,2152 +0,0 @@ -#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; - -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; - -static uint32_t mem_abrt_rout; -uint32_t mem_load_addr_ea_b; -uint32_t mem_load_addr_ea_w; -uint32_t mem_load_addr_ea_l; -uint32_t mem_load_addr_ea_q; -uint32_t mem_store_addr_ea_b; -uint32_t mem_store_addr_ea_w; -uint32_t mem_store_addr_ea_l; -uint32_t mem_store_addr_ea_q; -uint32_t mem_load_addr_ea_b_no_abrt; -uint32_t mem_store_addr_ea_b_no_abrt; -uint32_t mem_load_addr_ea_w_no_abrt; -uint32_t mem_store_addr_ea_w_no_abrt; -uint32_t mem_load_addr_ea_l_no_abrt; -uint32_t mem_store_addr_ea_l_no_abrt; -uint32_t mem_check_write; -uint32_t mem_check_write_w; -uint32_t mem_check_write_l; - -static uint32_t gen_MEM_LOAD_ADDR_EA_B() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - 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+1); - addbyte(0x0f); /*MOVZX EAX, B[EDX+EDI]*/ - addbyte(0xb6); - addbyte(0x04); - addbyte(0x3a); - addbyte(0xc3); /*RET*/ - - addbyte(0x50); /*slowpath: PUSH EAX*/ - addbyte(0x56); /*PUSH ESI*/ - addbyte(0xe8); /*CALL readmembl*/ - addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ - addbyte(0xc4); - addbyte(8); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*MOVZX EAX, AL*/ - addbyte(0xb6); - addbyte(0xc0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static uint32_t gen_MEM_LOAD_ADDR_EA_W() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - 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+1); - addbyte(0x83); /*CMP EDX, -1*/ - addbyte(0xfa); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(5+1); - addbyte(0x0f); /*MOVZX EAX, -1[EDX+EDI]W*/ - addbyte(0xb7); - addbyte(0x44); - addbyte(0x3a); - addbyte(-1); - addbyte(0xc3); /*RET*/ - - addbyte(0x50); /*slowpath: PUSH EAX*/ - addbyte(0x56); /*PUSH ESI*/ - addbyte(0xe8); /*CALL readmemwl*/ - addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ - addbyte(0xc4); - addbyte(8); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*MOVZX EAX, AX*/ - addbyte(0xb7); - addbyte(0xc0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static uint32_t gen_MEM_LOAD_ADDR_EA_L() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - 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+1); - addbyte(0x83); /*CMP EDX, -1*/ - addbyte(0xfa); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(4+1); - addbyte(0x8b); /*MOV EAX, -3[EDX+EDI]*/ - addbyte(0x44); - addbyte(0x3a); - addbyte(-3); - addbyte(0xc3); /*RET*/ - - addbyte(0x50); /*slowpath: PUSH EAX*/ - addbyte(0x56); /*PUSH ESI*/ - addbyte(0xe8); /*CALL readmemll*/ - addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ - addbyte(0xc4); - addbyte(8); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static uint32_t gen_MEM_LOAD_ADDR_EA_Q() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - 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+1); - addbyte(0x83); /*CMP EDX, -1*/ - addbyte(0xfa); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(4+4+1); - 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(0xc3); /*RET*/ - - addbyte(0x50); /*slowpath: PUSH EAX*/ - addbyte(0x56); /*PUSH ESI*/ - addbyte(0xe8); /*CALL readmemql*/ - addlong((uint32_t)readmemql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ - addbyte(0xc4); - addbyte(8); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static uint32_t gen_MEM_STORE_ADDR_EA_B() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*dat = ECX, seg = ESI, addr = EAX*/ - addbyte(0x89); /*MOV EBX, ESI*/ - addbyte(0xf3); - 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+1); - addbyte(0x88); /*MOV [EDI+ESI],CL*/ - addbyte(0x04 | (REG_ECX << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(0xc3); /*RET*/ - - addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ - addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememb386l*/ - addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ - addbyte(0xc4); - addbyte(12); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static uint32_t gen_MEM_STORE_ADDR_EA_W() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*dat = ECX, seg = ESI, addr = EAX*/ - addbyte(0x89); /*MOV EBX, ESI*/ - addbyte(0xf3); - 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+1); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(5+1); - addbyte(0x66); /*MOV -1[EDI+ESI],CX*/ - addbyte(0x89); - addbyte(0x44 | (REG_CX << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); - addbyte(0xc3); /*RET*/ - - addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ - addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememwl*/ - addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ - addbyte(0xc4); - addbyte(12); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static uint32_t gen_MEM_STORE_ADDR_EA_L() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*dat = ECX, seg = ESI, addr = EAX*/ - addbyte(0x89); /*MOV EBX, ESI*/ - addbyte(0xf3); - 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+1); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(4+1); - addbyte(0x89); /*MOV -3[EDI+ESI],ECX*/ - addbyte(0x44 | (REG_ECX << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); - addbyte(0xc3); /*RET*/ - - addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ - addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememll*/ - addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ - addbyte(0xc4); - addbyte(12); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static uint32_t gen_MEM_STORE_ADDR_EA_Q() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*dat = EBX/ECX, seg = ESI, addr = EAX*/ - addbyte(0x89); /*MOV EDX, ESI*/ - addbyte(0xf2); - 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+1); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(4+4+1); - addbyte(0x89); /*MOV -7[EDI+ESI],EBX*/ - addbyte(0x44 | (REG_EBX << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-7); - addbyte(0x89); /*MOV -7[EDI+ESI],EBX*/ - addbyte(0x44 | (REG_ECX << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-7+4); - addbyte(0xc3); /*RET*/ - - addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x53); /*PUSH EBX*/ - addbyte(0x50); /*PUSH EAX*/ - addbyte(0x52); /*PUSH EDX*/ - addbyte(0xe8); /*CALL writememql*/ - addlong((uint32_t)writememql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 16*/ - addbyte(0xc4); - addbyte(16); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static char gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_B_NO_ABRT aborted\n"; -static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - 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+1); - addbyte(0x0f); /*MOVZX ECX, B[EDX+EDI]*/ - addbyte(0xb6); - addbyte(0x0c); - addbyte(0x3a); - addbyte(0xc3); /*RET*/ - - addbyte(0x50); /*slowpath: PUSH EAX*/ - addbyte(0x56); /*PUSH ESI*/ - addbyte(0xe8); /*CALL readmembl*/ - addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ - addbyte(0xc4); - addbyte(8); -#ifndef RELEASE_BUILD - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); -#endif - addbyte(0x0f); /*MOVZX ECX, AL*/ - addbyte(0xb6); - addbyte(0xc8); -#ifndef RELEASE_BUILD - addbyte(0x75); /*JNE mem_abrt_rout*/ - addbyte(1); -#endif - addbyte(0xc3); /*RET*/ -#ifndef RELEASE_BUILD - addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err*/ - addbyte(0x04); - addbyte(0x24); - addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err); - addbyte(0xe8); /*CALL fatal*/ - addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - /*Should not return!*/ -#endif - return addr; -} - -static char gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_W_NO_ABRT aborted\n"; -static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - 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+1); - addbyte(0x83); /*CMP EDX, -1*/ - addbyte(0xfa); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(5+1); - addbyte(0x0f); /*MOVZX EEX, -1[EDX+EDI]W*/ - addbyte(0xb7); - addbyte(0x4c); - addbyte(0x3a); - addbyte(-1); - addbyte(0xc3); /*RET*/ - - addbyte(0x50); /*slowpath: PUSH EAX*/ - addbyte(0x56); /*PUSH ESI*/ - addbyte(0xe8); /*CALL readmemwl*/ - addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ - addbyte(0xc4); - addbyte(8); -#ifndef RELEASE_BUILD - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); -#endif - addbyte(0x0f); /*MOVZX ECX, AX*/ - addbyte(0xb7); - addbyte(0xc8); -#ifndef RELEASE_BUILD - addbyte(0x75); /*JNE mem_abrt_rout*/ - addbyte(1); -#endif - addbyte(0xc3); /*RET*/ -#ifndef RELEASE_BUILD - addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err*/ - addbyte(0x04); - addbyte(0x24); - addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err); - addbyte(0xe8); /*CALL fatal*/ - addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - /*Should not return!*/ -#endif - return addr; -} - -static char gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_L_NO_ABRT aborted\n"; -static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - 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+1); - addbyte(0x83); /*CMP EDX, -1*/ - addbyte(0xfa); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(4+1); - addbyte(0x8b); /*MOV ECX, -3[EDX+EDI]*/ - addbyte(0x4c); - addbyte(0x3a); - addbyte(-3); - addbyte(0xc3); /*RET*/ - - addbyte(0x50); /*slowpath: PUSH EAX*/ - addbyte(0x56); /*PUSH ESI*/ - addbyte(0xe8); /*CALL readmemll*/ - addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ - addbyte(0xc4); - addbyte(8); - addbyte(0x89); /*MOV ECX, EAX*/ - addbyte(0xc1); -#ifndef RELEASE_BUILD - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x75); /*JNE mem_abrt_rout*/ - addbyte(1); -#endif - addbyte(0xc3); /*RET*/ -#ifndef RELEASE_BUILD - addbyte(0x83); /*SUBL 4,%esp*/ - addbyte(0xEC); - addbyte(4); - addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err*/ - addbyte(0x04); - addbyte(0x24); - addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err); - addbyte(0xe8); /*CALL fatal*/ - addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - /*Should not return!*/ -#endif - return addr; -} - -static char gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_B_NO_ABRT aborted\n"; -static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*dat = ECX, seg = ESI, addr = EAX*/ - addbyte(0x89); /*MOV EBX, ESI*/ - addbyte(0xf3); - 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+1); - addbyte(0x88); /*MOV [EDI+ESI],CL*/ - addbyte(0x04 | (REG_ECX << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(0xc3); /*RET*/ - - addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ - addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememb386l*/ - addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ - addbyte(0xc4); - addbyte(12); -#ifndef RELEASE_BUILD - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x75); /*JNE mem_abrt_rout*/ - addbyte(1); -#endif - addbyte(0xc3); /*RET*/ -#ifndef RELEASE_BUILD - addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err*/ - addbyte(0x04); - addbyte(0x24); - addlong((uint32_t)gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err); - addbyte(0xe8); /*CALL fatal*/ - addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - /*Should not return!*/ -#endif - return addr; -} - -static char gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_W_NO_ABRT aborted\n"; -static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*dat = ECX, seg = ESI, addr = EAX*/ - addbyte(0x89); /*MOV EBX, ESI*/ - addbyte(0xf3); - 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+1); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(5+1); - addbyte(0x66); /*MOV -1[EDI+ESI],CX*/ - addbyte(0x89); - addbyte(0x44 | (REG_CX << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-1); - addbyte(0xc3); /*RET*/ - - addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ - addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememwl*/ - addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ - addbyte(0xc4); - addbyte(12); -#ifndef RELEASE_BUILD - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x75); /*JNE mem_abrt_rout*/ - addbyte(1); -#endif - addbyte(0xc3); /*RET*/ -#ifndef RELEASE_BUILD - addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err*/ - addbyte(0x04); - addbyte(0x24); - addlong((uint32_t)gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err); - addbyte(0xe8); /*CALL fatal*/ - addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - /*Should not return!*/ -#endif - return addr; -} - -static char gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_L_NO_ABRT aborted\n"; -static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*dat = ECX, seg = ESI, addr = EAX*/ - addbyte(0x89); /*MOV EBX, ESI*/ - addbyte(0xf3); - 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+1); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xf8 | REG_ESI); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(4+1); - addbyte(0x89); /*MOV -3[EDI+ESI],ECX*/ - addbyte(0x44 | (REG_ECX << 3)); - addbyte(REG_EDI | (REG_ESI << 3)); - addbyte(-3); - addbyte(0xc3); /*RET*/ - - addbyte(0x51); /*slowpath: PUSH ECX*/ - addbyte(0x50); /*PUSH EAX*/ - addbyte(0x53); /*PUSH EBX*/ - addbyte(0xe8); /*CALL writememll*/ - addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 12*/ - addbyte(0xc4); - addbyte(12); -#ifndef RELEASE_BUILD - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x75); /*JNE mem_abrt_rout*/ - addbyte(1); -#endif - addbyte(0xc3); /*RET*/ -#ifndef RELEASE_BUILD - addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err*/ - addbyte(0x04); - addbyte(0x24); - addlong((uint32_t)gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err); - addbyte(0xe8); /*CALL fatal*/ - addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - /*Should not return!*/ -#endif - return addr; -} - -static uint32_t gen_MEM_CHECK_WRITE() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*seg = ESI, addr = EAX*/ - - addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ - addbyte(0x3c); - addbyte(0x30); - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3d); - addlong((uint32_t)&cr0); - addbyte(0); - addbyte(0x78); /*JS +*/ - addbyte(1); - addbyte(0xc3); /*RET*/ - addbyte(0xc1); /*SHR EDI, 12*/ - addbyte(0xef); - addbyte(12); - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); - addbyte(0x74); /*JE slowpath*/ - addbyte(11); - addbyte(0x83); /*CMP writelookup2[EDI*4],-1*/ - addbyte(0x3c); - addbyte(0xbd); - addlong((uint32_t)writelookup2); - addbyte(-1); - addbyte(0x74); /*JE +*/ - addbyte(1); - addbyte(0xc3); /*RET*/ - - /*slowpath:*/ - addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ - addbyte(0x3c); - addbyte(0x30); - addbyte(0x6a); /*PUSH 1*/ - addbyte(1); - addbyte(0x57); /*PUSH EDI*/ - addbyte(0xe8); /*CALL mmutranslatereal*/ - addlong((uint32_t)mmutranslatereal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x83); /*ADD ESP, 8*/ - addbyte(0xc4); - addbyte(8); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - addbyte(0xc3); /*RET*/ - - return addr; -} - -/*static void checkdebug(uint32_t a) -{ - pclog("checkdebug %08x\n", a); -}*/ - -static uint32_t gen_MEM_CHECK_WRITE_W() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*seg = ESI, addr = EAX*/ - - addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ - addbyte(0x3c); - addbyte(0x30); - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3d); - addlong((uint32_t)&cr0); - addbyte(0); - addbyte(0x78); /*JS +*/ - addbyte(1); - addbyte(0xc3); /*RET*/ - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); - addbyte(0x8d); /*LEA ESI, 1[EDI]*/ - addbyte(0x77); - addbyte(0x01); - addbyte(0x74); /*JE slowpath*/ - addbyte(11); - addbyte(0x89); /*MOV EAX, EDI*/ - addbyte(0xf8); - addbyte(0xc1); /*SHR EDI, 12*/ - addbyte(0xef); - addbyte(12); - addbyte(0xc1); /*SHR ESI, 12*/ - addbyte(0xee); - addbyte(12); - addbyte(0x83); /*CMP writelookup2[EDI*4],-1*/ - addbyte(0x3c); - addbyte(0xbd); - addlong((uint32_t)writelookup2); - addbyte(-1); - addbyte(0x74); /*JE +*/ - addbyte(11); - addbyte(0x83); /*CMP writelookup2[ESI*4],-1*/ - addbyte(0x3c); - addbyte(0xb5); - addlong((uint32_t)writelookup2); - addbyte(-1); - addbyte(0x74); /*JE +*/ - addbyte(1); - addbyte(0xc3); /*RET*/ - - /*slowpath:*/ - addbyte(0x89); /*MOV EDI, EAX*/ - addbyte(0xc7); - /*slowpath_lp:*/ - addbyte(0x6a); /*PUSH 1*/ - addbyte(1); - addbyte(0x57); /*PUSH EDI*/ - addbyte(0xe8); /*CALL mmutranslatereal*/ - addlong((uint32_t)mmutranslatereal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x5f); /*POP EDI*/ - addbyte(0x83); /*ADD ESP, 4*/ - addbyte(0xc4); - addbyte(4); - addbyte(0x83); /*ADD EDI, 1*/ - addbyte(0xc7); - addbyte(1); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - /*If bits 0-11 of the address are now 0 then this crosses a page, so loop back*/ - addbyte(0xf7); /*TEST $fff, EDI*/ - addbyte(0xc7); - addlong(0xfff); - addbyte(0x74); /*JE slowpath_lp*/ - addbyte(-33); - addbyte(0xc3); /*RET*/ - - return addr; -} - -static uint32_t gen_MEM_CHECK_WRITE_L() -{ - uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; - - /*seg = ESI, addr = EAX*/ - - addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ - addbyte(0x3c); - addbyte(0x30); - addbyte(0x83); /*CMP cr0, 0*/ - addbyte(0x3d); - addlong((uint32_t)&cr0); - addbyte(0); - addbyte(0x78); /*JS +*/ - addbyte(1); - addbyte(0xc3); /*RET*/ - addbyte(0x83); /*CMP ESI, -1*/ - addbyte(0xfe); - addbyte(-1); - addbyte(0x8d); /*LEA ESI, 3[EDI]*/ - addbyte(0x77); - addbyte(0x03); - addbyte(0x74); /*JE slowpath*/ - addbyte(11); - addbyte(0x89); /*MOV EAX, EDI*/ - addbyte(0xf8); - addbyte(0xc1); /*SHR EDI, 12*/ - addbyte(0xef); - addbyte(12); - addbyte(0xc1); /*SHR ESI, 12*/ - addbyte(0xee); - addbyte(12); - addbyte(0x83); /*CMP writelookup2[EDI*4],-1*/ - addbyte(0x3c); - addbyte(0xbd); - addlong((uint32_t)writelookup2); - addbyte(-1); - addbyte(0x74); /*JE +*/ - addbyte(11); - addbyte(0x83); /*CMP writelookup2[ESI*4],-1*/ - addbyte(0x3c); - addbyte(0xb5); - addlong((uint32_t)writelookup2); - addbyte(-1); - addbyte(0x74); /*JE +*/ - addbyte(1); - addbyte(0xc3); /*RET*/ - - /*slowpath:*/ - addbyte(0x89); /*MOV EDI, EAX*/ - addbyte(0xc7); - /*slowpath_lp:*/ - addbyte(0x6a); /*PUSH 1*/ - addbyte(1); - addbyte(0x57); /*PUSH EDI*/ - addbyte(0xe8); /*CALL mmutranslatereal*/ - addlong((uint32_t)mmutranslatereal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); - addbyte(0x5f); /*POP EDI*/ - addbyte(0x83); /*ADD ESP, 4*/ - addbyte(0xc4); - addbyte(4); - addbyte(0x83); /*ADD EDI, 3*/ - addbyte(0xc7); - addbyte(3); - addbyte(0x80); /*CMP abrt, 0*/ - addbyte(0x7d); - addbyte((uint8_t)cpu_state_offset(abrt)); - addbyte(0); - addbyte(0x0f); /*JNE mem_abrt_rout*/ - addbyte(0x85); - addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); - /*If bits 2-11 of the address are now 0 then this crosses a page, so loop back*/ - addbyte(0xf7); /*TEST EDI, FFC*/ - addbyte(0xc7); - addlong(0xffc); - addbyte(0x74); /*JE slowpath_lp*/ - addbyte(-33); - addbyte(0xc3); /*RET*/ - - return addr; -} - -void codegen_init() -{ -#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+1) * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); -#else - codeblock = malloc((BLOCK_SIZE+1) * sizeof(codeblock_t)); -#endif - codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); - - memset(codeblock, 0, (BLOCK_SIZE+1) * sizeof(codeblock_t)); - memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); - -#ifdef __linux__ - start = (void *)((long)codeblock & pagemask); - len = (((BLOCK_SIZE+1) * 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); - - block_current = BLOCK_SIZE; - block_pos = 0; - mem_abrt_rout = (uint32_t)&codeblock[block_current].data[block_pos]; - addbyte(0x83); /*ADDL $16+4,%esp*/ - addbyte(0xC4); - addbyte(0x10+4); - addbyte(0x5f); /*POP EDI*/ - addbyte(0x5e); /*POP ESI*/ - addbyte(0x5d); /*POP EBP*/ - addbyte(0x5b); /*POP EDX*/ - addbyte(0xC3); /*RET*/ - block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_l = (uint32_t)gen_MEM_LOAD_ADDR_EA_L(); - block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_w = (uint32_t)gen_MEM_LOAD_ADDR_EA_W(); - block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_b = (uint32_t)gen_MEM_LOAD_ADDR_EA_B(); - block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_q = (uint32_t)gen_MEM_LOAD_ADDR_EA_Q(); - block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_l = (uint32_t)gen_MEM_STORE_ADDR_EA_L(); - block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_w = (uint32_t)gen_MEM_STORE_ADDR_EA_W(); - block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_b = (uint32_t)gen_MEM_STORE_ADDR_EA_B(); - block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_q = (uint32_t)gen_MEM_STORE_ADDR_EA_Q(); - block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_b_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_B_NO_ABRT(); - block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_b_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_B_NO_ABRT(); - block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_w_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_W_NO_ABRT(); - block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_w_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_W_NO_ABRT(); - block_pos = (block_pos + 15) & ~15; - mem_load_addr_ea_l_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_L_NO_ABRT(); - block_pos = (block_pos + 15) & ~15; - mem_store_addr_ea_l_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_L_NO_ABRT(); - block_pos = (block_pos + 15) & ~15; - mem_check_write = (uint32_t)gen_MEM_CHECK_WRITE(); - block_pos = (block_pos + 15) & ~15; - mem_check_write_w = (uint32_t)gen_MEM_CHECK_WRITE_W(); - block_pos = (block_pos + 15) & ~15; - mem_check_write_l = (uint32_t)gen_MEM_CHECK_WRITE_L(); - - asm( - "fstcw %0\n" - : "=m" (cpu_state.old_npxc) - ); -} - -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 add_to_block_list(codeblock_t *block) -{ - codeblock_t *block_prev = pages[block->phys >> 12].block; - - if (!block->page_mask) - fatal("add_to_block_list - mask = 0\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) - { - if (!block->next->pc) - fatal("block->next->pc=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); - } - - if (block->page_mask2) - { - 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; - } - else - { - block->next_2 = NULL; - pages[block->phys_2 >> 12].block_2 = block; - } - } -} - -static void remove_from_block_list(codeblock_t *block, uint32_t pc) -{ - if (!block->page_mask) - return; - - 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); - } -} - -static void delete_block(codeblock_t *block) -{ - uint32_t old_pc = 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); - remove_from_block_list(block, old_pc); -} - -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; - 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->next_2 = block->prev_2 = NULL; - block->page_mask = 0; - block->flags = CODEBLOCK_STATIC_TOP; - - block->was_recompiled = 0; - - recomp_page = block->phys & ~0xfff; - - codeblock_tree_add(block); -} - -void codegen_block_start_recompile(codeblock_t *block) -{ - page_t *page = &pages[block->phys >> 12]; - - if (!page->block) - mem_flush_write_page(block->phys, cs+cpu_state.pc); - - block_num = HASH(block->phys); - block_current = block->pnt; - - if (block->pc != cs + cpu_state.pc || block->was_recompiled) - fatal("Recompile to used block!\n"); - - 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, &cpu_state*/ - addlong(((uintptr_t)&cpu_state) + 128); - -// 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 = block->phys & ~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; - - block->TOP = cpu_state.TOP; - block->was_recompiled = 1; -} - -void codegen_block_remove() -{ - codeblock_t *block = &codeblock[block_current]; - - delete_block(block); - cpu_recomp_removed++; - - recomp_page = -1; -} - -void codegen_block_generate_end_mask() -{ - codeblock_t *block = &codeblock[block_current]; - 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; - - 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); - - 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); - recomp_page = -1; -} - -void codegen_block_end() -{ - codeblock_t *block = &codeblock[block_current]; - - codegen_block_generate_end_mask(); - add_to_block_list(block); -} - -void codegen_block_end_recompile(codeblock_t *block) -{ - codegen_timing_block_end(); - - if (codegen_block_cycles) - { - addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ - addbyte(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addlong(codegen_block_cycles); - } - if (codegen_block_ins) - { - addbyte(0x81); /*ADD $codegen_block_ins,ins*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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"); - - remove_from_block_list(block, block->pc); - block->next = block->prev = NULL; - block->next_2 = block->prev_2 = NULL; - codegen_block_generate_end_mask(); - add_to_block_list(block); -// pclog("End block %i\n", block_num); - - if (!(block->flags & CODEBLOCK_HAS_FPU)) - block->flags &= ~CODEBLOCK_STATIC_TOP; -} - -void codegen_flush() -{ - return; -} - -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, 0, 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 (!cpu_mod && cpu_rm == 6) - { - addbyte(0xC7); /*MOVL $0,(ssegs)*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(eaaddr)); - addlong((fetchdat >> 8) & 0xffff); - (*op_pc) += 2; - } - else - { - switch (cpu_mod) - { - case 0: - addbyte(0xa1); /*MOVL *mod1add[0][cpu_rm], %eax*/ - addlong((uint32_t)mod1add[0][cpu_rm]); - addbyte(0x03); /*ADDL *mod1add[1][cpu_rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[1][cpu_rm]); - break; - case 1: - addbyte(0xb8); /*MOVL ,%eax*/ - addlong((uint32_t)(int8_t)(rmdat >> 8));// pc++; - addbyte(0x03); /*ADDL *mod1add[0][cpu_rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[0][cpu_rm]); - addbyte(0x03); /*ADDL *mod1add[1][cpu_rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[1][cpu_rm]); - (*op_pc)++; - break; - case 2: - addbyte(0xb8); /*MOVL ,%eax*/ - addlong((fetchdat >> 8) & 0xffff);// pc++; - addbyte(0x03); /*ADDL *mod1add[0][cpu_rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[0][cpu_rm]); - addbyte(0x03); /*ADDL *mod1add[1][cpu_rm], %eax*/ - addbyte(0x05); - addlong((uint32_t)mod1add[1][cpu_rm]); - (*op_pc) += 2; - break; - } - addbyte(0x25); /*ANDL $0xffff, %eax*/ - addlong(0xffff); - addbyte(0xa3); - addlong((uint32_t)&cpu_state.eaaddr); - - if (mod1seg[cpu_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 (cpu_rm == 4) - { - uint8_t sib = fetchdat >> 8; - (*op_pc)++; - - switch (cpu_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((uint8_t)cpu_state_offset(regs[sib & 7].l)); - } - 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((uint8_t)cpu_state_offset(regs[sib & 7].l)); - (*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((uint8_t)cpu_state_offset(regs[sib & 7].l)); - (*op_pc) += 4; - break; - } - if (stack_offset && (sib & 7) == 4 && (cpu_mod || (sib & 7) != 5)) /*ESP*/ - { - addbyte(0x05); - addlong(stack_offset); - } - if (((sib & 7) == 4 || (cpu_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((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); - break; - case 1: - addbyte(0x8B); addbyte(0x5D); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*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((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*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((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*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)&cpu_state.eaaddr); - } - else - { - if (!cpu_mod && cpu_rm == 5) - { - new_eaaddr = fastreadl(cs + (*op_pc) + 1); - addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(eaaddr)); - addlong(new_eaaddr); - (*op_pc) += 4; - return op_ea_seg; - } - addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(regs[cpu_rm].l)); -// addbyte(0xa1); /*MOVL regs[cpu_rm].l, %eax*/ -// addlong((uint32_t)&cpu_state.regs[cpu_rm].l); - cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; - if (cpu_mod) - { - if (cpu_rm == 5 && !op_ssegs) - op_ea_seg = &_ss; - if (cpu_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)&cpu_state.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; - block->flags |= CODEBLOCK_HAS_FPU; - 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; - block->flags |= CODEBLOCK_HAS_FPU; - 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; - block->flags |= CODEBLOCK_HAS_FPU; - 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; - block->flags |= CODEBLOCK_HAS_FPU; - 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; - block->flags |= CODEBLOCK_HAS_FPU; - 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; - block->flags |= CODEBLOCK_HAS_FPU; - 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; - block->flags |= CODEBLOCK_HAS_FPU; - 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; - block->flags |= CODEBLOCK_HAS_FPU; - break; - - case 0xf0: /*LOCK*/ - break; - - default: - goto generate_call; - } - fetchdat = fastreadl(cs + op_pc); - codegen_timing_prefix(opcode, fetchdat); - if (cpu_state.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(0x6d); - addbyte((uint8_t)cpu_state_offset(_cycles)); - addlong(codegen_block_cycles); - codegen_block_cycles = 0; - } - if (codegen_block_ins) - { - addbyte(0x81); /*ADD $codegen_block_ins,ins*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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 (op_ssegs != last_ssegs) - { - last_ssegs = op_ssegs; - - addbyte(0xC6); /*MOVB [ssegs],op_ssegs*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(ssegs)); - addbyte(op_pc + pc_off); - } - - 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; - - cpu_mod = (fetchdat >> 6) & 3; - cpu_reg = (fetchdat >> 3) & 7; - cpu_rm = fetchdat & 7; - - addbyte(0xC7); /*MOVL $rm | mod | reg,(rm_mod_reg_data)*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(rm_data.rm_mod_reg_data)); - addlong(cpu_rm | (cpu_mod << 8) | (cpu_reg << 16)); - - op_pc += pc_off; - if (cpu_mod != 3 && !(op_32 & 0x200)) - op_ea_seg = codegen_generate_ea_16_long(op_ea_seg, fetchdat, op_ssegs, &op_pc); - if (cpu_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(0x45); - addbyte((uint8_t)cpu_state_offset(ea_seg)); - addlong((uint32_t)op_ea_seg); - } - - addbyte(0xC7); /*MOVL pc,new_pc*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(pc)); - addlong(op_pc + pc_off); - - addbyte(0xC7); /*MOVL $old_pc,(oldpc)*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(oldpc)); - addlong(old_pc); - - if (op_32 != last_op32) - { - last_op32 = op_32; - addbyte(0xC7); /*MOVL $use32,(op32)*/ - addbyte(0x45); - addbyte((uint8_t)cpu_state_offset(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; -} - -#endif diff --git a/src/codegen_x86.h b/src/codegen_x86.h deleted file mode 100644 index c01608e..0000000 --- a/src/codegen_x86.h +++ /dev/null @@ -1,42 +0,0 @@ -#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) - -#define BLOCK_MAX 1720 - -enum -{ - OP_RET = 0xc3 -}; - -#define NR_HOST_REGS 4 -extern int host_reg_mapping[NR_HOST_REGS]; -#define NR_HOST_XMM_REGS 7 -extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; - -extern uint32_t mem_load_addr_ea_b; -extern uint32_t mem_load_addr_ea_w; -extern uint32_t mem_load_addr_ea_l; -extern uint32_t mem_load_addr_ea_q; -extern uint32_t mem_store_addr_ea_b; -extern uint32_t mem_store_addr_ea_w; -extern uint32_t mem_store_addr_ea_l; -extern uint32_t mem_store_addr_ea_q; - -extern uint32_t mem_load_addr_ea_b_no_abrt; -extern uint32_t mem_store_addr_ea_b_no_abrt; -extern uint32_t mem_load_addr_ea_w_no_abrt; -extern uint32_t mem_store_addr_ea_w_no_abrt; -extern uint32_t mem_load_addr_ea_l_no_abrt; -extern uint32_t mem_store_addr_ea_l_no_abrt; -extern uint32_t mem_check_write; -extern uint32_t mem_check_write_w; -extern uint32_t mem_check_write_l; diff --git a/src/config.c b/src/config.c index ca2a184..b880aab 100644 --- a/src/config.c +++ b/src/config.c @@ -5,6 +5,7 @@ #include "config.h" char config_file_default[256]; +char config_name[256]; static char config_file[256]; @@ -98,6 +99,43 @@ void config_free(int is_global) } } +int config_free_section(int is_global, char *name) +{ + section_t *current_section, *prev_section; + list_t *head = is_global ? &global_config_head : &machine_config_head; + current_section = (section_t *)head->next; + prev_section = 0; + + while (current_section) + { + section_t *next_section = (section_t *)current_section->list.next; + if (!strcmp(current_section->name, name)) + { + 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); + if (!prev_section) + head->next = (list_t*)next_section; + else + prev_section->list.next = (list_t*)next_section; + return 1; + } + prev_section = current_section; + current_section = next_section; + } + return 0; +} + void config_load(int is_global, char *fn) { FILE *f = fopen(fn, "rt"); @@ -190,8 +228,6 @@ void config_load(int is_global, char *fn) } fclose(f); - - config_dump(is_global); } @@ -281,6 +317,27 @@ int config_get_int(int is_global, char *head, char *name, int def) return value; } +float config_get_float(int is_global, char *head, char *name, float def) +{ + section_t *section; + entry_t *entry; + float value; + + section = find_section(head, is_global); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + sscanf(entry->data, "%f", &value); + + return value; +} + char *config_get_string(int is_global, char *head, char *name, char *def) { section_t *section; @@ -317,6 +374,24 @@ void config_set_int(int is_global, char *head, char *name, int val) sprintf(entry->data, "%i", val); } +void config_set_float(int is_global, char *head, char *name, float val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head, is_global); + + if (!section) + section = create_section(head, is_global); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + sprintf(entry->data, "%f", val); +} + void config_set_string(int is_global, char *head, char *name, char *val) { section_t *section; @@ -353,11 +428,26 @@ void append_filename(char *dest, char *s1, char *s2, int size) sprintf(dest, "%s%s", s1, s2); } +void append_slash(char *s, int size) +{ + int c = strlen(s)-1; + if (s[c] != '/' && s[c] != '\\') + { + if (c < size-2) + strcat(s, "/"); + else + s[c] = '/'; + } +} + void put_backslash(char *s) { int c = strlen(s) - 1; if (s[c] != '/' && s[c] != '\\') - s[c] = '/'; + { + s[c+1] = '/'; + s[c+2] = 0; + } } char *get_extension(char *s) diff --git a/src/config.h b/src/config.h index 23b0a48..dd2dceb 100644 --- a/src/config.h +++ b/src/config.h @@ -1,10 +1,17 @@ +float config_get_float(int is_global, char *head, char *name, float def); int config_get_int(int is_global, char *head, char *name, int def); char *config_get_string(int is_global, char *head, char *name, char *def); +void config_set_float(int is_global, char *head, char *name, float val); void config_set_int(int is_global, char *head, char *name, int val); void config_set_string(int is_global, char *head, char *name, char *val); +int config_free_section(int is_global, char *head); + +void add_config_callback(void(*loadconfig)(), void(*saveconfig)(), void(*onloaded)()); + char *get_filename(char *s); void append_filename(char *dest, char *s1, char *s2, int size); +void append_slash(char *s, int size); void put_backslash(char *s); char *get_extension(char *s); @@ -14,6 +21,7 @@ void config_dump(int is_global); void config_free(int is_global); extern char config_file_default[256]; +extern char config_name[256]; #define CFG_MACHINE 0 #define CFG_GLOBAL 1 diff --git a/src/cpu.c b/src/cpu.c index 540ba2d..99c0c8b 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -6,8 +6,16 @@ #include "mem.h" #include "pci.h" #include "codegen.h" +#include "x87_timings.h" + +int fpu_type; +uint32_t cpu_features; + +static int cpu_turbo_speed, cpu_nonturbo_speed; +static int cpu_turbo = 1; int isa_cycles; +int has_vlb; static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; OpFn *x86_dynarec_opcodes; @@ -28,6 +36,9 @@ 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_dynarec_opcodes_REPE; +OpFn *x86_dynarec_opcodes_REPNE; +OpFn *x86_dynarec_opcodes_3DNOW; OpFn *x86_opcodes; OpFn *x86_opcodes_0f; @@ -47,36 +58,48 @@ OpFn *x86_opcodes_de_a16; OpFn *x86_opcodes_de_a32; OpFn *x86_opcodes_df_a16; OpFn *x86_opcodes_df_a32; +OpFn *x86_opcodes_REPE; +OpFn *x86_opcodes_REPNE; +OpFn *x86_opcodes_3DNOW; enum { CPUID_FPU = (1 << 0), + CPUID_VME = (1 << 1), + CPUID_PSE = (1 << 3), CPUID_TSC = (1 << 4), CPUID_MSR = (1 << 5), CPUID_CMPXCHG8B = (1 << 8), + CPUID_SEP = (1 << 11), CPUID_CMOV = (1 << 15), CPUID_MMX = (1 << 23) }; +/*Addition flags returned by CPUID function 0x80000001*/ +enum +{ + CPUID_3DNOW = (1 << 31) +}; + 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; +int cpu_cyrix_alignment; uint64_t cpu_CR4_mask; int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; -int cpu_prefetch_cycles, cpu_prefetch_width; +int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; int cpu_waitstates; int cpu_cache_int_enabled, cpu_cache_ext_enabled; int is386; +int is486; +int CPUID; uint64_t tsc = 0; @@ -90,6 +113,7 @@ 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; +int timing_misaligned; static struct { @@ -99,356 +123,64 @@ static struct 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, 0,0,0,0}, - {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 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, 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, 0,0,0,0}, - {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8086/9.54", CPU_8086, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8086/12", CPU_8086, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0}, - {"8086/16", CPU_8086, 4, 16000000, 1, 0, 0, 0, 0, 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, 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, 2,2,2,2}, - {"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2}, - {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2}, - {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3}, - {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3}, - {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4}, - {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4}, - {"", -1, 0, 0, 0, 0} -}; - -CPU cpus_ibmat[] = -{ - /*286*/ - {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3}, - {"286/8", CPU_286, 0, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3}, - {"", -1, 0, 0, 0, 0} -}; - -CPU cpus_ps1_m2011[] = -{ - /*286*/ - {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2}, - {"", -1, 0, 0, 0, 0} -}; - -CPU cpus_ps2_m30_286[] = -{ - /*286*/ - {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2}, - {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3}, - {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3}, - {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4}, - {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4}, - {"", -1, 0, 0, 0, 0} -}; - -CPU cpus_i386SX[] = -{ - /*i386SX*/ - {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3}, - {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3}, - {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3}, - {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_i386DX[] = -{ - /*i386DX*/ - {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3}, - {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3}, - {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3}, - {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_acer[] = -{ - /*i386SX*/ - {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,4,4}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_Am386SX[] = -{ - /*Am386*/ - {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3}, - {"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3}, - {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3}, - {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3}, - {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_Am386DX[] = -{ - /*Am386*/ - {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3}, - {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3}, - {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_486SLC[] = -{ - /*Cx486SLC*/ - {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3}, - {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3}, - {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3}, - {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6}, - {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6}, - {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_486DLC[] = -{ - /*Cx486DLC*/ - {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4,4,3,3}, - {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6,6,3,3}, - {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7,7,3,3}, - {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6,6,6,6}, - {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6}, - {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6}, - {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_i486[] = -{ - /*i486*/ - {"i486SX/16", CPU_i486SX, 0, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3,3,3,3}, - {"i486SX/20", CPU_i486SX, 1, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3}, - {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3}, - {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3}, - {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, - {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3}, - {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3}, - {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4}, - {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, - {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, - {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6}, - {"iDX4/75", CPU_i486DX, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9}, /*CPUID available on DX4, >= 75 MHz*/ - {"iDX4/100", CPU_i486DX,10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9}, /*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, 10,10,7,7}, - {"Pentium OverDrive/83", CPU_PENTIUM, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_Am486[] = -{ - /*Am486/5x86*/ - {"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3}, - {"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3}, - {"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ - {"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6}, /*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, 6,6,3,3}, - {"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3}, - {"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, - {"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6}, - {"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14,6,6}, - {"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9}, - {"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9}, - {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9}, - {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21,9,9}, - {"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12}, - {"Am5x86/P75+", CPU_Am486DX, 13, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_Cx486[] = -{ - /*Cx486/5x86*/ - {"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4,4,3,3}, - {"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6,6,3,3}, - {"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7,7,3,3}, - {"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6,6,3,3}, - {"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7,7,3,3}, - {"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, - {"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12,6,6}, - {"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14,16,16}, - {"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12,9,9}, - {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15,9,9}, - {"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15,9,9}, - {"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21,9,9}, - {"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12}, - {"", -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, 8,8,6,6}, - {"6x86-PR120+", CPU_Cx6x86, 17, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6}, - {"6x86-PR133+", CPU_Cx6x86, 17, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6}, - {"6x86-PR150+", CPU_Cx6x86, 17, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"6x86-PR166+", CPU_Cx6x86, 17, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"6x86-PR200+", CPU_Cx6x86, 17, 150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - - /*Cyrix 6x86L*/ - {"6x86L-PR133+", CPU_Cx6x86L, 19, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6}, - {"6x86L-PR150+", CPU_Cx6x86L, 19, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"6x86L-PR166+", CPU_Cx6x86L, 19, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"6x86L-PR200+", CPU_Cx6x86L, 19, 150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - - /*Cyrix 6x86MX*/ - {"6x86MX-PR166", CPU_Cx6x86MX, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"6x86MX-PR200", CPU_Cx6x86MX, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"6x86MX-PR233", CPU_Cx6x86MX, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"6x86MX-PR266", CPU_Cx6x86MX, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7}, - {"6x86MX-PR300", CPU_Cx6x86MX, 18, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,7,7}, - {"6x86MX-PR333", CPU_Cx6x86MX, 18, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20,9,9}, - {"6x86MX-PR366", CPU_Cx6x86MX, 18, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12}, - {"6x86MX-PR400", CPU_Cx6x86MX, 18, 285000000, 3, 31666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, - {"", -1, 0, 0, 0} - }; - - - -CPU cpus_WinChip[] = -{ - /*IDT WinChip*/ - {"WinChip 75", CPU_WINCHIP, 7, 75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4}, - {"WinChip 90", CPU_WINCHIP, 9, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4}, - {"WinChip 100", CPU_WINCHIP, 10, 100000000, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4}, - {"WinChip 120", CPU_WINCHIP, 11, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6}, - {"WinChip 133", CPU_WINCHIP, 12, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6}, - {"WinChip 150", CPU_WINCHIP, 13, 150000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7}, - {"WinChip 166", CPU_WINCHIP, 15, 166666666, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7}, - {"WinChip 180", CPU_WINCHIP, 16, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9}, - {"WinChip 200", CPU_WINCHIP, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9}, - {"WinChip 225", CPU_WINCHIP, 17, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9}, - {"WinChip 240", CPU_WINCHIP, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12}, - {"", -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, 6,6,3,3}, - {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3}, - {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_PentiumS5[] = -{ - /*Intel Pentium (Socket 5)*/ - {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4}, - {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4}, - {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6}, - {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4}, - {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7}, - {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, - {"", -1, 0, 0, 0} -}; - -CPU cpus_Pentium[] = -{ - /*Intel Pentium*/ - {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4}, - {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4}, - {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6}, - {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4}, - {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"Pentium 133", CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"Pentium 150", CPU_PENTIUM, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium 166", CPU_PENTIUM, 19, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium 200", CPU_PENTIUM, 21, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, - {"Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, - {"Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10}, - {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, 14, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, 16, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6}, - {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, 17, 150000000, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, - {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10}, - {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, 26, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12}, - {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, 28, 300000000, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13}, - {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7}, - {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7}, - {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7}, - {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, - {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9}, - {"", -1, 0, 0, 0} -}; - void cpu_set_edx() { EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset; } +int fpu_get_type(int model, int manu, int cpu, const char *internal_name) +{ + CPU *cpu_s = &models[model].cpu[manu].cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + int fpu_type = fpus[0].type; + int c = 0; + + while (fpus[c].internal_name) + { + if (!strcmp(internal_name, fpus[c].internal_name)) + fpu_type = fpus[c].type; + c++; + } + + return fpu_type; +} + +const char *fpu_get_internal_name(int model, int manu, int cpu, int type) +{ + CPU *cpu_s = &models[model].cpu[manu].cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + int c = 0; + + while (fpus[c].internal_name) + { + if (fpus[c].type == type) + return fpus[c].internal_name; + c++; + } + + return fpus[0].internal_name; +} + +const char *fpu_get_name_from_index(int model, int manu, int cpu, int c) +{ + CPU *cpu_s = &models[model].cpu[manu].cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + + return fpus[c].name; +} + +int fpu_get_type_from_index(int model, int manu, int cpu, int c) +{ + CPU *cpu_s = &models[model].cpu[manu].cpus[cpu]; + const FPU *fpus = cpu_s->fpus; + + return fpus[c].type; +} + +CPU *cpu_s; + void cpu_set() { - CPU *cpu_s; - if (!models[model].cpu[cpu_manufacturer].cpus) { /*CPU is invalid, set to default*/ @@ -463,21 +195,33 @@ void cpu_set() is8086 = (cpu_s->cpu_type > CPU_8088); 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); + hasfpu = (fpu_type != FPU_NONE); + 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_286 || 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; + has_vlb = (cpu_s->cpu_type >= CPU_i486SX) && (cpu_s->cpu_type <= CPU_Cx5x86); + + cpu_turbo_speed = cpu_s->rspeed; + if (cpu_s->cpu_type < CPU_286) + cpu_nonturbo_speed = 4772728; + else if (cpu_s->rspeed < 8000000) + cpu_nonturbo_speed = cpu_s->rspeed; + else + cpu_nonturbo_speed = 8000000; + cpu_turbo = 1; cpu_update_waitstates(); + + isa_cycles = cpu_s->atclk_div; - isa_cycles = (int)(((int64_t)cpu_s->rspeed << ISA_CYCLES_SHIFT) / 8000000ll); + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; + else + cpu_rom_prefetch_cycles = cpu_s->rspeed / 1000000; if (cpu_s->pci_speed) { @@ -500,6 +244,12 @@ void cpu_set() pclog("is486 - %i %i\n",is486,cpu_s->cpu_type); x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); + x86_opcodes_REPE = ops_REPE; + x86_opcodes_REPNE = ops_REPNE; + x86_opcodes_3DNOW = ops_3DNOW; + x86_dynarec_opcodes_REPE = dynarec_ops_REPE; + x86_dynarec_opcodes_REPNE = dynarec_ops_REPNE; + x86_dynarec_opcodes_3DNOW = dynarec_ops_3DNOW; if (hasfpu) { @@ -581,6 +331,10 @@ void cpu_set() } memset(&msr, 0, sizeof(msr)); + + timing_misaligned = 0; + cpu_cyrix_alignment = 0; + cpu_CR4_mask = 0; switch (cpu_s->cpu_type) { @@ -712,6 +466,7 @@ void cpu_set() timing_jmp_rm = 9; timing_jmp_pm = 26; timing_jmp_pm_gate = 37; + timing_misaligned = 3; break; case CPU_486DLC: @@ -744,8 +499,12 @@ void cpu_set() timing_jmp_rm = 9; timing_jmp_pm = 26; timing_jmp_pm_gate = 37; + timing_misaligned = 3; break; - + + case CPU_iDX4: + cpu_features = CPU_FEATURE_CR4 | CPU_FEATURE_VME; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; case CPU_i486SX: case CPU_i486DX: timing_rr = 1; /*register dest - register src*/ @@ -776,6 +535,7 @@ void cpu_set() timing_jmp_rm = 17; timing_jmp_pm = 19; timing_jmp_pm_gate = 32; + timing_misaligned = 3; break; case CPU_Am486SX: @@ -809,6 +569,7 @@ void cpu_set() timing_jmp_rm = 17; timing_jmp_pm = 19; timing_jmp_pm_gate = 32; + timing_misaligned = 3; break; case CPU_Cx486S: @@ -841,6 +602,7 @@ void cpu_set() timing_jmp_rm = 9; timing_jmp_pm = 26; timing_jmp_pm_gate = 37; + timing_misaligned = 3; break; case CPU_Cx5x86: @@ -872,6 +634,8 @@ void cpu_set() timing_jmp_rm = 5; timing_jmp_pm = 7; timing_jmp_pm_gate = 17; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; break; case CPU_WINCHIP: @@ -885,10 +649,8 @@ void cpu_set() 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_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4; + msr.fcr = (1 << 8) | (1 << 16); cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; /*unknown*/ timing_int_rm = 26; @@ -909,9 +671,49 @@ void cpu_set() timing_jmp_rm = 5; timing_jmp_pm = 7; timing_jmp_pm_gate = 17; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; codegen_timing_set(&codegen_timing_winchip); break; + case CPU_WINCHIP2: + x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_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_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21); + 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; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + codegen_timing_set(&codegen_timing_winchip2); + 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*/ @@ -942,12 +744,10 @@ void cpu_set() timing_jmp_rm = 3; timing_jmp_pm = 3; timing_jmp_pm_gate = 18; - cpu_hasrdtsc = 1; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME; 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; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; codegen_timing_set(&codegen_timing_pentium); break; @@ -981,17 +781,15 @@ void cpu_set() timing_jmp_rm = 3; timing_jmp_pm = 3; timing_jmp_pm_gate = 18; - cpu_hasrdtsc = 1; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; 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; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | 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); + x86_setopcodes(ops_386, ops_c6x86_0f, dynarec_ops_386, dynarec_ops_c6x86_0f); timing_rr = 1; /*register dest - register src*/ timing_rm = 1; /*register dest - memory src*/ timing_mr = 2; /*memory dest - register src*/ @@ -1019,11 +817,10 @@ void cpu_set() timing_jmp_rm = 1; timing_jmp_pm = 4; timing_jmp_pm_gate = 14; - cpu_hasrdtsc = 1; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_features = CPU_FEATURE_RDTSC; 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; @@ -1057,11 +854,10 @@ void cpu_set() timing_jmp_rm = 1; timing_jmp_pm = 4; timing_jmp_pm_gate = 14; - cpu_hasrdtsc = 1; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_features = CPU_FEATURE_RDTSC; 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; @@ -1078,11 +874,8 @@ void cpu_set() timing_mml = 2; timing_bt = 5-1; /*branch taken*/ timing_bnt = 1; /*branch not taken*/ - cpu_hasrdtsc = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4; 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; @@ -1129,19 +922,256 @@ void cpu_set() timing_jmp_rm = 1; timing_jmp_pm = 4; timing_jmp_pm_gate = 14; - cpu_hasrdtsc = 1; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_MMX; 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_K6: + 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; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE; + codegen_timing_set(&codegen_timing_k6); + break; + + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_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; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_MMX | CPU_FEATURE_3DNOW; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE; + codegen_timing_set(&codegen_timing_k6); + 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 = 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; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_CX8 | CPU_FEATURE_SYSCALL; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_p6); + break; + + case CPU_PENTIUM_2: + case CPU_CELERON: + case CPU_CELERON_A: + 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 = 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; + timing_misaligned = 3; + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_VME | CPU_FEATURE_CX8 | CPU_FEATURE_MMX | CPU_FEATURE_SYSCALL; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_p6); + break; + + case CPU_CYRIX_III: + x86_setopcodes(ops_386, ops_winchip2_0f, dynarec_ops_386, dynarec_ops_winchip2_0f); + 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 = 1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_features = CPU_FEATURE_RDTSC | CPU_FEATURE_MMX | CPU_FEATURE_MSR | CPU_FEATURE_CR4 | CPU_FEATURE_3DNOW; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 18) | (1 << 19) | (1 << 20) | (1 << 21); + 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; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + codegen_timing_set(&codegen_timing_cyrixiii); + break; + default: fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type); } + + switch (fpu_type) + { + case FPU_NONE: + break; + + case FPU_8087: + x87_timings = x87_timings_8087; + break; + + case FPU_287: + x87_timings = x87_timings_287; + break; + + case FPU_287XL: + case FPU_387: + x87_timings = x87_timings_387; + break; + + default: + x87_timings = x87_timings_486; + break; + } } void cpu_CPUID() @@ -1163,7 +1193,25 @@ void cpu_CPUID() EDX = CPUID_FPU; /*FPU*/ } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_iDX4: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME; + } + else + EAX = EBX = ECX = EDX = 0; break; case CPU_Am486SX: @@ -1180,7 +1228,7 @@ void cpu_CPUID() EBX = ECX = EDX = 0; /*No FPU*/ } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_Am486DX: @@ -1198,7 +1246,7 @@ void cpu_CPUID() EDX = CPUID_FPU; /*FPU*/ } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_WINCHIP: @@ -1214,7 +1262,7 @@ void cpu_CPUID() else { EBX = 0x746e6543; /*CentaurHauls*/ - ECX = 0x736c7561; + ECX = 0x736c7561; EDX = 0x48727561; } } @@ -1223,11 +1271,73 @@ void cpu_CPUID() EAX = 0x540; EBX = ECX = 0; EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; if (msr.fcr & (1 << 9)) EDX |= CPUID_MMX; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_WINCHIP2: + switch (EAX) + { + case 0: + 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; + } + break; + case 1: + EAX = 0x580; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000005; + break; + case 0x80000001: + EAX = 0x580; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + if (cpu_has_feature(CPU_FEATURE_3DNOW)) + EDX |= CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x20544449; /*IDT WinChip 2-3D*/ + EBX = 0x436e6957; + ECX = 0x20706968; + EDX = 0x44332d32; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x08800880; /*TLBs*/ + ECX = 0x20040120; /*L1 data cache*/ + EDX = 0x20020120; /*L1 instruction cache*/ + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } break; case CPU_PENTIUM: @@ -1242,10 +1352,10 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; case CPU_PENTIUMMMX: @@ -1260,10 +1370,10 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; @@ -1282,7 +1392,7 @@ void cpu_CPUID() EDX = CPUID_FPU; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; @@ -1301,7 +1411,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_CMPXCHG8B; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; @@ -1320,7 +1430,7 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; @@ -1340,9 +1450,349 @@ void cpu_CPUID() EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; } else - EAX = 0; + EAX = EBX = ECX = EDX = 0; break; + case CPU_K6: + switch (EAX) + { + case 0: + EAX = 1; + EBX = 0x68747541; /*AuthenticAMD*/ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000005; + break; + case 0x80000001: + EAX = CPUID+0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x2d444d41; /*AMD-K6tm w/ mult*/ + EBX = 0x6d74364b; + ECX = 0x202f7720; + EDX = 0x746c756d; + break; + + case 0x80000003: /*Processor name string*/ + EAX = 0x64656d69; /*imedia extension*/ + EBX = 0x65206169; + ECX = 0x6e657478; + EDX = 0x6e6f6973; + break; + + case 0x80000004: /*Processor name string*/ + EAX = 0x00000073; /*s*/ + EBX = 0x00000000; + ECX = 0x00000000; + EDX = 0x00000000; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x02800140; /*TLBs*/ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + + case CPU_K6_2: + switch (EAX) + { + case 0: + EAX = 1; + EBX = 0x68747541; /*AuthenticAMD*/ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000005; + break; + case 0x80000001: + EAX = CPUID+0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x2d444d41; /*AMD-K6(tm) 3D pr*/ + EBX = 0x7428364b; + ECX = 0x3320296d; + EDX = 0x72702044; + break; + + case 0x80000003: /*Processor name string*/ + EAX = 0x7365636f; /*ocessor*/ + EBX = 0x00726f73; + ECX = 0x00000000; + EDX = 0x00000000; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x02800140; /*TLBs*/ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + + case CPU_K6_3: + switch (EAX) + { + case 0: + EAX = 1; + EBX = 0x68747541; /*AuthenticAMD*/ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000006; + break; + case 0x80000001: + EAX = CPUID+0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x2d444d41; /*AMD-K6(tm) 3D+ P*/ + EBX = 0x7428364b; + ECX = 0x3320296d; + EDX = 0x50202b44; + break; + + case 0x80000003: /*Processor name string*/ + EAX = 0x65636f72; /*rocessor*/ + EBX = 0x726f7373; + ECX = 0x00000000; + EDX = 0x00000000; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x02800140; /*TLBs*/ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + + case 0x80000006: /*L2 Cache information*/ + ECX = 0x01004220; + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; + + case CPU_K6_2P: + case CPU_K6_3P: + switch (EAX) + { + case 0: + EAX = 1; + EBX = 0x68747541; /*AuthenticAMD*/ + ECX = 0x444d4163; + EDX = 0x69746e65; + break; + case 1: + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000007; + break; + case 0x80000001: + EAX = CPUID+0x100; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + EAX = 0x2d444d41; /*AMD-K6(tm)-III P*/ + EBX = 0x7428364b; + ECX = 0x492d296d; + EDX = 0x50204949; + break; + + case 0x80000003: /*Processor name string*/ + EAX = 0x65636f72; /*rocessor*/ + EBX = 0x726f7373; + ECX = 0x00000000; + EDX = 0x00000000; + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x02800140; /*TLBs*/ + ECX = 0x20020220; /*L1 data cache*/ + EDX = 0x20020220; /*L1 instruction cache*/ + break; + + case 0x80000006: /*L2 Cache information*/ + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_K6_3P) + ECX = 0x01004220; + else + ECX = 0x00804220; + break; + + case 0x80000007: /*PowerNow information*/ + EDX = 7; + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + 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_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_SEP; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = 0; + ECX = 0; + EDX = 0x06040a42; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_PENTIUM_2: + case CPU_CELERON: + case CPU_CELERON_A: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX | CPUID_SEP; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = 0; + ECX = 0; + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUM_2) + EDX = 0x08040c43; /*512kb L2 cache*/ + else if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_CELERON) + EDX = 0x08040c40; /*No L2 cache*/ + else + EDX = 0x08040c41; /*128kb L2 cache*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_CYRIX_III: + switch (EAX) + { + case 0: + EAX = 1; + EBX = 0x746e6543; /*CentaurHauls*/ + ECX = 0x736c7561; + EDX = 0x48727561; + break; + case 1: + EAX = models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + break; + case 0x80000000: + EAX = 0x80000006; + break; + case 0x80000001: + EAX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (cpu_has_feature(CPU_FEATURE_CX8)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + if (cpu_has_feature(CPU_FEATURE_3DNOW)) + EDX |= CPUID_3DNOW; + break; + + case 0x80000002: /*Processor name string*/ + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model >= 0x670) + { + EAX = 0x20414956; /*VIA Samuel 2*/ + EBX = 0x756d6153; + ECX = 0x32206c65; + EDX = 0x00000000; + } + else + { + EAX = 0x20414956; /*VIA SamuelM*/ + EBX = 0x756d6153; + ECX = 0x004d6c65; + EDX = 0x00000000; + } + break; + + case 0x80000005: /*Cache information*/ + EBX = 0x08800880; /*TLBs*/ + ECX = 0x40040120; /*L1 data cache*/ + EDX = 0x40020120; /*L1 instruction cache*/ + break; + + case 0x80000006: /*L2 Cache information*/ + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model >= 0x670) + ECX = 0x40040120; /*L2 cache*/ + else + ECX = 0; + EAX = EBX = EDX = 0; + break; + + default: + EAX = EBX = ECX = EDX = 0; + break; + } + break; } } @@ -1351,6 +1801,8 @@ void cpu_RDMSR() switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) { case CPU_WINCHIP: + case CPU_WINCHIP2: + case CPU_CYRIX_III: EAX = EDX = 0; switch (ECX) { @@ -1403,6 +1855,46 @@ void cpu_RDMSR() break; } break; + case CPU_K6: + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + case CPU_PENTIUMPRO: + case CPU_PENTIUM_2: + case CPU_CELERON: + case CPU_CELERON_A: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + + case 0x174: + EAX = sysenter_cs; + EDX = 0; + break; + case 0x175: + EAX = sysenter_esp; + EDX = 0; + break; + case 0x176: + EAX = sysenter_eip; + EDX = 0; + break; + } + break; } } @@ -1411,6 +1903,8 @@ void cpu_WRMSR() switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) { case CPU_WINCHIP: + case CPU_WINCHIP2: + case CPU_CYRIX_III: switch (ECX) { case 0x02: @@ -1427,7 +1921,18 @@ void cpu_WRMSR() break; case 0x107: msr.fcr = EAX; - cpu_hasMMX = EAX & (1 << 9); + if (EAX & (1 << 9)) + cpu_features |= CPU_FEATURE_MMX; + else + cpu_features &= ~CPU_FEATURE_MMX; + if (EAX & (1 << 1)) + cpu_features |= CPU_FEATURE_CX8; + else + cpu_features &= ~CPU_FEATURE_CX8; + if ((EAX & (1 << 20)) && models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type >= CPU_WINCHIP2) + cpu_features |= CPU_FEATURE_3DNOW; + else + cpu_features &= ~CPU_FEATURE_3DNOW; if (EAX & (1 << 29)) CPUID = 0; else @@ -1462,11 +1967,51 @@ void cpu_WRMSR() break; } break; + case CPU_K6: + case CPU_K6_2: + case CPU_K6_3: + case CPU_K6_2P: + case CPU_K6_3P: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + case CPU_PENTIUMPRO: + case CPU_PENTIUM_2: + case CPU_CELERON: + case CPU_CELERON_A: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + + case 0x174: + sysenter_cs = EAX & 0xffff; + break; + case 0x175: + sysenter_esp = EAX; + break; + case 0x176: + sysenter_eip = EAX; + break; + } + break; } } static int cyrix_addr; +#define CCR1_USE_SMI (1 << 1) +#define CCR1_SMAC (1 << 2) +#define CCR1_SM3 (1 << 7) + +#define CCR3_SMI_LOCK (1 << 0) +#define CCR3_NMI_EN (1 << 1) + void cyrix_write(uint16_t addr, uint8_t val, void *priv) { if (!(addr & 1)) @@ -1477,14 +2022,46 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv) ccr0 = val; break; case 0xc1: /*CCR1*/ + if ((ccr3 & CCR3_SMI_LOCK) && !(cpu_cur_status & CPU_STATUS_SMM)) + val = (val & ~(CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)) | (ccr1 & (CCR1_USE_SMI | CCR1_SMAC | CCR1_SM3)); ccr1 = val; break; case 0xc2: /*CCR2*/ ccr2 = val; break; case 0xc3: /*CCR3*/ + if ((ccr3 & CCR3_SMI_LOCK) && !(cpu_cur_status & CPU_STATUS_SMM)) + val = (val & ~(CCR3_NMI_EN)) | (ccr3 & CCR3_NMI_EN) | CCR3_SMI_LOCK; ccr3 = val; break; + case 0xcd: + if (!(ccr3 & CCR3_SMI_LOCK) || (cpu_cur_status & CPU_STATUS_SMM)) + { + cyrix.arr[3].base = (cyrix.arr[3].base & ~0xff000000) | (val << 24); + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xce: + if (!(ccr3 & CCR3_SMI_LOCK) || (cpu_cur_status & CPU_STATUS_SMM)) + { + cyrix.arr[3].base = (cyrix.arr[3].base & ~0x00ff0000) | (val << 16); + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xcf: + if (!(ccr3 & CCR3_SMI_LOCK) || (cpu_cur_status & CPU_STATUS_SMM)) + { + cyrix.arr[3].base = (cyrix.arr[3].base & ~0x0000f000) | ((val & 0xf0) << 8); + if ((val & 0xf) == 0xf) + cyrix.arr[3].size = 1ull << 32; /*4 GB*/ + else if (val & 0xf) + cyrix.arr[3].size = 2048 << (val & 0xf); + else + cyrix.arr[3].size = 0; /*Disabled*/ + cyrix.smhr &= ~SMHR_VALID; + } + break; + case 0xe8: /*CCR4*/ if ((ccr3 & 0xf0) == 0x10) { @@ -1525,7 +2102,6 @@ uint8_t cyrix_read(uint16_t addr, void *priv) 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; @@ -1543,7 +2119,10 @@ void cpu_update_waitstates() { cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu]; - cpu_prefetch_width = cpu_16bitbus ? 2 : 4; + if (is486) + cpu_prefetch_width = 16; + else + cpu_prefetch_width = cpu_16bitbus ? 2 : 4; if (cpu_cache_int_enabled) { @@ -1577,4 +2156,51 @@ void cpu_update_waitstates() cpu_cycles_write = cpu_s->mem_write_cycles; cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_write_cycles; } + if (is486) + cpu_prefetch_cycles = (cpu_prefetch_cycles * 11) / 16; + cpu_mem_prefetch_cycles = cpu_prefetch_cycles; + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; +} + +void cpu_set_turbo(int turbo) +{ + if (cpu_turbo != turbo) + { + cpu_turbo = turbo; + + cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu]; + if (cpu_s->cpu_type >= CPU_286) + { + if (cpu_turbo) + setpitclock(cpu_turbo_speed); + else + setpitclock(cpu_nonturbo_speed); + } + else + setpitclock(14318184.0); + } +} + +int cpu_get_turbo() +{ + return cpu_turbo; +} + +int cpu_get_speed() +{ + if (cpu_turbo) + return cpu_turbo_speed; + return cpu_nonturbo_speed; +} + +void cpu_set_nonturbo_divider(int divider) +{ + if (divider < 2) + cpu_set_turbo(1); + else + { + cpu_nonturbo_speed = cpu_turbo_speed / divider; + cpu_set_turbo(0); + } } diff --git a/src/cpu.h b/src/cpu.h index 4a5a679..97acec1 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -2,6 +2,7 @@ #define _CPU_H_ extern int cpu, cpu_manufacturer; +extern int fpu_type; /*808x class CPUs*/ #define CPU_8088 0 @@ -23,21 +24,34 @@ extern int cpu, cpu_manufacturer; #define CPU_i486DX 10 #define CPU_Am486DX 11 #define CPU_Cx486DX 12 -#define CPU_Cx5x86 13 +#define CPU_iDX4 13 +#define CPU_Cx5x86 14 /*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_WINCHIP 15 +#define CPU_WINCHIP2 16 +#define CPU_PENTIUM 17 +#define CPU_PENTIUMMMX 18 +#define CPU_Cx6x86 19 +#define CPU_Cx6x86MX 20 +#define CPU_Cx6x86L 21 +#define CPU_CxGX1 22 +#define CPU_K6 23 +#define CPU_K6_2 24 +#define CPU_K6_3 25 +#define CPU_K6_2P 26 +#define CPU_K6_3P 27 +#define CPU_PENTIUMPRO 28 +#define CPU_PENTIUM_2 29 +#define CPU_CELERON 30 +#define CPU_CELERON_A 31 +#define CPU_CYRIX_III 32 #define MANU_INTEL 0 #define MANU_AMD 1 #define MANU_CYRIX 2 #define MANU_IDT 3 +#define MANU_VIA 4 extern int timing_rr; extern int timing_mr, timing_mrl; @@ -51,11 +65,30 @@ extern int timing_call_rm, timing_call_pm, timing_call_pm_gate, timing_call_pm_g extern int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +extern int timing_misaligned; + +enum +{ + FPU_NONE, + FPU_8087, + FPU_287, + FPU_287XL, + FPU_387, + FPU_BUILTIN +}; + +typedef struct +{ + const char *name; + const char *internal_name; + const int type; +} FPU; typedef struct { char name[32]; int cpu_type; + const FPU *fpus; int speed; int rspeed; int multi; @@ -66,8 +99,11 @@ typedef struct int cpu_flags; int mem_read_cycles, mem_write_cycles; int cache_read_cycles, cache_write_cycles; + int atclk_div; } CPU; +extern CPU *cpu_s; + extern CPU cpus_8088[]; extern CPU cpus_8086[]; extern CPU cpus_286[]; @@ -81,14 +117,24 @@ extern CPU cpus_i486[]; extern CPU cpus_Am486[]; extern CPU cpus_Cx486[]; extern CPU cpus_WinChip[]; +extern CPU cpus_WinChip_SS7[]; extern CPU cpus_Pentium5V[]; extern CPU cpus_PentiumS5[]; extern CPU cpus_Pentium[]; extern CPU cpus_6x86[]; +extern CPU cpus_6x86_SS7[]; +extern CPU cpus_K6_S7[]; +extern CPU cpus_K6_SS7[]; +extern CPU cpus_PentiumPro[]; +extern CPU cpus_Slot1_100MHz[]; +extern CPU cpus_VIA_100MHz[]; extern CPU cpus_pcjr[]; +extern CPU cpus_europc[]; extern CPU cpus_pc1512[]; +extern CPU cpus_super286tr[]; extern CPU cpus_ibmat[]; +extern CPU cpus_ibmxt286[]; extern CPU cpus_ps1_m2011[]; extern CPU cpus_ps2_m30_286[]; extern CPU cpus_acer[]; @@ -97,11 +143,23 @@ extern int cpu_iscyrix; extern int cpu_16bitbus; extern int cpu_busspeed; extern int cpu_multi; +/*Cyrix 5x86/6x86 only has data misalignment penalties when crossing 8-byte boundaries*/ +extern int cpu_cyrix_alignment; -extern int cpu_hasrdtsc; -extern int cpu_hasMSR; -extern int cpu_hasMMX; -extern int cpu_hasCR4; +#define CPU_FEATURE_RDTSC (1 << 0) +#define CPU_FEATURE_MSR (1 << 1) +#define CPU_FEATURE_MMX (1 << 2) +#define CPU_FEATURE_CR4 (1 << 3) +#define CPU_FEATURE_VME (1 << 4) +#define CPU_FEATURE_CX8 (1 << 5) +#define CPU_FEATURE_3DNOW (1 << 6) +#define CPU_FEATURE_SYSCALL (1 << 7) + +extern uint32_t cpu_features; +static inline int cpu_has_feature(int feature) +{ + return cpu_features & feature; +} #define CR4_TSD (1 << 2) #define CR4_DE (1 << 3) @@ -114,7 +172,7 @@ extern uint64_t cpu_CR4_mask; #define CPU_REQUIRES_DYNAREC 2 extern int cpu_cycles_read, cpu_cycles_read_l, cpu_cycles_write, cpu_cycles_write_l; -extern int cpu_prefetch_cycles, cpu_prefetch_width; +extern int cpu_prefetch_cycles, cpu_prefetch_width, cpu_mem_prefetch_cycles, cpu_rom_prefetch_cycles; extern int cpu_waitstates; extern int cpu_cache_int_enabled, cpu_cache_ext_enabled; @@ -124,6 +182,8 @@ void cyrix_write(uint16_t addr, uint8_t val, void *priv); uint8_t cyrix_read(uint16_t addr, void *priv); extern int is8086; +extern int is486; +extern int CPUID; void cpu_CPUID(); void cpu_RDMSR(); @@ -131,14 +191,25 @@ void cpu_WRMSR(); extern int cpu_use_dynarec; -extern int xt_cpu_multi; +extern uint64_t xt_cpu_multi; -#define ISA_CYCLES_SHIFT 6 extern int isa_cycles; -#define ISA_CYCLES(x) ((x * isa_cycles) >> ISA_CYCLES_SHIFT) +#define ISA_CYCLES(x) (x * isa_cycles) +#define CPU_CLOCK_DIVIDER_MAX 16384 void cpu_update_waitstates(); void cpu_set(); void cpu_set_edx(); +void cpu_set_turbo(int turbo); +int cpu_get_turbo(); +void cpu_set_nonturbo_divider(int divider); +int cpu_get_speed(); + +extern int has_vlb; + +int fpu_get_type(int model, int manu, int cpu, const char *internal_name); +const char *fpu_get_internal_name(int model, int manu, int cpu, int type); +const char *fpu_get_name_from_index(int model, int manu, int cpu, int c); +int fpu_get_type_from_index(int model, int manu, int cpu, int c); #endif diff --git a/src/cpu_tables.c b/src/cpu_tables.c new file mode 100644 index 0000000..c0bd920 --- /dev/null +++ b/src/cpu_tables.c @@ -0,0 +1,551 @@ +#include "ibm.h" +#include "cpu.h" + +/*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 +*/ + +FPU fpus_none[] = +{ + {"None", "none", FPU_NONE}, + {NULL, NULL, 0} +}; +FPU fpus_8088[] = +{ + {"None", "none", FPU_NONE}, + {"8087", "8087", FPU_8087}, + {NULL, NULL, 0} +}; +FPU fpus_80286[] = +{ + {"None", "none", FPU_NONE}, + {"287", "287", FPU_287}, + {"287XL", "287xl", FPU_287XL}, + {NULL, NULL, 0} +}; +FPU fpus_80386[] = +{ + {"None", "none", FPU_NONE}, + {"387", "387", FPU_387}, + {NULL, NULL, 0} +}; +FPU fpus_builtin[] = +{ + {"Built-in", "builtin", FPU_BUILTIN}, + {NULL, NULL, 0} +}; + +CPU cpus_8088[] = +{ + /*8088 standard*/ + {"8088/4.77", CPU_8088, fpus_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, fpus_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/8", CPU_8088, fpus_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/10", CPU_8088, fpus_8088, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/12", CPU_8088, fpus_8088, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/16", CPU_8088, fpus_8088, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_pcjr[] = +{ + /*8088 PCjr*/ + {"8088/4.77", CPU_8088, fpus_none, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_europc[] = +{ + /*8088 EuroPC*/ + {"8088/4.77", CPU_8088, fpus_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, fpus_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/9.54", CPU_8088, fpus_8088, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_8086[] = +{ + /*8086 standard*/ + {"8086/7.16", CPU_8086, fpus_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/8", CPU_8086, fpus_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/9.54", CPU_8086, fpus_8088, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/10", CPU_8086, fpus_8088, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/12", CPU_8086, fpus_8088, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/16", CPU_8086, fpus_8088, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_pc1512[] = +{ + /*8086 Amstrad*/ + {"8086/8", CPU_8086, fpus_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_286[] = +{ + /*286*/ + {"286/6", CPU_286, fpus_80286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/8", CPU_286, fpus_80286, 1, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/10", CPU_286, fpus_80286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, fpus_80286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, fpus_80286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, fpus_80286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, fpus_80286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_super286tr[] = +{ + /*286*/ + {"286/12", CPU_286, fpus_80286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ibmat[] = +{ + /*286*/ + {"286/6", CPU_286, fpus_80286, 0, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"286/8", CPU_286, fpus_80286, 0, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ibmxt286[] = +{ + /*286*/ + {"286/6", CPU_286, fpus_80286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ps1_m2011[] = +{ + /*286*/ + {"286/10", CPU_286, fpus_80286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ps2_m30_286[] = +{ + /*286*/ + {"286/10", CPU_286, fpus_80286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, fpus_80286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, fpus_80286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, fpus_80286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, fpus_80286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_i386SX[] = +{ + /*i386SX*/ + {"i386SX/16", CPU_386SX, fpus_80386, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"i386SX/20", CPU_386SX, fpus_80386, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/25", CPU_386SX, fpus_80386, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/33", CPU_386SX, fpus_80386, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_i386DX[] = +{ + /*i386DX*/ + {"i386DX/16", CPU_386DX, fpus_80386, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, + {"i386DX/20", CPU_386DX, fpus_80386, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/25", CPU_386DX, fpus_80386, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/33", CPU_386DX, fpus_80386, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_acer[] = +{ + /*i386SX*/ + {"i386SX/25", CPU_386SX, fpus_80386, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am386SX[] = +{ + /*Am386*/ + {"Am386SX/16", CPU_386SX, fpus_80386, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"Am386SX/20", CPU_386SX, fpus_80386, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/25", CPU_386SX, fpus_80386, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/33", CPU_386SX, fpus_80386, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386SX/40", CPU_386SX, fpus_80386, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am386DX[] = +{ + /*Am386*/ + {"Am386DX/25", CPU_386DX, fpus_80386, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386DX/33", CPU_386DX, fpus_80386, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386DX/40", CPU_386DX, fpus_80386, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_486SLC[] = +{ + /*Cx486SLC*/ + {"Cx486SLC/20", CPU_486SLC, fpus_80386, 1, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/25", CPU_486SLC, fpus_80386, 2, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/33", CPU_486SLC, fpus_80386, 3, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, + {"Cx486SRx2/32", CPU_486SLC, fpus_80386, 3, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 2*2}, + {"Cx486SRx2/40", CPU_486SLC, fpus_80386, 4, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 2*3}, + {"Cx486SRx2/50", CPU_486SLC, fpus_80386, 5, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 2*3}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_486DLC[] = +{ + /*Cx486DLC*/ + {"Cx486DLC/25", CPU_486DLC, fpus_80386, 2, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4,4,3,3, 3}, + {"Cx486DLC/33", CPU_486DLC, fpus_80386, 3, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6,6,3,3, 4}, + {"Cx486DLC/40", CPU_486DLC, fpus_80386, 4, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7,7,3,3, 5}, + {"Cx486DRx2/32", CPU_486DLC, fpus_80386, 3, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6,6,6,6, 2*2}, + {"Cx486DRx2/40", CPU_486DLC, fpus_80386, 4, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 2*3}, + {"Cx486DRx2/50", CPU_486DLC, fpus_80386, 5, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 2*3}, + {"Cx486DRx2/66", CPU_486DLC, fpus_80386, 6, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 2*4}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_i486[] = +{ + /*i486*/ + {"i486SX/16", CPU_i486SX, fpus_none, 0, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3,3,3,3, 2}, + {"i486SX/20", CPU_i486SX, fpus_none, 1, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"i486SX/25", CPU_i486SX, fpus_none, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"i486SX/33", CPU_i486SX, fpus_none, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"i486SX2/50", CPU_i486SX, fpus_none, 5, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3}, + {"i486DX/25", CPU_i486DX, fpus_builtin, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"i486DX/33", CPU_i486DX, fpus_builtin, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"i486DX/50", CPU_i486DX, fpus_builtin, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, 6}, + {"i486DX2/40", CPU_i486DX, fpus_builtin, 4, 40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3}, + {"i486DX2/50", CPU_i486DX, fpus_builtin, 5, 50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3}, + {"i486DX2/66", CPU_i486DX, fpus_builtin, 6, 66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*4}, + {"iDX4/75", CPU_iDX4, fpus_builtin, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 3*3}, /*CPUID available on DX4, >= 75 MHz*/ + {"iDX4/100", CPU_iDX4, fpus_builtin, 10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*4}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ + {"Pentium OverDrive/63", CPU_PENTIUM, fpus_builtin, 6, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, (5*3)/2}, + {"Pentium OverDrive/83", CPU_PENTIUM, fpus_builtin, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, (5*4)/2}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am486[] = +{ + /*Am486/5x86*/ + {"Am486SX/33", CPU_Am486SX, fpus_none, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"Am486SX/40", CPU_Am486SX, fpus_none, 4, 40000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"Am486SX2/50", CPU_Am486SX, fpus_none, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, fpus_none, 6, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*4}, /*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, fpus_builtin, 3, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"Am486DX/40", CPU_Am486DX, fpus_builtin, 4, 40000000, 1, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"Am486DX2/50", CPU_Am486DX, fpus_builtin, 5, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3}, + {"Am486DX2/66", CPU_Am486DX, fpus_builtin, 6, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*4}, + {"Am486DX2/80", CPU_Am486DX, fpus_builtin, 8, 80000000, 2, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14,6,6, 2*5}, + {"Am486DX4/75", CPU_Am486DX, fpus_builtin, 7, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 3*3}, + {"Am486DX4/90", CPU_Am486DX, fpus_builtin, 9, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 3*4}, + {"Am486DX4/100", CPU_Am486DX, fpus_builtin, 10, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 3*4}, + {"Am486DX4/120", CPU_Am486DX, fpus_builtin, 11, 120000000, 3, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 3*5}, + {"Am5x86/P75", CPU_Am486DX, fpus_builtin, 12, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 4*4}, + {"Am5x86/P75+", CPU_Am486DX, fpus_builtin, 13, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 4*5}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Cx486[] = +{ + /*Cx486/5x86*/ + {"Cx486S/25", CPU_Cx486S, fpus_none, 2, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"Cx486S/33", CPU_Cx486S, fpus_none, 3, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"Cx486S/40", CPU_Cx486S, fpus_none, 4, 40000000, 1, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"Cx486DX/33", CPU_Cx486DX, fpus_builtin, 3, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"Cx486DX/40", CPU_Cx486DX, fpus_builtin, 4, 40000000, 1, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"Cx486DX2/50", CPU_Cx486DX, fpus_builtin, 5, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 2*3}, + {"Cx486DX2/66", CPU_Cx486DX, fpus_builtin, 6, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*4}, + {"Cx486DX2/80", CPU_Cx486DX, fpus_builtin, 8, 80000000, 2, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14,16,16, 2*5}, + {"Cx486DX4/75", CPU_Cx486DX, fpus_builtin, 7, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 3*3}, + {"Cx486DX4/100", CPU_Cx486DX, fpus_builtin, 10, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 3*4}, + {"Cx5x86/100", CPU_Cx5x86, fpus_builtin, 10, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 3*4}, + {"Cx5x86/120", CPU_Cx5x86, fpus_builtin, 11, 120000000, 3, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 3*5}, + {"Cx5x86/133", CPU_Cx5x86, fpus_builtin, 12, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 4*4}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_6x86[] = +{ + /*Cyrix 6x86*/ + {"6x86-P90", CPU_Cx6x86, fpus_builtin, 17, 80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8,8,6,6, 2*5}, + {"6x86-PR120+", CPU_Cx6x86, fpus_builtin, 17, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*6}, + {"6x86-PR133+", CPU_Cx6x86, fpus_builtin, 17, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*7}, + {"6x86-PR150+", CPU_Cx6x86, fpus_builtin, 17, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7}, + {"6x86-PR166+", CPU_Cx6x86, fpus_builtin, 17, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"6x86-PR200+", CPU_Cx6x86, fpus_builtin, 17, 150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*9}, + + /*Cyrix 6x86L*/ + {"6x86L-PR133+", CPU_Cx6x86L, fpus_builtin, 19, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*7}, + {"6x86L-PR150+", CPU_Cx6x86L, fpus_builtin, 19, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7}, + {"6x86L-PR166+", CPU_Cx6x86L, fpus_builtin, 19, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"6x86L-PR200+", CPU_Cx6x86L, fpus_builtin, 19, 150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*9}, + + /*Cyrix 6x86MX*/ + {"6x86MX-PR166", CPU_Cx6x86MX, fpus_builtin, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"6x86MX-PR200", CPU_Cx6x86MX, fpus_builtin, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"6x86MX-PR233", CPU_Cx6x86MX, fpus_builtin, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*9)/2}, + {"6x86MX-PR266", CPU_Cx6x86MX, fpus_builtin, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, (5*10)/2}, + + /*Cyrix M II*/ + {"M II-200", CPU_Cx6x86MX, fpus_builtin, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0854, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"M II-233", CPU_Cx6x86MX, fpus_builtin, 18, 188888888, 3, 37500000, 0x601, 0x601, 0x0854, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*9)/2}, + {"M II-266", CPU_Cx6x86MX, fpus_builtin, 18, 207500000, 3, 41666667, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, (5*10)/2}, + {"M II-300", CPU_Cx6x86MX, fpus_builtin, 18, 233333333, 3, 33333333, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,7,7, (7*8)/2}, + {"M II-333", CPU_Cx6x86MX, fpus_builtin, 18, 250000000, 3, 41666667, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20,9,9, 3*10}, + + {"", -1, 0, 0, 0} +}; + +CPU cpus_6x86_SS7[] = +{ + /*Cyrix 6x86*/ + {"6x86-P90", CPU_Cx6x86, fpus_builtin, 17, 80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8,8,6,6, 2*5}, + {"6x86-PR120+", CPU_Cx6x86, fpus_builtin, 17, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*6}, + {"6x86-PR133+", CPU_Cx6x86, fpus_builtin, 17, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*7}, + {"6x86-PR150+", CPU_Cx6x86, fpus_builtin, 17, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7}, + {"6x86-PR166+", CPU_Cx6x86, fpus_builtin, 17, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"6x86-PR200+", CPU_Cx6x86, fpus_builtin, 17, 150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*9}, + + /*Cyrix 6x86L*/ + {"6x86L-PR133+", CPU_Cx6x86L, fpus_builtin, 19, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*7}, + {"6x86L-PR150+", CPU_Cx6x86L, fpus_builtin, 19, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7}, + {"6x86L-PR166+", CPU_Cx6x86L, fpus_builtin, 19, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"6x86L-PR200+", CPU_Cx6x86L, fpus_builtin, 19, 150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*9}, + + /*Cyrix 6x86MX*/ + {"6x86MX-PR166", CPU_Cx6x86MX, fpus_builtin, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"6x86MX-PR200", CPU_Cx6x86MX, fpus_builtin, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"6x86MX-PR233", CPU_Cx6x86MX, fpus_builtin, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*9)/2}, + {"6x86MX-PR266", CPU_Cx6x86MX, fpus_builtin, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, (5*10)/2}, + + /*Cyrix M II*/ + {"M II-200", CPU_Cx6x86MX, fpus_builtin, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0854, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"M II-233", CPU_Cx6x86MX, fpus_builtin, 18, 188888888, 3, 37500000, 0x601, 0x601, 0x0854, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*9)/2}, + {"M II-266", CPU_Cx6x86MX, fpus_builtin, 18, 207500000, 3, 41666667, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, (5*10)/2}, + {"M II-300", CPU_Cx6x86MX, fpus_builtin, 18, 233333333, 3, 33333333, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,7,7, (7*8)/2}, + {"M II-333", CPU_Cx6x86MX, fpus_builtin, 18, 250000000, 3, 41666667, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20,9,9, 3*10}, + {"M II-366", CPU_Cx6x86MX, fpus_builtin, 18, 250000000, 3, 33333333, 0x601, 0x601, 0x0852, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 3*10}, + {"M II-400", CPU_Cx6x86MX, fpus_builtin, 18, 285000000, 3, 31666667, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*11}, + {"M II-433", CPU_Cx6x86MX, fpus_builtin, 18, 300000000, 3, 33333333, 0x601, 0x601, 0x0853, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*12}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_WinChip[] = +{ + /*IDT WinChip*/ + {"WinChip 75", CPU_WINCHIP, fpus_builtin, 7, 75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, (3*6)/2}, + {"WinChip 90", CPU_WINCHIP, fpus_builtin, 9, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, (3*7)/2}, + {"WinChip 100", CPU_WINCHIP, fpus_builtin, 10, 100000000, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, (3*8)/2}, + {"WinChip 120", CPU_WINCHIP, fpus_builtin, 11, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*7}, + {"WinChip 133", CPU_WINCHIP, fpus_builtin, 12, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 2*8}, + {"WinChip 150", CPU_WINCHIP, fpus_builtin, 13, 150000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, (5*7)/2}, + {"WinChip 166", CPU_WINCHIP, fpus_builtin, 15, 166666666, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, (5*8)/2}, + {"WinChip 180", CPU_WINCHIP, fpus_builtin, 16, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*7}, + {"WinChip 200", CPU_WINCHIP, fpus_builtin, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*8}, + {"WinChip 240", CPU_WINCHIP, fpus_builtin, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 4*7}, + {"WinChip 2/200", CPU_WINCHIP2, fpus_builtin, 17, 200000000, 3, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*8}, + {"WinChip 2/240", CPU_WINCHIP2, fpus_builtin, 17, 240000000, 6, 30000000, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 30}, + {"WinChip 2A/200", CPU_WINCHIP2, fpus_builtin, 17, 200000000, 3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*8}, + {"WinChip 2A/233", CPU_WINCHIP2, fpus_builtin, 17, 233333333, 3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, (7*8)/2}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_WinChip_SS7[] = +{ + /*IDT WinChip (Super Socket 7)*/ + {"WinChip 200", CPU_WINCHIP, fpus_builtin, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*8}, + {"WinChip 225", CPU_WINCHIP, fpus_builtin, 17, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*9}, + {"WinChip 240", CPU_WINCHIP, fpus_builtin, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 4*7}, + {"WinChip 2/200", CPU_WINCHIP2, fpus_builtin, 17, 200000000, 3, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*8}, + {"WinChip 2/225", CPU_WINCHIP2, fpus_builtin, 17, 225000000, 3, 37500000, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 3*9}, + {"WinChip 2/240", CPU_WINCHIP2, fpus_builtin, 17, 240000000, 6, 30000000, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 30}, + {"WinChip 2/250", CPU_WINCHIP2, fpus_builtin, 17, 250000000, 6, 41666667, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 30}, + {"WinChip 2A/200", CPU_WINCHIP2, fpus_builtin, 17, 200000000, 3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 24}, + {"WinChip 2A/233", CPU_WINCHIP2, fpus_builtin, 17, 233333333, 3, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 28}, + {"WinChip 2A/266", CPU_WINCHIP2, fpus_builtin, 17, 233333333, 6, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 28}, + {"WinChip 2A/300", CPU_WINCHIP2, fpus_builtin, 17, 250000000, 6, 33333333, 0x587, 0x587, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 30}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium5V[] = +{ + /*Intel Pentium (5V, socket 4)*/ + {"Pentium 60", CPU_PENTIUM, fpus_builtin, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, + {"Pentium 66", CPU_PENTIUM, fpus_builtin, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, + {"Pentium OverDrive 120", CPU_PENTIUM, fpus_builtin, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7}, + {"Pentium OverDrive 133", CPU_PENTIUM, fpus_builtin, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_PentiumS5[] = +{ + /*Intel Pentium (Socket 5)*/ + {"Pentium 75", CPU_PENTIUM, fpus_builtin, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, (3*6)/2}, + {"Pentium 90", CPU_PENTIUM, fpus_builtin, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, (3*7)/2}, + {"Pentium 100/50", CPU_PENTIUM, fpus_builtin, 13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*6}, + {"Pentium 100/66", CPU_PENTIUM, fpus_builtin, 13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, (3*8)/2}, + {"Pentium 120", CPU_PENTIUM, fpus_builtin, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7}, + {"Pentium 133", CPU_PENTIUM, fpus_builtin, 16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"Pentium OverDrive 125",CPU_PENTIUM,fpus_builtin, 15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, (5*6)/2}, + {"Pentium OverDrive 150",CPU_PENTIUM,fpus_builtin, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2}, + {"Pentium OverDrive 166",CPU_PENTIUM,fpus_builtin, 17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, fpus_builtin, 15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, (5*6)/2}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, fpus_builtin, 17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, fpus_builtin, 19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, fpus_builtin, 20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*7}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, fpus_builtin, 21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium[] = +{ + /*Intel Pentium*/ + {"Pentium 75", CPU_PENTIUM, fpus_builtin, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, (3*6)/2}, + {"Pentium 90", CPU_PENTIUM, fpus_builtin, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, (3*7)/2}, + {"Pentium 100/50", CPU_PENTIUM, fpus_builtin, 13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 2*6}, + {"Pentium 100/66", CPU_PENTIUM, fpus_builtin, 13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, (3*8)/2}, + {"Pentium 120", CPU_PENTIUM, fpus_builtin, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7}, + {"Pentium 133", CPU_PENTIUM, fpus_builtin, 16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"Pentium 150", CPU_PENTIUM, fpus_builtin, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2}, + {"Pentium 166", CPU_PENTIUM, fpus_builtin, 19, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"Pentium 200", CPU_PENTIUM, fpus_builtin, 21, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8}, + {"Pentium MMX 166", CPU_PENTIUMMMX, fpus_builtin, 19, 166666666, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"Pentium MMX 200", CPU_PENTIUMMMX, fpus_builtin, 21, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8}, + {"Pentium MMX 233", CPU_PENTIUMMMX, fpus_builtin, 24, 233333333, 4, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, (7*8)/2}, + {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, fpus_builtin, 14, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*7}, + {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, fpus_builtin, 16, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 2*8}, + {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, fpus_builtin, 17, 150000000, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2}, + {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, fpus_builtin, 19, 166666666, 3, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, fpus_builtin, 21, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8}, + {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, fpus_builtin, 24, 233333333, 4, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, (7*8)/2}, + {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, fpus_builtin, 26, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 4*8}, + {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, fpus_builtin, 28, 300000000, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, (9*8)/2}, + {"Pentium OverDrive 125", CPU_PENTIUM, fpus_builtin, 15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, (5*6)/2}, + {"Pentium OverDrive 150", CPU_PENTIUM, fpus_builtin, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2}, + {"Pentium OverDrive 166", CPU_PENTIUM, fpus_builtin, 17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX, fpus_builtin, 15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, (5*6)/2}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX, fpus_builtin, 17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX, fpus_builtin, 19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX, fpus_builtin, 20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*7}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX, fpus_builtin, 21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_K6_S7[] = +{ + /*AMD K6*/ + {"K6/166", CPU_K6, fpus_builtin, 19, 166666666, 3, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"K6/200", CPU_K6, fpus_builtin, 21, 200000000, 3, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"K6/233", CPU_K6, fpus_builtin, 24, 233333333, 4, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"K6/266", CPU_K6, fpus_builtin, 26, 266666666, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"K6/300", CPU_K6, fpus_builtin, 28, 300000000, 5, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"K6-2/233", CPU_K6_2, fpus_builtin, 24, 233333333, 4, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"K6-2/266", CPU_K6_2, fpus_builtin, 26, 266666666, 4, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"K6-2/300 AFR-66", CPU_K6_2, fpus_builtin, 28, 300000000, 5, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_K6_SS7[] = +{ + /*AMD K6*/ + {"K6/166", CPU_K6, fpus_builtin, 19, 166666666, 3, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"K6/200", CPU_K6, fpus_builtin, 21, 200000000, 3, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"K6/233", CPU_K6, fpus_builtin, 24, 233333333, 4, 33333333, 0x561, 0x561, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"K6/266", CPU_K6, fpus_builtin, 26, 266666666, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"K6/300", CPU_K6, fpus_builtin, 28, 300000000, 5, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"K6-2/233", CPU_K6_2, fpus_builtin, 24, 233333333, 4, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"K6-2/266", CPU_K6_2, fpus_builtin, 26, 266666666, 4, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"K6-2/300", CPU_K6_2, fpus_builtin, 28, 300000000, 5, 33333333, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"K6-2/333", CPU_K6_2, fpus_builtin, 28, 333333333, 5, 31666667, 0x580, 0x580, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, + {"K6-2/350", CPU_K6_2, fpus_builtin, 28, 350000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 42}, + {"K6-2/366", CPU_K6_2, fpus_builtin, 28, 366666666, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 44}, + {"K6-2/380", CPU_K6_2, fpus_builtin, 28, 380000000, 5, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 46}, + {"K6-2/400", CPU_K6_2, fpus_builtin, 28, 400000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 48}, + {"K6-2/450", CPU_K6_2, fpus_builtin, 28, 450000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 54}, + {"K6-2/475", CPU_K6_2, fpus_builtin, 28, 475000000, 5, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 57}, + {"K6-2/500", CPU_K6_2, fpus_builtin, 28, 500000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 60}, + {"K6-2/533", CPU_K6_2, fpus_builtin, 28, 533333333, 5, 31666667, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 64}, + {"K6-2/550", CPU_K6_2, fpus_builtin, 28, 550000000, 5, 33333333, 0x58c, 0x58c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 66}, + {"K6-2+/450", CPU_K6_2P, fpus_builtin, 28, 450000000, 5, 33333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 54}, + {"K6-2+/475", CPU_K6_2P, fpus_builtin, 28, 475000000, 5, 31666667, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 57}, + {"K6-2+/500", CPU_K6_2P, fpus_builtin, 28, 500000000, 5, 33333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 60}, + {"K6-2+/533", CPU_K6_2P, fpus_builtin, 28, 533333333, 5, 31666667, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 64}, + {"K6-2+/550", CPU_K6_2P, fpus_builtin, 28, 550000000, 5, 33333333, 0x5d4, 0x5d4, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 66}, + {"K6-III/400", CPU_K6_3, fpus_builtin, 28, 400000000, 5, 33333333, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 48}, + {"K6-III/450", CPU_K6_3, fpus_builtin, 28, 450000000, 5, 33333333, 0x591, 0x591, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 54}, + {"K6-III+/400", CPU_K6_3P, fpus_builtin, 28, 400000000, 5, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 48}, + {"K6-III+/450", CPU_K6_3P, fpus_builtin, 28, 450000000, 5, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 54}, + {"K6-III+/475", CPU_K6_3P, fpus_builtin, 28, 475000000, 5, 31666667, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 57}, + {"K6-III+/500", CPU_K6_3P, fpus_builtin, 28, 500000000, 5, 33333333, 0x5d0, 0x5d0, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 60}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_PentiumPro[] = +{ + /*Intel Pentium Pro*/ + {"Pentium Pro 150", CPU_PENTIUMPRO, fpus_builtin, 17, 150000000, 3, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*7)/2}, + {"Pentium Pro 166", CPU_PENTIUMPRO, fpus_builtin, 19, 166666666, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, (5*8)/2}, + {"Pentium Pro 180", CPU_PENTIUMPRO, fpus_builtin, 20, 180000000, 3, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8}, + {"Pentium Pro 200", CPU_PENTIUMPRO, fpus_builtin, 21, 200000000, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 3*8}, + {"Pentium II Overdrive 300", CPU_PENTIUM_2, fpus_builtin, 20, 300000000, 3, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 36}, + {"Pentium II Overdrive 333", CPU_PENTIUM_2, fpus_builtin, 21, 333333333, 3, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 40}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Slot1_100MHz[] = +{ + /*Intel Pentium II*/ + {"Pentium II/233", CPU_PENTIUM_2, fpus_builtin, 20, 233333333, 3, 33333333, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 28}, + {"Pentium II/266", CPU_PENTIUM_2, fpus_builtin, 20, 266666666, 3, 33333333, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 32}, + {"Pentium II/300", CPU_PENTIUM_2, fpus_builtin, 20, 300000000, 3, 33333333, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 36}, + {"Pentium II/333", CPU_PENTIUM_2, fpus_builtin, 20, 333333333, 3, 33333333, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 40}, + {"Pentium II/350", CPU_PENTIUM_2, fpus_builtin, 20, 350000000, 3, 33333333, 0x651, 0x651, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 42}, + {"Pentium II/400", CPU_PENTIUM_2, fpus_builtin, 20, 400000000, 3, 33333333, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 48}, + {"Pentium II/450", CPU_PENTIUM_2, fpus_builtin, 20, 450000000, 3, 33333333, 0x652, 0x652, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 54}, + {"Celeron 266", CPU_CELERON, fpus_builtin, 20, 266666666, 3, 33333333, 0x650, 0x650, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 32}, + {"Celeron 300", CPU_CELERON, fpus_builtin, 20, 300000000, 3, 33333333, 0x650, 0x650, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 36}, + {"Celeron-A 300", CPU_CELERON_A, fpus_builtin, 20, 300000000, 3, 33333333, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 40}, + {"Celeron 333", CPU_CELERON_A, fpus_builtin, 20, 333333333, 3, 33333333, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 44}, + {"Celeron 366", CPU_CELERON_A, fpus_builtin, 20, 366666666, 3, 33333333, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 48}, + {"Celeron 400", CPU_CELERON_A, fpus_builtin, 20, 400000000, 3, 33333333, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 52}, + {"Celeron 433", CPU_CELERON_A, fpus_builtin, 20, 433333333, 3, 33333333, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 56}, + {"Celeron 466", CPU_CELERON_A, fpus_builtin, 20, 466666666, 3, 33333333, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 60}, + {"Celeron 500", CPU_CELERON_A, fpus_builtin, 20, 500000000, 3, 33333333, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 64}, + {"Celeron 533", CPU_CELERON_A, fpus_builtin, 20, 533333333, 3, 33333333, 0x660, 0x660, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 68}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_VIA_100MHz[] = +{ + /*VIA Cyrix III*/ + {"Cyrix III/500", CPU_CYRIX_III, fpus_builtin, 20, 500000000, 3, 33333333, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 64}, +/*Below are disabled as Windows 98 won't boot. This is most likely a limitation of the timer system*/ +/* {"Cyrix III/550", CPU_CYRIX_III, fpus_builtin, 20, 550000000, 3, 33333333, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 70}, + {"Cyrix III/600", CPU_CYRIX_III, fpus_builtin, 20, 600000000, 3, 33333333, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 76}, + {"Cyrix III/650", CPU_CYRIX_III, fpus_builtin, 20, 650000000, 3, 33333333, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 82}, + {"Cyrix III/700", CPU_CYRIX_III, fpus_builtin, 20, 700000000, 3, 33333333, 0x663, 0x663, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 88}, + {"C3/750", CPU_CYRIX_III, fpus_builtin, 20, 750000000, 3, 33333333, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 94}, + {"C3/800", CPU_CYRIX_III, fpus_builtin, 20, 800000000, 3, 33333333, 0x673, 0x673, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 100},*/ + {"", -1, 0, 0, 0} +}; diff --git a/src/cs8230.c b/src/cs8230.c new file mode 100644 index 0000000..c2125ed --- /dev/null +++ b/src/cs8230.c @@ -0,0 +1,120 @@ +/*CS8230 CHIPSet consists of : + 82c301 bus controller + 82c302 page/interleave memory controller + 82a303 high address buffer + 82a304 low address buffer + 82b305 data buffer + 82a306 control buffer*/ +#include "ibm.h" +#include "cs8230.h" +#include "io.h" +#include "mem.h" + +static struct +{ + int idx; + uint8_t regs[256]; +} cs8230; + +static void shadow_control(uint32_t addr, uint32_t size, int state) +{ +// pclog("shadow_control: addr=%08x size=%04x state=%02x\n", addr, size, state); + switch (state) + { + case 0x00: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x01: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x10: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x11: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + } + flushmmucache_nopc(); +} + +static void rethink_shadow_mappings(void) +{ + int c; + + for (c = 0; c < 4*8; c++) /*Addresses 40000-bffff in 16k blocks*/ + { + if (cs8230.regs[0xa + (c >> 3)] & (1 << (c & 7))) + mem_set_mem_state(0x40000 + c*0x4000, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); /*IO channel*/ + else + mem_set_mem_state(0x40000 + c*0x4000, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); /*System board*/ + } + for (c = 0; c < 2*8; c++) /*Addresses c0000-fffff in 16k blocks. System board ROM can be mapped here*/ + { + if (cs8230.regs[0xe + (c >> 3)] & (1 << (c & 7))) + mem_set_mem_state(0xc0000 + c*0x4000, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); /*IO channel*/ + else + shadow_control(0xc0000 + c*0x4000, 0x4000, (cs8230.regs[9] >> (3-(c >> 2))) & 0x11); + } +} + +static uint8_t cs8230_read(uint16_t port, void *p) +{ + uint8_t ret = 0xff; + + if (port & 1) + { + switch (cs8230.idx) + { + case 0x04: /*82C301 ID/version*/ + ret = cs8230.regs[cs8230.idx] & ~0xe3; + break; + + case 0x08: /*82C302 ID/Version*/ + ret = cs8230.regs[cs8230.idx] & ~0xe0; + break; + + case 0x05: case 0x06: /*82C301 registers*/ + case 0x09: case 0x0a: case 0x0b: case 0x0c: /*82C302 registers*/ + case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x28: case 0x29: case 0x2a: + ret = cs8230.regs[cs8230.idx]; + break; + } + } + + return ret; +} + +static void cs8230_write(uint16_t port, uint8_t val, void *p) +{ + if (!(port & 1)) + cs8230.idx = val; + else + { +// pclog("cs8230_write: reg=%02x val=%02x\n", cs8230.idx, val); + cs8230.regs[cs8230.idx] = val; + switch (cs8230.idx) + { + case 0x09: /*RAM/ROM Configuration in boot area*/ + case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f: /*Address maps*/ + rethink_shadow_mappings(); + break; + } + } +} + +void cs8230_init(void) +{ + memset(&cs8230, 0, sizeof(cs8230)); + + io_sethandler(0x0022, 0x0002, + cs8230_read, NULL, NULL, + cs8230_write, NULL, NULL, + NULL); + if (mem_size > 768) + { + mem_mapping_set_addr(&ram_mid_mapping, 0xa0000, mem_size > 1024 ? 0x60000 : 0x20000 + (mem_size - 768) * 1024); + mem_mapping_set_exec(&ram_mid_mapping, ram + 0xa0000); + } +} diff --git a/src/cs8230.h b/src/cs8230.h new file mode 100644 index 0000000..d4bd4a0 --- /dev/null +++ b/src/cs8230.h @@ -0,0 +1 @@ +void cs8230_init(void); diff --git a/src/dac.c b/src/dac.c deleted file mode 100644 index b24561b..0000000 --- a/src/dac.c +++ /dev/null @@ -1,69 +0,0 @@ -#include "ibm.h" -#include "dac.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;cname; if (d->init != NULL) { @@ -37,6 +39,7 @@ void device_add(device_t *d) devices[c] = d; device_priv[c] = priv; + current_device_name = NULL; } void device_close_all() diff --git a/src/device.h b/src/device.h index 0e2dd8c..38a46bc 100644 --- a/src/device.h +++ b/src/device.h @@ -1,3 +1,6 @@ +#ifndef _DEVICE_H_ +#define _DEVICE_H_ + #define CONFIG_STRING 0 #define CONFIG_INT 1 #define CONFIG_BINARY 2 @@ -41,6 +44,8 @@ void device_speed_changed(); void device_force_redraw(); void device_add_status_info(char *s, int max_len); +extern char *current_device_name; + int device_get_config_int(char *name); char *device_get_config_string(char *name); @@ -49,8 +54,11 @@ enum DEVICE_NOT_WORKING = 1, /*Device does not currently work correctly and will be disabled in a release build*/ DEVICE_AT = 2, /*Device requires an AT-compatible system*/ DEVICE_MCA = 0x20, /*Device requires an MCA system*/ - DEVICE_PCI = 0x40 /*Device requires a PCI system*/ + DEVICE_PCI = 0x40, /*Device requires a PCI system*/ + DEVICE_PS1 = 0x80 /*Device is only for IBM PS/1 Model 2011*/ }; int model_get_config_int(char *s); char *model_get_config_string(char *s); + +#endif diff --git a/src/disc.c b/src/disc.c index f4ccb2b..6b76b9b 100644 --- a/src/disc.c +++ b/src/disc.c @@ -9,7 +9,7 @@ #include "timer.h" int disc_drivesel = 0; -int disc_poll_time = 16; +pc_timer_t disc_poll_timer; int disc_track[2]; int writeprot[2], fwriteprot[2]; @@ -22,9 +22,6 @@ int curdrive = 0; //char discfns[2][260] = {"", ""}; int defaultwriteprot = 0; -int fdc_time; -int disc_time; - int fdc_ready; int drive_empty[2] = {1, 1}; @@ -125,7 +122,7 @@ int disc_hole(int drive) { drive ^= fdd_swap; - if (drives[drive].hole) + if (drive < 2 && drives[drive].hole) { return drives[drive].hole(drive); } @@ -137,16 +134,16 @@ int disc_hole(int drive) void disc_poll() { - disc_poll_time += disc_period * TIMER_USEC; + timer_advance_u64(&disc_poll_timer, disc_period * TIMER_USEC); - if (drives[disc_drivesel].poll) + if (disc_drivesel < 2 && drives[disc_drivesel].poll) drives[disc_drivesel].poll(); if (disc_notfound) { disc_notfound--; if (!disc_notfound) - fdc_notfound(); + fdc_notfound(FDC_STATUS_AM_NOT_FOUND); } } @@ -205,17 +202,29 @@ void disc_set_rate(int drive, int drvden, int rate) void disc_reset() { + int drive; + curdrive = 0; disc_period = 32; - timer_add(disc_poll, &disc_poll_time, &motoron, NULL); + timer_add(&disc_poll_timer, disc_poll, NULL, 0); + + for (drive = 0; drive < 2; drive++) + { + if (loaders[driveloaders[drive]].close) + loaders[driveloaders[drive]].close(drive); + drive_empty[drive] = 1; + 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; + } } 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(); } @@ -223,7 +232,7 @@ 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) + if (drive < 2 && drives[drive].seek) drives[drive].seek(drive, track); // if (track != oldtrack[drive]) // fdc_discchange_clear(drive); @@ -235,7 +244,7 @@ void disc_readsector(int drive, int sector, int track, int side, int density, in { drive ^= fdd_swap; - if (drives[drive].readsector) + if (drive < 2 && drives[drive].readsector) drives[drive].readsector(drive, sector, track, side, density, sector_size); else disc_notfound = 1000; @@ -245,7 +254,7 @@ void disc_writesector(int drive, int sector, int track, int side, int density, i { drive ^= fdd_swap; - if (drives[drive].writesector) + if (drive < 2 && drives[drive].writesector) drives[drive].writesector(drive, sector, track, side, density, sector_size); else disc_notfound = 1000; @@ -255,7 +264,7 @@ void disc_readaddress(int drive, int track, int side, int density) { drive ^= fdd_swap; - if (drives[drive].readaddress) + if (drive < 2 && drives[drive].readaddress) drives[drive].readaddress(drive, track, side, density); } @@ -263,7 +272,7 @@ void disc_format(int drive, int track, int side, int density, uint8_t fill) { drive ^= fdd_swap; - if (drives[drive].format) + if (drive < 2 && drives[drive].format) drives[drive].format(drive, track, side, density, fill); else disc_notfound = 1000; @@ -273,7 +282,7 @@ void disc_stop(int drive) { drive ^= fdd_swap; - if (drives[drive].stop) + if (drive < 2 && drives[drive].stop) drives[drive].stop(drive); } @@ -283,3 +292,12 @@ void disc_set_drivesel(int drive) disc_drivesel = drive; } + +void disc_set_motor_enable(int motor_enable) +{ + if (motor_enable && !motoron) + timer_set_delay_u64(&disc_poll_timer, disc_period * TIMER_USEC); + else if (!motor_enable) + timer_disable(&disc_poll_timer); + motoron = motor_enable; +} diff --git a/src/disc.h b/src/disc.h index a0214e4..714af06 100644 --- a/src/disc.h +++ b/src/disc.h @@ -30,23 +30,21 @@ 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; +void disc_set_motor_enable(int motor_enable); extern int disc_drivesel; void fdc_callback(); int fdc_data(uint8_t dat); void fdc_spindown(); void fdc_finishread(); -void fdc_notfound(); +void fdc_notfound(int reason); 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_ready; extern int fdc_indexcount;*/ extern int motorspin; diff --git a/src/disc_fdi.c b/src/disc_fdi.c index 498a623..1393bc2 100644 --- a/src/disc_fdi.c +++ b/src/disc_fdi.c @@ -3,6 +3,7 @@ #include "ibm.h" #include "disc.h" #include "disc_fdi.h" +#include "fdc.h" #include "fdi2raw.h" static struct @@ -314,7 +315,7 @@ void fdi_poll() if (fdi_revs == 3) { // pclog("Not found!\n"); - fdc_notfound(); + fdc_notfound(FDC_STATUS_NOT_FOUND); fdi_inread = fdi_inreadaddr = 0; return; } diff --git a/src/disc_img.c b/src/disc_img.c index 206eaae..c18d45a 100644 --- a/src/disc_img.c +++ b/src/disc_img.c @@ -130,7 +130,7 @@ void img_load(int drive, char *fn) uint8_t bpb_sectors; uint8_t bpb_sides; uint32_t bpt; - uint8_t max_spt; /* Used for XDF detection. */ + uint8_t max_spt = 0; /* Used for XDF detection. */ if (!xdf_maps_initialized) initialize_xdf_maps(); /* Initialize XDF maps, will need them to properly register sectors in tracks. */ diff --git a/src/disc_sector.c b/src/disc_sector.c index 8aad435..26759bf 100644 --- a/src/disc_sector.c +++ b/src/disc_sector.c @@ -46,7 +46,9 @@ static int disc_intersector_delay = 0; static uint8_t disc_sector_fill; static int cur_sector, cur_byte; static int index_count; - + +static int disc_sector_status; + void disc_sector_reset(int drive, int side) { disc_sector_count[drive][side] = 0; @@ -90,6 +92,8 @@ void disc_sector_readsector(int drive, int sector, int track, int side, int rate disc_sector_sector = sector; disc_sector_n = sector_size; index_count = 0; + + disc_sector_status = FDC_STATUS_AM_NOT_FOUND; } void disc_sector_writesector(int drive, int sector, int track, int side, int rate, int sector_size) @@ -103,6 +107,8 @@ void disc_sector_writesector(int drive, int sector, int track, int side, int rat disc_sector_sector = sector; disc_sector_n = sector_size; index_count = 0; + + disc_sector_status = FDC_STATUS_AM_NOT_FOUND; } void disc_sector_readaddress(int drive, int track, int side, int rate) @@ -114,6 +120,8 @@ void disc_sector_readaddress(int drive, int track, int side, int rate) disc_sector_side = side; disc_sector_drive = drive; index_count = 0; + + disc_sector_status = FDC_STATUS_AM_NOT_FOUND; } void disc_sector_format(int drive, int track, int side, int rate, uint8_t fill) @@ -179,7 +187,7 @@ void disc_sector_poll() if (index_count > 1) { // pclog("Find sector not found\n"); - fdc_notfound(); + fdc_notfound(disc_sector_status); disc_sector_state = STATE_IDLE; break; } @@ -187,10 +195,11 @@ void disc_sector_poll() disc_sector_side != s->h, disc_sector_sector != s->r, fdc_get_bitcell_period() != get_bitcell_period());*/ - if (cur_byte || disc_sector_track != s->c || - disc_sector_side != s->h || - disc_sector_sector != s->r || - disc_sector_n != s->n || + if (!cur_byte && fdc_get_bitcell_period() == get_bitcell_period() && + fdd_can_read_medium(disc_sector_drive ^ fdd_swap)) + disc_sector_status = FDC_STATUS_NOT_FOUND; /*Disc readable, assume address marker found*/ + + if (cur_byte || fdc_get_bitcell_period() != get_bitcell_period() || !fdd_can_read_medium(disc_sector_drive ^ fdd_swap) || disc_intersector_delay) @@ -198,6 +207,16 @@ void disc_sector_poll() advance_byte(); break; } + if (disc_sector_track != s->c || + disc_sector_side != s->h || + disc_sector_sector != s->r || + disc_sector_n != s->n) + { + if (disc_sector_track != s->c) + disc_sector_status = (disc_sector_track == 0xff) ? FDC_STATUS_BAD_CYLINDER : FDC_STATUS_WRONG_CYLINDER; + advance_byte(); + break; + } disc_sector_state = STATE_READ_SECTOR; case STATE_READ_SECTOR: // pclog("STATE_READ_SECTOR: cur_byte=%i %i\n", cur_byte, disc_intersector_delay); @@ -218,10 +237,14 @@ void disc_sector_poll() if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap))) { // pclog("Medium is of a density not supported by the drive\n"); - fdc_notfound(); + fdc_notfound(FDC_STATUS_AM_NOT_FOUND); disc_sector_state = STATE_IDLE; break; } + if (!cur_byte && fdc_get_bitcell_period() == get_bitcell_period() && + fdd_can_read_medium(disc_sector_drive ^ fdd_swap)) + disc_sector_status = FDC_STATUS_NOT_FOUND; /*Disc readable, assume address marker found*/ + if (cur_byte || !index_count || fdc_get_bitcell_period() != get_bitcell_period() || disc_intersector_delay) { @@ -244,14 +267,14 @@ void disc_sector_poll() if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap))) { // pclog("Medium is of a density not supported by the drive\n"); - fdc_notfound(); + fdc_notfound(FDC_STATUS_AM_NOT_FOUND); disc_sector_state = STATE_IDLE; break; } if (index_count) { // pclog("Find next sector hit end of track\n"); - fdc_notfound(); + fdc_notfound(disc_sector_status); disc_sector_state = STATE_IDLE; break; } @@ -277,32 +300,45 @@ void disc_sector_poll() if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap))) { // pclog("Medium is of a density not supported by the drive\n"); - fdc_notfound(); + fdc_notfound(FDC_STATUS_AM_NOT_FOUND); disc_sector_state = STATE_IDLE; break; } + + if (!cur_byte && fdc_get_bitcell_period() == get_bitcell_period() && + fdd_can_read_medium(disc_sector_drive ^ fdd_swap)) + disc_sector_status = FDC_STATUS_NOT_FOUND; /*Disc readable, assume address marker found*/ + if (writeprot[disc_sector_drive]) { fdc_writeprotect(); + disc_sector_state = STATE_IDLE; return; } if (index_count > 1) { // pclog("Write find sector not found\n"); - fdc_notfound(); + fdc_notfound(disc_sector_status); disc_sector_state = STATE_IDLE; break; } - if (cur_byte || disc_sector_track != s->c || - disc_sector_side != s->h || - disc_sector_sector != s->r || - disc_sector_n != s->n || + if (cur_byte || fdc_get_bitcell_period() != get_bitcell_period() || disc_intersector_delay) { advance_byte(); break; } + if (disc_sector_track != s->c || + disc_sector_side != s->h || + disc_sector_sector != s->r || + disc_sector_n != s->n) + { + if (disc_sector_track != s->c) + disc_sector_status = (disc_sector_track == 0xff) ? FDC_STATUS_BAD_CYLINDER : FDC_STATUS_WRONG_CYLINDER; + advance_byte(); + break; + } disc_sector_state = STATE_WRITE_SECTOR; case STATE_WRITE_SECTOR: data = fdc_getdata(cur_byte == ((128 << s->n) - 1)); @@ -322,14 +358,19 @@ void disc_sector_poll() if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap))) { // pclog("Medium is of a density not supported by the drive\n"); - fdc_notfound(); + fdc_notfound(FDC_STATUS_AM_NOT_FOUND); disc_sector_state = STATE_IDLE; break; } + + if (!cur_byte && fdc_get_bitcell_period() == get_bitcell_period() && + fdd_can_read_medium(disc_sector_drive ^ fdd_swap)) + disc_sector_status = FDC_STATUS_NOT_FOUND; /*Disc readable, assume address marker found*/ + if (index_count) { // pclog("Find next sector hit end of track\n"); - fdc_notfound(); + fdc_notfound(disc_sector_status); disc_sector_state = STATE_IDLE; break; } @@ -342,6 +383,7 @@ void disc_sector_poll() disc_sector_state = STATE_READ_ADDRESS; case STATE_READ_ADDRESS: fdc_sectorid(s->c, s->h, s->r, s->n, 0, 0); + advance_byte(); disc_sector_state = STATE_IDLE; break; @@ -349,6 +391,7 @@ void disc_sector_poll() if (writeprot[disc_sector_drive]) { fdc_writeprotect(); + disc_sector_state = STATE_IDLE; return; } if (!index_count || fdc_get_bitcell_period() != get_bitcell_period() || @@ -360,13 +403,13 @@ void disc_sector_poll() if (!(fdd_can_read_medium(disc_sector_drive ^ fdd_swap))) { // pclog("Medium is of a density not supported by the drive\n"); - fdc_notfound(); + fdc_notfound(FDC_STATUS_NOT_FOUND); disc_sector_state = STATE_IDLE; break; } if (fdc_get_bitcell_period() != get_bitcell_period()) { - fdc_notfound(); + fdc_notfound(FDC_STATUS_NOT_FOUND); disc_sector_state = STATE_IDLE; break; } diff --git a/src/dma.c b/src/dma.c index eb32dbc..76d88a8 100644 --- a/src/dma.c +++ b/src/dma.c @@ -4,6 +4,7 @@ #include "fdc.h" #include "io.h" #include "mem.h" +#include "ps2_mca.h" #include "video.h" #include "x86.h" @@ -11,57 +12,73 @@ static uint8_t dmaregs[16]; static uint8_t dma16regs[16]; static uint8_t dmapages[16]; +static int dma_wp, dma16_wp; +static uint8_t dma_m; +static uint8_t dma_stat; +static uint8_t dma_stat_rq; +static uint8_t dma_command, dma16_command; + +static struct +{ + int xfr_command, xfr_channel; + int byte_ptr; + + int is_ps2; +} dma_ps2; + +#define DMA_PS2_IOA (1 << 0) +#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) +#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) +#define DMA_PS2_XFER_MASK (3 << 2) +#define DMA_PS2_DEC2 (1 << 4) +#define DMA_PS2_SIZE16 (1 << 6) + +static void dma_ps2_run(int channel); + void dma_reset() { int c; - dma.wp = 0; + + dma_wp = dma16_wp = 0; + dma_m = 0; + for (c = 0; c < 16; c++) dmaregs[c] = 0; - for (c = 0; c < 4; c++) + for (c = 0; c < 8; c++) { - dma.mode[c] = 0; - dma.ac[c] = 0; - dma.cc[c] = 0; - dma.ab[c] = 0; - dma.cb[c] = 0; + dma[c].mode = 0; + dma[c].ac = 0; + dma[c].cc = 0; + dma[c].ab = 0; + dma[c].cb = 0; + dma[c].size = (c & 4) ? 1 : 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) { + int channel = (addr >> 1) & 3; 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) & 0xff; + dma_wp ^= 1; + if (dma_wp) + return dma[channel].ac & 0xff; + return (dma[channel].ac >> 8) & 0xff; 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; + dma_wp ^= 1; + if (dma_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; return temp; case 8: /*Status register*/ - temp = dma.stat; - dma.stat = 0; + temp = dma_stat & 0xf; + dma_stat &= ~0xf; return temp; case 0xd: @@ -73,107 +90,131 @@ uint8_t dma_read(uint16_t addr, void *priv) void dma_write(uint16_t addr, uint8_t val, void *priv) { + int channel = (addr >> 1) & 3; // 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] & 0xffff00) | val; - else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00ff) | (val << 8); - dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3]; + dma_wp ^= 1; + if (dma_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ac = dma[channel].ab; // pclog("Addr = %04x\n", dma.ab[(addr >> 1) & 3]); 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]; + dma_wp ^= 1; + if (dma_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; return; case 8: /*Control register*/ - dma.command = val; + dma_command = val; return; case 0xa: /*Mask*/ - if (val & 4) dma.m |= (1 << (val & 3)); - else dma.m &= ~(1 << (val & 3)); + if (val & 4) + dma_m |= (1 << (val & 3)); + else + dma_m &= ~(1 << (val & 3)); return; case 0xb: /*Mode*/ - dma.mode[val & 3] = val; - if (dma.is_ps2) + channel = (val & 3); + dma[channel].mode = val; + if (dma_ps2.is_ps2) { - dma.ps2_mode[val & 3] &= ~0x1c; + dma[channel].ps2_mode &= ~0x1c; if (val & 0x20) - dma.ps2_mode[val & 3] |= 0x10; + dma[channel].ps2_mode |= 0x10; if ((val & 0xc) == 8) - dma.ps2_mode[val & 3] |= 4; + dma[channel].ps2_mode |= 4; else if ((val & 0xc) == 4) - dma.ps2_mode[val & 3] |= 0xc; + dma[channel].ps2_mode |= 0xc; } return; case 0xc: /*Clear FF*/ - dma.wp = 0; + dma_wp = 0; return; case 0xd: /*Master clear*/ - dma.wp = 0; - dma.m = 0xf; + dma_wp = 0; + dma_m |= 0xf; return; case 0xf: /*Mask write*/ - dma.m = val & 0xf; + dma_m = (dma_m & 0xf0) | (val & 0xf); return; } } static uint8_t dma_ps2_read(uint16_t addr, void *priv) { + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; uint8_t temp = 0xff; switch (addr) { case 0x1a: - switch (dma.xfr_command) + switch (dma_ps2.xfr_command) { case 2: /*Address*/ case 3: - switch (dma.byte_ptr) + switch (dma_ps2.byte_ptr) { case 0: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] & 0xff) : (dma.ac[dma.xfr_channel] & 0xff); - dma.byte_ptr = 1; + temp = dma_c->ac & 0xff; + dma_ps2.byte_ptr = 1; break; case 1: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] >> 8) : (dma.ac[dma.xfr_channel] >> 8); - dma.byte_ptr = 2; + temp = (dma_c->ac >> 8) & 0xff; + dma_ps2.byte_ptr = 2; break; case 2: - temp = (dma.xfr_channel & 4) ? (dma16.ac[dma.xfr_channel & 3] >> 16) : (dma.ac[dma.xfr_channel] >> 16); - dma.byte_ptr = 0; + temp = (dma_c->ac >> 16) & 0xff; + dma_ps2.byte_ptr = 0; break; } break; case 4: /*Count*/ case 5: - if (dma.byte_ptr) - temp = (dma.xfr_channel & 4) ? (dma16.cc[dma.xfr_channel & 3] >> 8) : (dma.cc[dma.xfr_channel] >> 8); + if (dma_ps2.byte_ptr) + temp = dma_c->cc >> 8; else - temp = (dma.xfr_channel & 4) ? (dma16.cc[dma.xfr_channel & 3] & 0xff) : (dma.cc[dma.xfr_channel] & 0xff); - dma.byte_ptr = (dma.byte_ptr + 1) & 1; + temp = dma_c->cc & 0xff; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; break; + case 6: /*Read DMA status*/ + if (dma_ps2.byte_ptr) + { + temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); + dma_stat &= ~0xf0; + dma_stat_rq &= ~0xf0; + } + else + { + temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); + dma_stat &= ~0xf; + dma_stat_rq &= ~0xf; + } + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; case 7: /*Mode*/ - temp = (dma.xfr_channel & 4) ? dma16.ps2_mode[dma.xfr_channel & 3] : dma.ps2_mode[dma.xfr_channel]; + temp = dma_c->ps2_mode; break; case 8: /*Arbitration Level*/ - temp = (dma.xfr_channel & 4) ? dma16.arb_level[dma.xfr_channel & 3] : dma.arb_level[dma.xfr_channel]; + temp = dma_c->arb_level; break; default: - fatal("Bad XFR Read command %i channel %i\n", dma.xfr_command, dma.xfr_channel); + fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); } break; } @@ -185,6 +226,7 @@ static uint8_t dma_ps2_read(uint16_t addr, void *priv) static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) { + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; uint8_t mode; // pclog("Write PS2 DMA %04X %02X %04X:%04X\n",addr,val,CS,cpu_state.pc); @@ -192,114 +234,83 @@ static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) switch (addr) { case 0x18: - dma.xfr_channel = val & 0x7; - dma.xfr_command = val >> 4; - dma.byte_ptr = 0; - switch (dma.xfr_command) + dma_ps2.xfr_channel = val & 0x7; + dma_ps2.xfr_command = val >> 4; + dma_ps2.byte_ptr = 0; + switch (dma_ps2.xfr_command) { case 9: /*Set DMA mask*/ - if (dma.xfr_channel & 4) - dma16.m |= (1 << (dma.xfr_channel & 3)); - else - dma.m |= (1 << dma.xfr_channel); + dma_m |= (1 << dma_ps2.xfr_channel); break; case 0xa: /*Reset DMA mask*/ - if (dma.xfr_channel & 4) - dma16.m &= ~(1 << (dma.xfr_channel & 3)); - else - dma.m &= ~(1 << dma.xfr_channel); + dma_m &= ~(1 << dma_ps2.xfr_channel); break; + case 0xb: + if (!(dma_m & (1 << dma_ps2.xfr_channel))) + dma_ps2_run(dma_ps2.xfr_channel); + break; + +// case 0xb: output = 3; break; } break; case 0x1a: - switch (dma.xfr_command) + switch (dma_ps2.xfr_command) { + case 0: /*I/O address*/ + if (dma_ps2.byte_ptr) + dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); + else + dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + case 2: /*Address*/ - switch (dma.byte_ptr) + switch (dma_ps2.byte_ptr) { case 0: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0xffff00) | val; - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0xffff00) | val; - dma.byte_ptr = 1; + dma_c->ac = (dma_c->ac & 0xffff00) | val; + dma_ps2.byte_ptr = 1; break; case 1: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0xff00ff) | (val << 8); - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0xff00ff) | (val << 8); - dma.byte_ptr = 2; + dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); + dma_ps2.byte_ptr = 2; break; case 2: - if (dma.xfr_channel & 4) - dma16.ac[dma.xfr_channel & 3] = (dma16.ac[dma.xfr_channel & 3] & 0x00ffff) | (val << 16); - else - dma.ac[dma.xfr_channel] = (dma.ac[dma.xfr_channel] & 0x00ffff) | (val << 16); - dma.byte_ptr = 0; + dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); + dma_ps2.byte_ptr = 0; break; } - if (dma.xfr_channel & 4) - dma16.ab[dma.xfr_channel & 3] = dma16.ac[dma.xfr_channel & 3]; - else - dma.ab[dma.xfr_channel] = dma.ac[dma.xfr_channel]; + dma_c->ab = dma_c->ac; break; case 4: /*Count*/ - if (dma.byte_ptr) - { - if (dma.xfr_channel & 4) - dma16.cc[dma.xfr_channel & 3] = (dma16.cc[dma.xfr_channel & 3] & 0xff) | (val << 8); - else - dma.cc[dma.xfr_channel] = (dma.cc[dma.xfr_channel] & 0xff) | (val << 8); - } + if (dma_ps2.byte_ptr) + dma_c->cc = (dma_c->cc & 0xff) | (val << 8); else - { - if (dma.xfr_channel & 4) - dma16.cc[dma.xfr_channel & 3] = (dma16.cc[dma.xfr_channel & 3] & 0xff00) | val; - else - dma.cc[dma.xfr_channel] = (dma.cc[dma.xfr_channel] & 0xff00) | val; - } - dma.byte_ptr = (dma.byte_ptr + 1) & 1; - if (dma.xfr_channel & 4) - dma16.cb[dma.xfr_channel & 3] = dma16.cc[dma.xfr_channel & 3]; - else - dma.cb[dma.xfr_channel] = dma.cc[dma.xfr_channel]; + dma_c->cc = (dma_c->cc & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + dma_c->cb = dma_c->cc; break; case 7: /*Mode register*/ mode = 0; - if (val & 0x10) + if (val & DMA_PS2_DEC2) mode |= 0x20; - if ((val & 0xc) == 4) + if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) mode |= 8; - else if ((val & 0xc) == 0xc) + else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) mode |= 4; - if ((val & 0x40) && !(dma.xfr_channel & 4)) - fatal("16-bit DMA on 8-bit channel\n"); - if (!(val & 0x40) && (dma.xfr_channel & 4)) - fatal("8-bit DMA on 16-bit channel\n"); - if (dma.xfr_channel & 4) - { - dma16.mode[dma.xfr_channel & 3] = (dma16.mode[dma.xfr_channel & 3] & ~0x2c) | mode; - dma16.ps2_mode[dma.xfr_channel & 3] = val; - } - else - { - dma.mode[dma.xfr_channel] = (dma.mode[dma.xfr_channel] & ~0x2c) | mode; - dma.ps2_mode[dma.xfr_channel] = val; - } + dma_c->mode = (dma_c->mode & ~0x2c) | mode; + dma_c->ps2_mode = val; + dma_c->size = val & DMA_PS2_SIZE16; break; case 8: /*Arbitration Level*/ - if (dma.xfr_channel & 4) - dma16.arb_level[dma.xfr_channel & 3] = val; - else - dma.arb_level[dma.xfr_channel] = val; + dma_c->arb_level = val; break; default: - fatal("Bad XFR command %i channel %i val %02x\n", dma.xfr_command, dma.xfr_channel, val); + fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); } break; } @@ -307,32 +318,35 @@ static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) uint8_t dma16_read(uint16_t addr, void *priv) { + int channel = ((addr >> 2) & 3) + 4; 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 (dma.is_ps2) + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { - if (dma16.wp) - return dma16.ac[(addr >> 1) & 3] & 0xff; - return (dma16.ac[(addr >> 1) & 3] >> 8) & 0xff; + if (dma16_wp) + return dma[channel].ac; + return (dma[channel].ac >> 8) & 0xff; } - if (dma16.wp) - return (dma16.ac[(addr >> 1) & 3] >> 1) & 0xff; - return (dma16.ac[(addr >> 1) & 3] >> 9) & 0xff; + if (dma16_wp) + return (dma[channel].ac >> 1) & 0xff; + return (dma[channel].ac >> 9) & 0xff; 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; + dma16_wp ^= 1; + if (dma16_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; return temp; case 8: /*Status register*/ - temp = dma16.stat; - dma16.stat = 0; + temp = dma_stat >> 4; + dma_stat &= ~0xf0; return temp; } return dma16regs[addr & 0xf]; @@ -340,66 +354,76 @@ uint8_t dma16_read(uint16_t addr, void *priv) void dma16_write(uint16_t addr, uint8_t val, void *priv) { + int channel = ((addr >> 2) & 3) + 4; // 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 (dma.is_ps2) + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { - if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xffff00) | val; - else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00ff) | (val << 8); + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); } else { - if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xfffe00) | (val << 1); - else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xfe01ff) | (val << 9); + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); + else + dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); } - dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3]; + dma[channel].ac = dma[channel].ab; 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]; + dma16_wp ^= 1; + if (dma16_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; return; case 8: /*Control register*/ return; case 0xa: /*Mask*/ - if (val & 4) dma16.m |= (1 << (val & 3)); - else dma16.m &= ~(1 << (val & 3)); + if (val & 4) + dma_m |= (0x10 << (val & 3)); + else + dma_m &= ~(0x10 << (val & 3)); return; case 0xb: /*Mode*/ - dma16.mode[val & 3] = val; - if (dma.is_ps2) + channel = (val & 3) + 4; + dma[channel].mode = val; + if (dma_ps2.is_ps2) { - dma16.ps2_mode[val & 3] &= ~0x1c; + dma[channel].ps2_mode &= ~0x1c; if (val & 0x20) - dma16.ps2_mode[val & 3] |= 0x10; + dma[channel].ps2_mode |= 0x10; if ((val & 0xc) == 8) - dma16.ps2_mode[val & 3] |= 4; + dma[channel].ps2_mode |= 4; else if ((val & 0xc) == 4) - dma16.ps2_mode[val & 3] |= 0xc; + dma[channel].ps2_mode |= 0xc; } return; case 0xc: /*Clear FF*/ - dma16.wp = 0; + dma16_wp = 0; return; case 0xd: /*Master clear*/ - dma16.wp = 0; - dma16.m = 0xf; + dma16_wp = 0; + dma_m |= 0xf0; return; case 0xf: /*Mask write*/ - dma16.m = val&0xf; + dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); return; } } @@ -411,39 +435,39 @@ void dma_page_write(uint16_t addr, uint8_t val, void *priv) switch (addr & 0xf) { case 1: - dma.page[2] = (AT) ? val : val & 0xf; - dma.ab[2] = (dma.ab[2] & 0xffff) | (dma.page[2] << 16); - dma.ac[2] = (dma.ac[2] & 0xffff) | (dma.page[2] << 16); + dma[2].page = (AT) ? val : val & 0xf; + dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); + dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); break; case 2: - dma.page[3] = (AT) ? val : val & 0xf; - dma.ab[3] = (dma.ab[3] & 0xffff) | (dma.page[3] << 16); - dma.ac[3] = (dma.ac[3] & 0xffff) | (dma.page[3] << 16); + dma[3].page = (AT) ? val : val & 0xf; + dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); + dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); break; case 3: - dma.page[1] = (AT) ? val : val & 0xf; - dma.ab[1] = (dma.ab[1] & 0xffff) | (dma.page[1] << 16); - dma.ac[1] = (dma.ac[1] & 0xffff) | (dma.page[1] << 16); + dma[1].page = (AT) ? val : val & 0xf; + dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); + dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); break; case 7: - dma.page[0] = (AT) ? val : val & 0xf; - dma.ab[0] = (dma.ab[0] & 0xffff) | (dma.page[0] << 16); - dma.ac[0] = (dma.ac[0] & 0xffff) | (dma.page[0] << 16); + dma[0].page = (AT) ? val : val & 0xf; + dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); + dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); break; case 0x9: - dma16.page[2] = val & 0xfe; - dma16.ab[2] = (dma16.ab[2] & 0x1ffff) | (dma16.page[2] << 16); - dma16.ac[2] = (dma16.ac[2] & 0x1ffff) | (dma16.page[2] << 16); + dma[6].page = val & 0xfe; + dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); + dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); break; case 0xa: - dma16.page[3] = val & 0xfe; - dma16.ab[3] = (dma16.ab[3] & 0x1ffff) | (dma16.page[3] << 16); - dma16.ac[3] = (dma16.ac[3] & 0x1ffff) | (dma16.page[3] << 16); + dma[7].page = val & 0xfe; + dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); + dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); break; case 0xb: - dma16.page[1] = val & 0xfe; - dma16.ab[1] = (dma16.ab[1] & 0x1ffff) | (dma16.page[1] << 16); - dma16.ac[1] = (dma16.ac[1] & 0x1ffff) | (dma16.page[1] << 16); + dma[5].page = val & 0xfe; + dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); + dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); break; } } @@ -457,7 +481,7 @@ 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); - dma.is_ps2 = 0; + dma_ps2.is_ps2 = 0; } void dma16_init() @@ -470,7 +494,7 @@ void ps2_dma_init() { io_sethandler(0x0018, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); io_sethandler(0x001a, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); - dma.is_ps2 = 1; + dma_ps2.is_ps2 = 1; } @@ -488,190 +512,267 @@ void _dma_write(uint32_t addr, uint8_t val) int dma_channel_read(int channel) { + dma_t *dma_c = &dma[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]); - - if (dma.mode[channel] & 0x20) - { - if (dma.is_ps2) - dma.ac[channel]--; - else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] - 1) & 0xffff); - } - else - { - if (dma.is_ps2) - dma.ac[channel]++; - else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] + 1) & 0xffff); - } - 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; + if (dma_command & 0x04) + return DMA_NODATA; } else { - channel &= 3; - if (dma16.m & (1 << channel)) - return DMA_NODATA; - if ((dma16.mode[channel] & 0xC) != 8) - return DMA_NODATA; + if (dma16_command & 0x04) + return DMA_NODATA; + } + + if (!AT) + refreshread(); - temp = _dma_read(dma16.ac[channel]) | - (_dma_read(dma16.ac[channel] + 1) << 8); + if (dma_m & (1 << channel)) + return DMA_NODATA; + if ((dma_c->mode & 0xC) != 8) + return DMA_NODATA; + + if (!dma_c->size) + { + temp = _dma_read(dma_c->ac); - if (dma16.mode[channel] & 0x20) + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma16.ac[channel] -= 2; + if (dma_ps2.is_ps2) + dma_c->ac--; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); } else { - if (dma.is_ps2) - dma16.ac[channel] += 2; + if (dma_ps2.is_ps2) + dma_c->ac++; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] + 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } - - 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; } + else + { + temp = _dma_read(dma_c->ac) | + (_dma_read(dma_c->ac + 1) << 8); + + if (dma_c->mode & 0x20) + { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } + else + { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) + { + tc = 1; + if (dma_c->mode & 0x10) /*Auto-init*/ + { + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } + else + dma_m |= (1 << channel); + dma_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; + dma_t *dma_c = &dma[channel]; + + if (channel < 4) + { + if (dma_command & 0x04) + return DMA_NODATA; + } + else + { + if (dma16_command & 0x04) + return DMA_NODATA; + } if (!AT) refreshread(); - if (channel < 4) + if (dma_m & (1 << channel)) + return DMA_NODATA; + if ((dma_c->mode & 0xC) != 4) + return DMA_NODATA; + + if (!dma_c->size) { - if (dma.m & (1 << channel)) - return DMA_NODATA; - if ((dma.mode[channel] & 0xC) != 4) - return DMA_NODATA; - - _dma_write(dma.ac[channel], val); - - if (dma.mode[channel] & 0x20) + _dma_write(dma_c->ac, val); + + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma.ac[channel]--; + if (dma_ps2.is_ps2) + dma_c->ac--; else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] - 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); } else { - if (dma.is_ps2) - dma.ac[channel]++; + if (dma_ps2.is_ps2) + dma_c->ac++; else - dma.ac[channel] = (dma.ac[channel] & 0xff0000) | ((dma.ac[channel] + 1) & 0xffff); + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); } - - 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(dma_c->ac, val); + _dma_write(dma_c->ac + 1, val >> 8); - _dma_write(dma16.ac[channel], val); - _dma_write(dma16.ac[channel] + 1, val >> 8); - - if (dma16.mode[channel] & 0x20) + if (dma_c->mode & 0x20) { - if (dma.is_ps2) - dma16.ac[channel] -= 2; + if (dma_ps2.is_ps2) + dma_c->ac -= 2; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); } else { - if (dma.is_ps2) - dma16.ac[channel] += 2; + if (dma_ps2.is_ps2) + dma_c->ac += 2; else - dma16.ac[channel] = (dma16.ac[channel] & 0xfe0000) | ((dma16.ac[channel] + 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); } - - 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; } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) + { + if (dma_c->mode & 0x10) /*Auto-init*/ + { + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } + else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (dma_m & (1 << channel)) + return DMA_OVER; + return 0; } + +static void dma_ps2_run(int channel) +{ + dma_t *dma_c = &dma[channel]; + + switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) + { + case DMA_PS2_XFER_MEM_TO_IO: + do + { + if (!dma_c->size) + { + uint8_t temp = _dma_read(dma_c->ac); + outb(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + outw(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + dma_stat |= (1 << channel); + break; + + case DMA_PS2_XFER_IO_TO_MEM: + do + { + if (!dma_c->size) + { + uint8_t temp = inb(dma_c->io_addr); + _dma_write(dma_c->ac, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + uint16_t temp = inw(dma_c->io_addr); + _dma_write(dma_c->ac, temp & 0xff); + _dma_write(dma_c->ac + 1, temp >> 8); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + ps2_cache_clean(); + dma_stat |= (1 << channel); + break; + + default: /*Memory verify*/ + do + { + if (!dma_c->size) + { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma->cc--; + } while (dma->cc > 0); + + dma_stat |= (1 << channel); + break; + } +} diff --git a/src/dosbox/cdrom.h b/src/dosbox/cdrom.h new file mode 100644 index 0000000..603deb7 --- /dev/null +++ b/src/dosbox/cdrom.h @@ -0,0 +1,172 @@ +/* + * Copyright (C) 2002-2015 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. + */ + +/* Modified for use with PCem by bit */ + +#ifndef __CDROM_INTERFACE__ +#define __CDROM_INTERFACE__ + +#include +#include +#include +#include +#include +#include +//#include "dosbox.h" +//#include "mem.h" +//#include "mixer.h" +//#include "SDL.h" +//#include "SDL_thread.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; + +typedef size_t PhysPt; + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +#define DATA_TRACK 0x14 +#define AUDIO_TRACK 0x10 + +#define CD_FPS 75 +#define FRAMES_TO_MSF(f, M,S,F) { \ + int value = f; \ + *(F) = value%CD_FPS; \ + value /= CD_FPS; \ + *(S) = value%60; \ + value /= 60; \ + *(M) = value; \ +} +#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) + + +typedef struct SMSF { + unsigned char min; + unsigned char sec; + unsigned char fr; +} TMSF; + +typedef struct SCtrl { + Bit8u out[4]; // output channel + Bit8u vol[4]; // channel volume +} TCtrl; + +extern int CDROM_GetMountType(char* path, int force); + +class CDROM_Interface +{ +public: +// CDROM_Interface (void); + virtual ~CDROM_Interface (void) {}; + + virtual bool SetDevice (char* path, int forceCD) = 0; + + virtual bool GetUPC (unsigned char& attr, char* upc) = 0; + + virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0; + virtual bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; + virtual bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0; + virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; + + virtual bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num) = 0; + + virtual bool LoadUnloadMedia (bool unload) = 0; + + virtual void InitNewMedia (void) {}; +}; + +class CDROM_Interface_Image : public CDROM_Interface +{ +private: + class TrackFile { + public: + virtual bool read(Bit8u *buffer, int seek, int count) = 0; + virtual int getLength() = 0; + virtual ~TrackFile() { }; + }; + + class BinaryFile : public TrackFile { + public: + BinaryFile(const char *filename, bool &error); + ~BinaryFile(); + bool read(Bit8u *buffer, int seek, int count); + int getLength(); + private: + BinaryFile(); + std::ifstream *file; + }; + + struct Track { + int number; + int track_number; + int attr; + int start; + int length; + int skip; + int sectorSize; + bool mode2; + TrackFile *file; + }; + +public: + CDROM_Interface_Image (); + virtual ~CDROM_Interface_Image (void); + void InitNewMedia (void); + bool SetDevice (char* path, int forceCD); + bool GetUPC (unsigned char& attr, char* upc); + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr); + bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); + bool LoadUnloadMedia (bool unload); + bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector); + bool HasDataTrack (void); + bool HasAudioTracks (void); + + int GetTrack (int sector); + +private: + // player +static void CDAudioCallBack(Bitu len); + + void ClearTracks(); + bool LoadIsoFile(char *filename); + bool CanReadPVD(TrackFile *file, int sectorSize, bool mode2); + // cue sheet processing + bool LoadCueSheet(char *cuefile); + bool GetRealFileName(std::string& filename, std::string& pathname); + bool GetCueKeyword(std::string &keyword, std::istream &in); + bool GetCueFrame(int &frames, std::istream &in); + bool GetCueString(std::string &str, std::istream &in); + bool AddTrack(Track &curr, int &shift, int prestart, int &totalPregap, int currPregap); + + std::vector tracks; +typedef std::vector::iterator track_it; + std::string mcn; +}; + +#endif /* __CDROM_INTERFACE__ */ diff --git a/src/dosbox/cdrom_image.cpp b/src/dosbox/cdrom_image.cpp new file mode 100644 index 0000000..096777c --- /dev/null +++ b/src/dosbox/cdrom_image.cpp @@ -0,0 +1,546 @@ +/* + * Copyright (C) 2002-2015 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. + */ + +/* Modified for use with PCem by bit */ + +#include +#include +#include +#include +#include +#include +#include //GCC 2.95 +#include +#include +#include +#include "cdrom.h" + +#if !defined(WIN32) +#include +#else +#include +#endif + +using namespace std; + +#define MAX_LINE_LENGTH 512 +#define MAX_FILENAME_LENGTH 256 +#define CROSS_LEN 512 + +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + +CDROM_Interface_Image::BinaryFile::BinaryFile(const char *filename, bool &error) +{ + file = new ifstream(filename, ios::in | ios::binary); + error = (file == NULL) || (file->fail()); +} + +CDROM_Interface_Image::BinaryFile::~BinaryFile() +{ + delete file; +} + +bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, int seek, int count) +{ + file->seekg(seek, ios::beg); + file->read((char*)buffer, count); + return !(file->fail()); +} + +int CDROM_Interface_Image::BinaryFile::getLength() +{ + file->seekg(0, ios::end); + int length = (int)file->tellg(); + if (file->fail()) return -1; + return length; +} + +CDROM_Interface_Image::CDROM_Interface_Image() +{ +} + +CDROM_Interface_Image::~CDROM_Interface_Image() +{ + ClearTracks(); +} + +void CDROM_Interface_Image::InitNewMedia() +{ +} + +bool CDROM_Interface_Image::SetDevice(char* path, int forceCD) +{ + if (LoadCueSheet(path)) return true; + if (LoadIsoFile(path)) return true; + + // print error message on dosbox console + //printf("Could not load image file: %s\n", path); + return false; +} + +bool CDROM_Interface_Image::GetUPC(unsigned char& attr, char* upc) +{ + attr = 0; + strcpy(upc, this->mcn.c_str()); + return true; +} + +bool CDROM_Interface_Image::GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) +{ + stTrack = 1; + end = (int)(tracks.size() - 1); + FRAMES_TO_MSF(tracks[tracks.size() - 1].start + 150, &leadOut.min, &leadOut.sec, &leadOut.fr); + return true; +} + +bool CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF& start, unsigned char& attr) +{ + if (track < 1 || track > (int)tracks.size()) return false; + FRAMES_TO_MSF(tracks[track - 1].start + 150, &start.min, &start.sec, &start.fr); + track_number = tracks[track - 1].track_number; + attr = tracks[track - 1].attr; + return true; +} + +bool CDROM_Interface_Image::GetAudioSub(int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + int cur_track = GetTrack(sector); + if (cur_track < 1) return false; + track = (unsigned char)cur_track; + attr = tracks[track - 1].attr; + index = 1; + FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr); + FRAMES_TO_MSF(sector - tracks[track - 1].start + 150, &relPos.min, &relPos.sec, &relPos.fr); + return true; +} + +bool CDROM_Interface_Image::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + mediaPresent = true; + mediaChanged = false; + trayOpen = false; + return true; +} + +bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) +{ + int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; + Bitu buflen = num * sectorSize; + Bit8u* buf = new Bit8u[buflen]; + + bool success = true; //Gobliiins reads 0 sectors + for(unsigned long i = 0; i < num; i++) { + success = ReadSector(&buf[i * sectorSize], raw, sector + i); + if (!success) break; + } + + memcpy((void*)buffer, buf, buflen); + delete[] buf; + + return success; +} + +bool CDROM_Interface_Image::LoadUnloadMedia(bool unload) +{ + return true; +} + +int CDROM_Interface_Image::GetTrack(int sector) +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end() - 1; + + while(i != end) { + Track &curr = *i; + Track &next = *(i + 1); + if (curr.start <= sector && sector < next.start) return curr.number; + i++; + } + return -1; +} + +bool CDROM_Interface_Image::ReadSector(Bit8u *buffer, bool raw, unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + int seek = tracks[track].skip + (sector - tracks[track].start) * tracks[track].sectorSize; + int length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE); + if (tracks[track].sectorSize != RAW_SECTOR_SIZE && raw) return false; + if (tracks[track].sectorSize == RAW_SECTOR_SIZE && !tracks[track].mode2 && !raw) seek += 16; + if (tracks[track].mode2 && !raw) seek += 24; + + return tracks[track].file->read(buffer, seek, length); +} + +bool CDROM_Interface_Image::LoadIsoFile(char* filename) +{ + tracks.clear(); + + // data track + Track track = {0, 0, 0, 0, 0, 0, 0, false, NULL}; + bool error; + track.file = new BinaryFile(filename, error); + if (error) { + delete track.file; + return false; + } + track.number = 1; + track.track_number = 1; + track.attr = DATA_TRACK;//data + + // try to detect iso type + if (CanReadPVD(track.file, COOKED_SECTOR_SIZE, false)) { + track.sectorSize = COOKED_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, false)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, 2336, true)) { + track.sectorSize = 2336; + track.mode2 = true; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, true)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = true; + } else return false; + + track.length = track.file->getLength() / track.sectorSize; + tracks.push_back(track); + + // leadout track + track.number = 2; + track.track_number = 0xAA; + track.attr = 0; + track.start = track.length; + track.length = 0; + track.file = NULL; + tracks.push_back(track); + + return true; +} + +bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, int sectorSize, bool mode2) +{ + Bit8u pvd[COOKED_SECTOR_SIZE]; + int seek = 16 * sectorSize; // first vd is located at sector 16 + if (sectorSize == RAW_SECTOR_SIZE && !mode2) seek += 16; + if (mode2) seek += 24; + file->read(pvd, seek, COOKED_SECTOR_SIZE); + // pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra) + return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) || + (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1)); +} + +#if defined(WIN32) +static string dirname(char * file) { + char * sep = strrchr(file, '\\'); + if (sep == NULL) + sep = strrchr(file, '/'); + if (sep == NULL) + return ""; + else { + int len = (int)(sep - file); + char tmp[MAX_FILENAME_LENGTH]; + safe_strncpy(tmp, file, len+1); + return tmp; + } +} +#endif + +bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) +{ + Track track = {0, 0, 0, 0, 0, 0, 0, false, NULL}; + tracks.clear(); + int shift = 0; + int currPregap = 0; + int totalPregap = 0; + int prestart = 0; + bool success; + bool canAddTrack = false; + char tmp[MAX_FILENAME_LENGTH]; // dirname can change its argument + safe_strncpy(tmp, cuefile, MAX_FILENAME_LENGTH); + string pathname(dirname(tmp)); + ifstream in; + in.open(cuefile, ios::in); + if (in.fail()) return false; + + while(!in.eof()) { + // get next line + char buf[MAX_LINE_LENGTH]; + in.getline(buf, MAX_LINE_LENGTH); + if (in.fail() && !in.eof()) return false; // probably a binary file + istringstream line(buf); + + string command; + GetCueKeyword(command, line); + + if (command == "TRACK") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + + track.start = 0; + track.skip = 0; + currPregap = 0; + prestart = 0; + + line >> track.number; + track.track_number = track.number; + string type; + GetCueKeyword(type, line); + + if (type == "AUDIO") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = AUDIO_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2048") { + track.sectorSize = COOKED_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE2/2336") { + track.sectorSize = 2336; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = true; + } else success = false; + + canAddTrack = true; + } + else if (command == "INDEX") { + int index; + line >> index; + int frame; + success = GetCueFrame(frame, line); + + if (index == 1) track.start = frame; + else if (index == 0) prestart = frame; + // ignore other indices + } + else if (command == "FILE") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + canAddTrack = false; + + string filename; + GetCueString(filename, line); + GetRealFileName(filename, pathname); + string type; + GetCueKeyword(type, line); + + track.file = NULL; + bool error = true; + if (type == "BINARY") { + track.file = new BinaryFile(filename.c_str(), error); + } + if (error) { + delete track.file; + success = false; + } + } + else if (command == "PREGAP") success = GetCueFrame(currPregap, line); + else if (command == "CATALOG") success = GetCueString(mcn, line); + // ignored commands + else if (command == "CDTEXTFILE" || command == "FLAGS" || command == "ISRC" + || command == "PERFORMER" || command == "POSTGAP" || command == "REM" + || command == "SONGWRITER" || command == "TITLE" || command == "") success = true; + // failure + else success = false; + + if (!success) return false; + } + // add last track + if (!AddTrack(track, shift, prestart, totalPregap, currPregap)) return false; + + // add leadout track + track.number++; + track.track_number = 0xAA; + track.attr = 0;//sync with load iso + track.start = 0; + track.length = 0; + track.file = NULL; + if(!AddTrack(track, shift, 0, totalPregap, 0)) return false; + + return true; +} + +bool CDROM_Interface_Image::AddTrack(Track &curr, int &shift, int prestart, int &totalPregap, int currPregap) +{ + // frames between index 0(prestart) and 1(curr.start) must be skipped + int skip; + if (prestart > 0) { + if (prestart > curr.start) return false; + skip = curr.start - prestart; + } else skip = 0; + + // first track (track number must be 1) + if (tracks.empty()) { + if (curr.number != 1) return false; + curr.skip = skip * curr.sectorSize; + curr.start += currPregap; + totalPregap = currPregap; + tracks.push_back(curr); + return true; + } + + Track &prev = *(tracks.end() - 1); + + // current track consumes data from the same file as the previous + if (prev.file == curr.file) { + curr.start += shift; + prev.length = curr.start + totalPregap - prev.start - skip; + curr.skip += prev.skip + prev.length * prev.sectorSize + skip * curr.sectorSize; + totalPregap += currPregap; + curr.start += totalPregap; + // current track uses a different file as the previous track + } else { + int tmp = prev.file->getLength() - prev.skip; + prev.length = tmp / prev.sectorSize; + if (tmp % prev.sectorSize != 0) prev.length++; // padding + + curr.start += prev.start + prev.length + currPregap; + curr.skip = skip * curr.sectorSize; + shift += prev.start + prev.length; + totalPregap = currPregap; + } + + // error checks + if (curr.number <= 1) return false; + if (prev.number + 1 != curr.number) return false; + if (curr.start < prev.start + prev.length) return false; + if (curr.length < 0) return false; + + tracks.push_back(curr); + return true; +} + +bool CDROM_Interface_Image::HasDataTrack(void) +{ + //Data track has attribute 0x14 + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == DATA_TRACK) return true; + } + return false; +} + +bool CDROM_Interface_Image::HasAudioTracks(void) +{ + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == AUDIO_TRACK) return true; + } + return false; +} + + +bool CDROM_Interface_Image::GetRealFileName(string &filename, string &pathname) +{ + // check if file exists + struct stat test; + if (stat(filename.c_str(), &test) == 0) return true; + + // check if file with path relative to cue file exists + string tmpstr(pathname + "/" + filename); + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } +#if defined (WIN32) || defined(OS2) + //Nothing +#else + //Consider the possibility that the filename has a windows directory seperator (inside the CUE file) + //which is common for some commercial rereleases of DOS games using DOSBox + + string copy = filename; + size_t l = copy.size(); + for (size_t i = 0; i < l;i++) { + if(copy[i] == '\\') copy[i] = '/'; + } + + if (stat(copy.c_str(), &test) == 0) { + filename = copy; + return true; + } + + tmpstr = pathname + "/" + copy; + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } + +#endif + return false; +} + +bool CDROM_Interface_Image::GetCueKeyword(string &keyword, istream &in) +{ + in >> keyword; + for(Bitu i = 0; i < keyword.size(); i++) keyword[i] = toupper(keyword[i]); + + return true; +} + +bool CDROM_Interface_Image::GetCueFrame(int &frames, istream &in) +{ + string msf; + in >> msf; + int min, sec, fr; + bool success = sscanf(msf.c_str(), "%d:%d:%d", &min, &sec, &fr) == 3; + frames = MSF_TO_FRAMES(min, sec, fr); + + return success; +} + +bool CDROM_Interface_Image::GetCueString(string &str, istream &in) +{ + int pos = (int)in.tellg(); + in >> str; + if (str[0] == '\"') { + if (str[str.size() - 1] == '\"') { + str.assign(str, 1, str.size() - 2); + } else { + in.seekg(pos, ios::beg); + char buffer[MAX_FILENAME_LENGTH]; + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); // skip + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); + str = buffer; + } + } + return true; +} + +void CDROM_Interface_Image::ClearTracks() +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end(); + + TrackFile* last = NULL; + while(i != end) { + Track &curr = *i; + if (curr.file != last) { + delete curr.file; + last = curr.file; + } + i++; + } + tracks.clear(); +} diff --git a/src/dosbox/nukedopl.cpp b/src/dosbox/nukedopl.cpp new file mode 100644 index 0000000..374b9bf --- /dev/null +++ b/src/dosbox/nukedopl.cpp @@ -0,0 +1,1371 @@ +// +// Nuked OPL3 emulator. +// Thanks: +// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): +// Feedback and Rhythm part calculation information. +// forums.submarine.org.uk(carbon14, opl3): +// Tremolo and phase generator calculation information. +// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): +// OPL2 ROMs. +// +// version: 1.7.4 +// + +#include +#include +#include +#include "nukedopl.h" + +#define RSM_FRAC 10 + +// Channel types + +enum { + ch_2op = 0, + ch_4op = 1, + ch_4op2 = 2, + ch_drum = 3 +}; + +// Envelope key types + +enum { + egk_norm = 0x01, + egk_drum = 0x02 +}; + + +// +// logsin table +// + +static const Bit16u logsinrom[256] = { + 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, + 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, + 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, + 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, + 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, + 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, + 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, + 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, + 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, + 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, + 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, + 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, + 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, + 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, + 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, + 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, + 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, + 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, + 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, + 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, + 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, + 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, + 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, + 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, + 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, + 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, + 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, + 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, + 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, + 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, + 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +// +// exp table +// + +static const Bit16u exprom[256] = { + 0x000, 0x003, 0x006, 0x008, 0x00b, 0x00e, 0x011, 0x014, + 0x016, 0x019, 0x01c, 0x01f, 0x022, 0x025, 0x028, 0x02a, + 0x02d, 0x030, 0x033, 0x036, 0x039, 0x03c, 0x03f, 0x042, + 0x045, 0x048, 0x04b, 0x04e, 0x051, 0x054, 0x057, 0x05a, + 0x05d, 0x060, 0x063, 0x066, 0x069, 0x06c, 0x06f, 0x072, + 0x075, 0x078, 0x07b, 0x07e, 0x082, 0x085, 0x088, 0x08b, + 0x08e, 0x091, 0x094, 0x098, 0x09b, 0x09e, 0x0a1, 0x0a4, + 0x0a8, 0x0ab, 0x0ae, 0x0b1, 0x0b5, 0x0b8, 0x0bb, 0x0be, + 0x0c2, 0x0c5, 0x0c8, 0x0cc, 0x0cf, 0x0d2, 0x0d6, 0x0d9, + 0x0dc, 0x0e0, 0x0e3, 0x0e7, 0x0ea, 0x0ed, 0x0f1, 0x0f4, + 0x0f8, 0x0fb, 0x0ff, 0x102, 0x106, 0x109, 0x10c, 0x110, + 0x114, 0x117, 0x11b, 0x11e, 0x122, 0x125, 0x129, 0x12c, + 0x130, 0x134, 0x137, 0x13b, 0x13e, 0x142, 0x146, 0x149, + 0x14d, 0x151, 0x154, 0x158, 0x15c, 0x160, 0x163, 0x167, + 0x16b, 0x16f, 0x172, 0x176, 0x17a, 0x17e, 0x181, 0x185, + 0x189, 0x18d, 0x191, 0x195, 0x199, 0x19c, 0x1a0, 0x1a4, + 0x1a8, 0x1ac, 0x1b0, 0x1b4, 0x1b8, 0x1bc, 0x1c0, 0x1c4, + 0x1c8, 0x1cc, 0x1d0, 0x1d4, 0x1d8, 0x1dc, 0x1e0, 0x1e4, + 0x1e8, 0x1ec, 0x1f0, 0x1f5, 0x1f9, 0x1fd, 0x201, 0x205, + 0x209, 0x20e, 0x212, 0x216, 0x21a, 0x21e, 0x223, 0x227, + 0x22b, 0x230, 0x234, 0x238, 0x23c, 0x241, 0x245, 0x249, + 0x24e, 0x252, 0x257, 0x25b, 0x25f, 0x264, 0x268, 0x26d, + 0x271, 0x276, 0x27a, 0x27f, 0x283, 0x288, 0x28c, 0x291, + 0x295, 0x29a, 0x29e, 0x2a3, 0x2a8, 0x2ac, 0x2b1, 0x2b5, + 0x2ba, 0x2bf, 0x2c4, 0x2c8, 0x2cd, 0x2d2, 0x2d6, 0x2db, + 0x2e0, 0x2e5, 0x2e9, 0x2ee, 0x2f3, 0x2f8, 0x2fd, 0x302, + 0x306, 0x30b, 0x310, 0x315, 0x31a, 0x31f, 0x324, 0x329, + 0x32e, 0x333, 0x338, 0x33d, 0x342, 0x347, 0x34c, 0x351, + 0x356, 0x35b, 0x360, 0x365, 0x36a, 0x370, 0x375, 0x37a, + 0x37f, 0x384, 0x38a, 0x38f, 0x394, 0x399, 0x39f, 0x3a4, + 0x3a9, 0x3ae, 0x3b4, 0x3b9, 0x3bf, 0x3c4, 0x3c9, 0x3cf, + 0x3d4, 0x3da, 0x3df, 0x3e4, 0x3ea, 0x3ef, 0x3f5, 0x3fa +}; + +// +// freq mult table multiplied by 2 +// +// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 +// + +static const Bit8u mt[16] = { + 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 +}; + +// +// ksl table +// + +static const Bit8u kslrom[16] = { + 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 +}; + +static const Bit8u kslshift[4] = { + 8, 1, 2, 0 +}; + +// +// envelope generator constants +// + +static const Bit8u eg_incstep[3][4][8] = { + { + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0 } + }, + { + { 0, 1, 0, 1, 0, 1, 0, 1 }, + { 0, 1, 0, 1, 1, 1, 0, 1 }, + { 0, 1, 1, 1, 0, 1, 1, 1 }, + { 0, 1, 1, 1, 1, 1, 1, 1 } + }, + { + { 1, 1, 1, 1, 1, 1, 1, 1 }, + { 2, 2, 1, 1, 1, 1, 1, 1 }, + { 2, 2, 1, 1, 2, 2, 1, 1 }, + { 2, 2, 2, 2, 2, 2, 1, 1 } + } +}; + +static const Bit8u eg_incdesc[16] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2 +}; + +static const Bit8s eg_incsh[16] = { + 0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0, -1, -2 +}; + +// +// address decoding +// + +static const Bit8s ad_slot[0x20] = { + 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, + 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static const Bit8u ch_slot[18] = { + 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 +}; + +// +// Envelope generator +// + +typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); +typedef void(*envelope_genfunc)(opl3_slot *slott); + +static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) +{ + if (level > 0x1fff) + { + level = 0x1fff; + } + return ((exprom[(level & 0xff) ^ 0xff] | 0x400) << 1) >> (level >> 8); +} + +static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = ~0; + } + if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin1(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin2(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin3(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x100) + { + out = 0x1000; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin4(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if ((phase & 0x300) == 0x100) + { + neg = ~0; + } + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x80) + { + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + } + else + { + out = logsinrom[(phase << 1) & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin5(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x80) + { + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + } + else + { + out = logsinrom[(phase << 1) & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin6(Bit16u phase, Bit16u envelope) +{ + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = ~0; + } + return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin7(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = ~0; + phase = (phase & 0x1ff) ^ 0x1ff; + } + out = phase << 3; + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static const envelope_sinfunc envelope_sin[8] = { + OPL3_EnvelopeCalcSin0, + OPL3_EnvelopeCalcSin1, + OPL3_EnvelopeCalcSin2, + OPL3_EnvelopeCalcSin3, + OPL3_EnvelopeCalcSin4, + OPL3_EnvelopeCalcSin5, + OPL3_EnvelopeCalcSin6, + OPL3_EnvelopeCalcSin7 +}; + +static void OPL3_EnvelopeGenOff(opl3_slot *slot); +static void OPL3_EnvelopeGenAttack(opl3_slot *slot); +static void OPL3_EnvelopeGenDecay(opl3_slot *slot); +static void OPL3_EnvelopeGenSustain(opl3_slot *slot); +static void OPL3_EnvelopeGenRelease(opl3_slot *slot); + +envelope_genfunc envelope_gen[5] = { + OPL3_EnvelopeGenOff, + OPL3_EnvelopeGenAttack, + OPL3_EnvelopeGenDecay, + OPL3_EnvelopeGenSustain, + OPL3_EnvelopeGenRelease +}; + +enum envelope_gen_num +{ + envelope_gen_num_off = 0, + envelope_gen_num_attack = 1, + envelope_gen_num_decay = 2, + envelope_gen_num_sustain = 3, + envelope_gen_num_release = 4 +}; + +static Bit8u OPL3_EnvelopeCalcRate(opl3_slot *slot, Bit8u reg_rate) +{ + Bit8u rate; + if (reg_rate == 0x00) + { + return 0x00; + } + rate = (reg_rate << 2) + + (slot->reg_ksr ? slot->channel->ksv : (slot->channel->ksv >> 2)); + if (rate > 0x3c) + { + rate = 0x3c; + } + return rate; +} + +static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) +{ + Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) + - ((0x08 - slot->channel->block) << 5); + if (ksl < 0) + { + ksl = 0; + } + slot->eg_ksl = (Bit8u)ksl; +} + +static void OPL3_EnvelopeUpdateRate(opl3_slot *slot) +{ + switch (slot->eg_gen) + { + case envelope_gen_num_off: + case envelope_gen_num_attack: + slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_ar); + break; + case envelope_gen_num_decay: + slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_dr); + break; + case envelope_gen_num_sustain: + case envelope_gen_num_release: + slot->eg_rate = OPL3_EnvelopeCalcRate(slot, slot->reg_rr); + break; + } +} + +static void OPL3_EnvelopeGenOff(opl3_slot *slot) +{ + slot->eg_rout = 0x1ff; +} + +static void OPL3_EnvelopeGenAttack(opl3_slot *slot) +{ + if (slot->eg_rout == 0x00) + { + slot->eg_gen = envelope_gen_num_decay; + OPL3_EnvelopeUpdateRate(slot); + return; + } + slot->eg_rout += ((~slot->eg_rout) * slot->eg_inc) >> 3; + if (slot->eg_rout < 0x00) + { + slot->eg_rout = 0x00; + } +} + +static void OPL3_EnvelopeGenDecay(opl3_slot *slot) +{ + if (slot->eg_rout >= slot->reg_sl << 4) + { + slot->eg_gen = envelope_gen_num_sustain; + OPL3_EnvelopeUpdateRate(slot); + return; + } + slot->eg_rout += slot->eg_inc; +} + +static void OPL3_EnvelopeGenSustain(opl3_slot *slot) +{ + if (!slot->reg_type) + { + OPL3_EnvelopeGenRelease(slot); + } +} + +static void OPL3_EnvelopeGenRelease(opl3_slot *slot) +{ + if (slot->eg_rout >= 0x1ff) + { + slot->eg_gen = envelope_gen_num_off; + slot->eg_rout = 0x1ff; + OPL3_EnvelopeUpdateRate(slot); + return; + } + slot->eg_rout += slot->eg_inc; +} + +static void OPL3_EnvelopeCalc(opl3_slot *slot) +{ + Bit8u rate_h, rate_l; + Bit8u inc = 0; + rate_h = slot->eg_rate >> 2; + rate_l = slot->eg_rate & 3; + if (eg_incsh[rate_h] > 0) + { + if ((slot->chip->timer & ((1 << eg_incsh[rate_h]) - 1)) == 0) + { + inc = eg_incstep[eg_incdesc[rate_h]][rate_l] + [((slot->chip->timer)>> eg_incsh[rate_h]) & 0x07]; + } + } + else + { + inc = eg_incstep[eg_incdesc[rate_h]][rate_l] + [slot->chip->timer & 0x07] << (-eg_incsh[rate_h]); + } + slot->eg_inc = inc; + slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + envelope_gen[slot->eg_gen](slot); +} + +static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type) +{ + if (!slot->key) + { + slot->eg_gen = envelope_gen_num_attack; + OPL3_EnvelopeUpdateRate(slot); + if ((slot->eg_rate >> 2) == 0x0f) + { + slot->eg_gen = envelope_gen_num_decay; + OPL3_EnvelopeUpdateRate(slot); + slot->eg_rout = 0x00; + } + slot->pg_phase = 0x00; + } + slot->key |= type; +} + +static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) +{ + if (slot->key) + { + slot->key &= (~type); + if (!slot->key) + { + slot->eg_gen = envelope_gen_num_release; + OPL3_EnvelopeUpdateRate(slot); + } + } +} + +// +// Phase Generator +// + +static void OPL3_PhaseGenerate(opl3_slot *slot) +{ + Bit16u f_num; + Bit32u basefreq; + + f_num = slot->channel->f_num; + if (slot->reg_vib) + { + Bit8s range; + Bit8u vibpos; + + range = (f_num >> 7) & 7; + vibpos = slot->chip->vibpos; + + if (!(vibpos & 3)) + { + range = 0; + } + else if (vibpos & 1) + { + range >>= 1; + } + range >>= slot->chip->vibshift; + + if (vibpos & 4) + { + range = -range; + } + f_num += range; + } + basefreq = (f_num << slot->channel->block) >> 1; + slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; +} + +// +// Noise Generator +// + +static void OPL3_NoiseGenerate(opl3_chip *chip) +{ + if (chip->noise & 0x01) + { + chip->noise ^= 0x800302; + } + chip->noise >>= 1; +} + +// +// Slot +// + +static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) +{ + if ((data >> 7) & 0x01) + { + slot->trem = &slot->chip->tremolo; + } + else + { + slot->trem = (Bit8u*)&slot->chip->zeromod; + } + slot->reg_vib = (data >> 6) & 0x01; + slot->reg_type = (data >> 5) & 0x01; + slot->reg_ksr = (data >> 4) & 0x01; + slot->reg_mult = data & 0x0f; + OPL3_EnvelopeUpdateRate(slot); +} + +static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data) +{ + slot->reg_ksl = (data >> 6) & 0x03; + slot->reg_tl = data & 0x3f; + OPL3_EnvelopeUpdateKSL(slot); +} + +static void OPL3_SlotWrite60(opl3_slot *slot, Bit8u data) +{ + slot->reg_ar = (data >> 4) & 0x0f; + slot->reg_dr = data & 0x0f; + OPL3_EnvelopeUpdateRate(slot); +} + +static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) +{ + slot->reg_sl = (data >> 4) & 0x0f; + if (slot->reg_sl == 0x0f) + { + slot->reg_sl = 0x1f; + } + slot->reg_rr = data & 0x0f; + OPL3_EnvelopeUpdateRate(slot); +} + +static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) +{ + slot->reg_wf = data & 0x07; + if (slot->chip->newm == 0x00) + { + slot->reg_wf &= 0x03; + } +} + +static void OPL3_SlotGeneratePhase(opl3_slot *slot, Bit16u phase) +{ + slot->out = envelope_sin[slot->reg_wf](phase, slot->eg_out); +} + +static void OPL3_SlotGenerate(opl3_slot *slot) +{ + OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9) + *slot->mod); +} + +static void OPL3_SlotGenerateZM(opl3_slot *slot) +{ + OPL3_SlotGeneratePhase(slot, (Bit16u)(slot->pg_phase >> 9)); +} + +static void OPL3_SlotCalcFB(opl3_slot *slot) +{ + if (slot->channel->fb != 0x00) + { + slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); + } + else + { + slot->fbmod = 0; + } + slot->prout = slot->out; +} + +// +// Channel +// + +static void OPL3_ChannelSetupAlg(opl3_channel *channel); + +static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) +{ + opl3_channel *channel6; + opl3_channel *channel7; + opl3_channel *channel8; + Bit8u chnum; + + chip->rhy = data & 0x3f; + if (chip->rhy & 0x20) + { + channel6 = &chip->channel[6]; + channel7 = &chip->channel[7]; + channel8 = &chip->channel[8]; + channel6->out[0] = &channel6->slots[1]->out; + channel6->out[1] = &channel6->slots[1]->out; + channel6->out[2] = &chip->zeromod; + channel6->out[3] = &chip->zeromod; + channel7->out[0] = &channel7->slots[0]->out; + channel7->out[1] = &channel7->slots[0]->out; + channel7->out[2] = &channel7->slots[1]->out; + channel7->out[3] = &channel7->slots[1]->out; + channel8->out[0] = &channel8->slots[0]->out; + channel8->out[1] = &channel8->slots[0]->out; + channel8->out[2] = &channel8->slots[1]->out; + channel8->out[3] = &channel8->slots[1]->out; + for (chnum = 6; chnum < 9; chnum++) + { + chip->channel[chnum].chtype = ch_drum; + } + OPL3_ChannelSetupAlg(channel6); + //hh + if (chip->rhy & 0x01) + { + OPL3_EnvelopeKeyOn(channel7->slots[0], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel7->slots[0], egk_drum); + } + //tc + if (chip->rhy & 0x02) + { + OPL3_EnvelopeKeyOn(channel8->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel8->slots[1], egk_drum); + } + //tom + if (chip->rhy & 0x04) + { + OPL3_EnvelopeKeyOn(channel8->slots[0], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel8->slots[0], egk_drum); + } + //sd + if (chip->rhy & 0x08) + { + OPL3_EnvelopeKeyOn(channel7->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel7->slots[1], egk_drum); + } + //bd + if (chip->rhy & 0x10) + { + OPL3_EnvelopeKeyOn(channel6->slots[0], egk_drum); + OPL3_EnvelopeKeyOn(channel6->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel6->slots[0], egk_drum); + OPL3_EnvelopeKeyOff(channel6->slots[1], egk_drum); + } + } + else + { + for (chnum = 6; chnum < 9; chnum++) + { + chip->channel[chnum].chtype = ch_2op; + OPL3_ChannelSetupAlg(&chip->channel[chnum]); + OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[0], egk_drum); + OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[1], egk_drum); + } + } +} + +static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) +{ + if (channel->chip->newm && channel->chtype == ch_4op2) + { + return; + } + channel->f_num = (channel->f_num & 0x300) | data; + channel->ksv = (channel->block << 1) + | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); + OPL3_EnvelopeUpdateKSL(channel->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->slots[1]); + OPL3_EnvelopeUpdateRate(channel->slots[0]); + OPL3_EnvelopeUpdateRate(channel->slots[1]); + if (channel->chip->newm && channel->chtype == ch_4op) + { + channel->pair->f_num = channel->f_num; + channel->pair->ksv = channel->ksv; + OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); + OPL3_EnvelopeUpdateRate(channel->pair->slots[0]); + OPL3_EnvelopeUpdateRate(channel->pair->slots[1]); + } +} + +static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) +{ + if (channel->chip->newm && channel->chtype == ch_4op2) + { + return; + } + channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); + channel->block = (data >> 2) & 0x07; + channel->ksv = (channel->block << 1) + | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); + OPL3_EnvelopeUpdateKSL(channel->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->slots[1]); + OPL3_EnvelopeUpdateRate(channel->slots[0]); + OPL3_EnvelopeUpdateRate(channel->slots[1]); + if (channel->chip->newm && channel->chtype == ch_4op) + { + channel->pair->f_num = channel->f_num; + channel->pair->block = channel->block; + channel->pair->ksv = channel->ksv; + OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); + OPL3_EnvelopeUpdateRate(channel->pair->slots[0]); + OPL3_EnvelopeUpdateRate(channel->pair->slots[1]); + } +} + +static void OPL3_ChannelSetupAlg(opl3_channel *channel) +{ + if (channel->chtype == ch_drum) + { + switch (channel->alg & 0x01) + { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + break; + } + return; + } + if (channel->alg & 0x08) + { + return; + } + if (channel->alg & 0x04) + { + channel->pair->out[0] = &channel->chip->zeromod; + channel->pair->out[1] = &channel->chip->zeromod; + channel->pair->out[2] = &channel->chip->zeromod; + channel->pair->out[3] = &channel->chip->zeromod; + switch (channel->alg & 0x03) + { + case 0x00: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->slots[1]->out; + channel->out[1] = &channel->chip->zeromod; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x01: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; + channel->slots[0]->mod = &channel->chip->zeromod; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->pair->slots[1]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x02: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->chip->zeromod; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->pair->slots[0]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x03: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->chip->zeromod; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->chip->zeromod; + channel->out[0] = &channel->pair->slots[0]->out; + channel->out[1] = &channel->slots[0]->out; + channel->out[2] = &channel->slots[1]->out; + channel->out[3] = &channel->chip->zeromod; + break; + } + } + else + { + switch (channel->alg & 0x01) + { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->slots[1]->out; + channel->out[1] = &channel->chip->zeromod; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + channel->out[0] = &channel->slots[0]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + } + } +} + +static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) +{ + channel->fb = (data & 0x0e) >> 1; + channel->con = data & 0x01; + channel->alg = channel->con; + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); + channel->alg = 0x08; + OPL3_ChannelSetupAlg(channel->pair); + } + else if (channel->chtype == ch_4op2) + { + channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); + channel->pair->alg = 0x08; + OPL3_ChannelSetupAlg(channel); + } + else + { + OPL3_ChannelSetupAlg(channel); + } + } + else + { + OPL3_ChannelSetupAlg(channel); + } + if (channel->chip->newm) + { + channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; + channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; + } + else + { + channel->cha = channel->chb = ~0; + } +} + +static void OPL3_ChannelKeyOn(opl3_channel *channel) +{ + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + OPL3_EnvelopeKeyOn(channel->pair->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->pair->slots[1], egk_norm); + } + else if (channel->chtype == ch_2op || channel->chtype == ch_drum) + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + } + } + else + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + } +} + +static void OPL3_ChannelKeyOff(opl3_channel *channel) +{ + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + OPL3_EnvelopeKeyOff(channel->pair->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->pair->slots[1], egk_norm); + } + else if (channel->chtype == ch_2op || channel->chtype == ch_drum) + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + } + } + else + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + } +} + +static void OPL3_ChannelSet4Op(opl3_chip *chip, Bit8u data) +{ + Bit8u bit; + Bit8u chnum; + for (bit = 0; bit < 6; bit++) + { + chnum = bit; + if (bit >= 3) + { + chnum += 9 - 3; + } + if ((data >> bit) & 0x01) + { + chip->channel[chnum].chtype = ch_4op; + chip->channel[chnum + 3].chtype = ch_4op2; + } + else + { + chip->channel[chnum].chtype = ch_2op; + chip->channel[chnum + 3].chtype = ch_2op; + } + } +} + +static Bit16s OPL3_ClipSample(Bit32s sample) +{ + if (sample > 32767) + { + sample = 32767; + } + else if (sample < -32768) + { + sample = -32768; + } + return (Bit16s)sample; +} + +static void OPL3_GenerateRhythm1(opl3_chip *chip) +{ + opl3_channel *channel6; + opl3_channel *channel7; + opl3_channel *channel8; + Bit16u phase14; + Bit16u phase17; + Bit16u phase; + Bit16u phasebit; + + channel6 = &chip->channel[6]; + channel7 = &chip->channel[7]; + channel8 = &chip->channel[8]; + OPL3_SlotGenerate(channel6->slots[0]); + phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + phase = 0x00; + //hh tc phase bit + phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) + | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //hh + phase = (phasebit << 9) + | (0x34 << ((phasebit ^ (chip->noise & 0x01)) << 1)); + OPL3_SlotGeneratePhase(channel7->slots[0], phase); + //tt + OPL3_SlotGenerateZM(channel8->slots[0]); +} + +static void OPL3_GenerateRhythm2(opl3_chip *chip) +{ + opl3_channel *channel6; + opl3_channel *channel7; + opl3_channel *channel8; + Bit16u phase14; + Bit16u phase17; + Bit16u phase; + Bit16u phasebit; + + channel6 = &chip->channel[6]; + channel7 = &chip->channel[7]; + channel8 = &chip->channel[8]; + OPL3_SlotGenerate(channel6->slots[1]); + phase14 = (channel7->slots[0]->pg_phase >> 9) & 0x3ff; + phase17 = (channel8->slots[1]->pg_phase >> 9) & 0x3ff; + phase = 0x00; + //hh tc phase bit + phasebit = ((phase14 & 0x08) | (((phase14 >> 5) ^ phase14) & 0x04) + | (((phase17 >> 2) ^ phase17) & 0x08)) ? 0x01 : 0x00; + //sd + phase = (0x100 << ((phase14 >> 8) & 0x01)) ^ ((chip->noise & 0x01) << 8); + OPL3_SlotGeneratePhase(channel7->slots[1], phase); + //tc + phase = 0x100 | (phasebit << 9); + OPL3_SlotGeneratePhase(channel8->slots[1], phase); +} + +void OPL3_Generate(opl3_chip *chip, Bit16s *buf) +{ + Bit8u ii; + Bit8u jj; + Bit16s accm; + + buf[1] = OPL3_ClipSample(chip->mixbuff[1]); + + for (ii = 0; ii < 12; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + for (ii = 12; ii < 15; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) + { + OPL3_GenerateRhythm1(chip); + } + else + { + OPL3_SlotGenerate(&chip->slot[12]); + OPL3_SlotGenerate(&chip->slot[13]); + OPL3_SlotGenerate(&chip->slot[14]); + } + + chip->mixbuff[0] = 0; + for (ii = 0; ii < 18; ii++) + { + accm = 0; + for (jj = 0; jj < 4; jj++) + { + accm += *chip->channel[ii].out[jj]; + } + chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + } + + for (ii = 15; ii < 18; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + } + + if (chip->rhy & 0x20) + { + OPL3_GenerateRhythm2(chip); + } + else + { + OPL3_SlotGenerate(&chip->slot[15]); + OPL3_SlotGenerate(&chip->slot[16]); + OPL3_SlotGenerate(&chip->slot[17]); + } + + buf[0] = OPL3_ClipSample(chip->mixbuff[0]); + + for (ii = 18; ii < 33; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + chip->mixbuff[1] = 0; + for (ii = 0; ii < 18; ii++) + { + accm = 0; + for (jj = 0; jj < 4; jj++) + { + accm += *chip->channel[ii].out[jj]; + } + chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + } + + for (ii = 33; ii < 36; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + OPL3_NoiseGenerate(chip); + + if ((chip->timer & 0x3f) == 0x3f) + { + chip->tremolopos = (chip->tremolopos + 1) % 210; + } + if (chip->tremolopos < 105) + { + chip->tremolo = chip->tremolopos >> chip->tremoloshift; + } + else + { + chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; + } + + if ((chip->timer & 0x3ff) == 0x3ff) + { + chip->vibpos = (chip->vibpos + 1) & 7; + } + + chip->timer++; +} + +void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) +{ + while (chip->samplecnt >= chip->rateratio) + { + chip->oldsamples[0] = chip->samples[0]; + chip->oldsamples[1] = chip->samples[1]; + OPL3_Generate(chip, chip->samples); + chip->samplecnt -= chip->rateratio; + } + buf[0] = (Bit16s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + + chip->samples[0] * chip->samplecnt) / chip->rateratio); + buf[1] = (Bit16s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + + chip->samples[1] * chip->samplecnt) / chip->rateratio); + chip->samplecnt += 1 << RSM_FRAC; +} + +void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) +{ + Bit8u slotnum; + Bit8u channum; + + memset(chip, 0, sizeof(opl3_chip)); + for (slotnum = 0; slotnum < 36; slotnum++) + { + chip->slot[slotnum].chip = chip; + chip->slot[slotnum].mod = &chip->zeromod; + chip->slot[slotnum].eg_rout = 0x1ff; + chip->slot[slotnum].eg_out = 0x1ff; + chip->slot[slotnum].eg_gen = envelope_gen_num_off; + chip->slot[slotnum].trem = (Bit8u*)&chip->zeromod; + } + for (channum = 0; channum < 18; channum++) + { + chip->channel[channum].slots[0] = &chip->slot[ch_slot[channum]]; + chip->channel[channum].slots[1] = &chip->slot[ch_slot[channum] + 3]; + chip->slot[ch_slot[channum]].channel = &chip->channel[channum]; + chip->slot[ch_slot[channum] + 3].channel = &chip->channel[channum]; + if ((channum % 9) < 3) + { + chip->channel[channum].pair = &chip->channel[channum + 3]; + } + else if ((channum % 9) < 6) + { + chip->channel[channum].pair = &chip->channel[channum - 3]; + } + chip->channel[channum].chip = chip; + chip->channel[channum].out[0] = &chip->zeromod; + chip->channel[channum].out[1] = &chip->zeromod; + chip->channel[channum].out[2] = &chip->zeromod; + chip->channel[channum].out[3] = &chip->zeromod; + chip->channel[channum].chtype = ch_2op; + chip->channel[channum].cha = ~0; + chip->channel[channum].chb = ~0; + OPL3_ChannelSetupAlg(&chip->channel[channum]); + } + chip->noise = 0x306600; + chip->rateratio = (samplerate << RSM_FRAC) / 49716; + chip->tremoloshift = 4; + chip->vibshift = 1; +} + +Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val) +{ + Bit16u addr; + addr = val; + if ((port & 2) && (addr == 0x05 || chip->newm)) { + addr |= 0x100; + } + return addr; +} + +void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) +{ + Bit8u high = (reg >> 8) & 0x01; + Bit8u regm = reg & 0xff; + switch (regm & 0xf0) + { + case 0x00: + if (high) + { + switch (regm & 0x0f) + { + case 0x04: + OPL3_ChannelSet4Op(chip, v); + break; + case 0x05: + chip->newm = v & 0x01; + break; + } + } + else + { + switch (regm & 0x0f) + { + case 0x08: + chip->nts = (v >> 6) & 0x01; + break; + } + } + break; + case 0x20: + case 0x30: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite20(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x40: + case 0x50: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite40(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x60: + case 0x70: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite60(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x80: + case 0x90: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite80(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0xe0: + case 0xf0: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWriteE0(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0xa0: + if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteA0(&chip->channel[9 * high + (regm & 0x0f)], v); + } + break; + case 0xb0: + if (regm == 0xbd && !high) + { + chip->tremoloshift = (((v >> 7) ^ 1) << 1) + 2; + chip->vibshift = ((v >> 6) & 0x01) ^ 1; + OPL3_ChannelUpdateRhythm(chip, v); + } + else if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteB0(&chip->channel[9 * high + (regm & 0x0f)], v); + if (v & 0x20) + { + OPL3_ChannelKeyOn(&chip->channel[9 * high + (regm & 0x0f)]); + } + else + { + OPL3_ChannelKeyOff(&chip->channel[9 * high + (regm & 0x0f)]); + } + } + break; + case 0xc0: + if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteC0(&chip->channel[9 * high + (regm & 0x0f)], v); + } + break; + } +} + +void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) +{ + Bit32u i; + + for(i = 0; i < numsamples; i++) + { + OPL3_GenerateResampled(chip, sndptr); + sndptr += 2; + } +} diff --git a/src/dosbox/nukedopl.h b/src/dosbox/nukedopl.h new file mode 100644 index 0000000..ccebfc2 --- /dev/null +++ b/src/dosbox/nukedopl.h @@ -0,0 +1,103 @@ +// +// Nuked OPL3 emulator. +// Thanks: +// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): +// Feedback and Rhythm part calculation information. +// forums.submarine.org.uk(carbon14, opl3): +// Tremolo and phase generator calculation information. +// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): +// OPL2 ROMs. +// + +#ifndef NUKEDOPL_H +#define NUKEDOPL_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; + +struct opl3_chip; +struct opl3_slot; +struct opl3_channel; + +struct opl3_slot { + opl3_channel *channel; + opl3_chip *chip; + Bit16s out; + Bit16s fbmod; + Bit16s *mod; + Bit16s prout; + Bit16s eg_rout; + Bit16s eg_out; + Bit8u eg_inc; + Bit8u eg_gen; + Bit8u eg_rate; + Bit8u eg_ksl; + Bit8u *trem; + Bit8u reg_vib; + Bit8u reg_type; + Bit8u reg_ksr; + Bit8u reg_mult; + Bit8u reg_ksl; + Bit8u reg_tl; + Bit8u reg_ar; + Bit8u reg_dr; + Bit8u reg_sl; + Bit8u reg_rr; + Bit8u reg_wf; + Bit8u key; + Bit32u pg_phase; + Bit32u timer; +}; + +struct opl3_channel { + opl3_slot *slots[2]; + opl3_channel *pair; + opl3_chip *chip; + Bit16s *out[4]; + Bit8u chtype; + Bit16u f_num; + Bit8u block; + Bit8u fb; + Bit8u con; + Bit8u alg; + Bit8u ksv; + Bit16u cha, chb; +}; + +struct opl3_chip { + opl3_channel channel[18]; + opl3_slot slot[36]; + Bit16u timer; + Bit8u newm; + Bit8u nts; + Bit8u rhy; + Bit8u vibpos; + Bit8u vibshift; + Bit8u tremolo; + Bit8u tremolopos; + Bit8u tremoloshift; + Bit32u noise; + Bit16s zeromod; + Bit32s mixbuff[2]; + + Bit32s rateratio; + Bit32s samplecnt; + Bit16s oldsamples[2]; + Bit16s samples[2]; +}; + +//void OPL3_Generate(opl3_chip *chip, Bit16s *buf); +//void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf); +void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); +Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val); +void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); +#endif diff --git a/src/esdi_at.c b/src/esdi_at.c new file mode 100644 index 0000000..9002502 --- /dev/null +++ b/src/esdi_at.c @@ -0,0 +1,812 @@ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include + +#include "ibm.h" +#include "device.h" +#include "hdd_file.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "rom.h" +#include "timer.h" + +#include "esdi_at.h" + + +#define IDE_TIME (TIMER_USEC*10)//(5 * 100 * (1 << TIMER_SHIFT)) + +#define STAT_ERR 0x01 +#define STAT_INDEX 0x02 +#define STAT_CORRECTED_DATA 0x04 +#define STAT_DRQ 0x08 /* Data request */ +#define STAT_DSC 0x10 +#define STAT_SEEK_COMPLETE 0x20 +#define STAT_READY 0x40 +#define STAT_BUSY 0x80 + +#define ERR_DAM_NOT_FOUND 0x01 /*Data Address Mark not found*/ +#define ERR_TR000 0x02 /*Track 0 not found*/ +#define ERR_ABRT 0x04 /*Command aborted*/ +#define ERR_ID_NOT_FOUND 0x10 /*ID not found*/ +#define ERR_DATA_CRC 0x40 /*Data CRC error*/ +#define ERR_BAD_BLOCK 0x80 /*Bad Block detected*/ + +#define CMD_NOP 0x00 +#define CMD_RESTORE 0x10 +#define CMD_READ 0x20 +#define CMD_WRITE 0x30 +#define CMD_VERIFY 0x40 +#define CMD_FORMAT 0x50 +#define CMD_SEEK 0x70 +#define CMD_DIAGNOSE 0x90 +#define CMD_SET_PARAMETERS 0x91 +#define CMD_READ_PARAMETERS 0xec + +extern char ide_fn[7][512]; + +typedef struct esdi_drive_t +{ + int cfg_spt; + int cfg_hpc; + int current_cylinder; + hdd_file_t hdd_file; +} esdi_drive_t; + +typedef struct esdi_t +{ + uint8_t status; + uint8_t error; + int secount,sector,cylinder,head,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + + int drive_sel; + int reset; + uint16_t buffer[256]; + int irqstat; + + pc_timer_t callback_timer; + + esdi_drive_t drives[2]; + + rom_t bios_rom; +} esdi_t; + +uint16_t esdi_readw(uint16_t port, void *p); +void esdi_writew(uint16_t port, uint16_t val, void *p); + +static inline void esdi_irq_raise(esdi_t *esdi) +{ +// pclog("IDE_IRQ_RAISE\n"); + if (!(esdi->fdisk&2)) + picint(1 << 14); + + esdi->irqstat=1; +} + +static inline void esdi_irq_lower(esdi_t *esdi) +{ + picintc(1 << 14); +} + +void esdi_irq_update(esdi_t *esdi) +{ + if (esdi->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(esdi->fdisk & 2)) + picint(1 << 14); +} + +/* + * Return the sector offset for the current register values + */ +int esdi_get_sector(esdi_t *esdi, off64_t *addr) +{ + esdi_drive_t *drive = &esdi->drives[esdi->drive_sel]; + int heads = drive->cfg_hpc; + int sectors = drive->cfg_spt; + + if (esdi->head > heads) + { + pclog("esdi_get_sector: past end of configured heads\n"); + return 1; + } + if (esdi->sector >= sectors+1) + { + pclog("esdi_get_sector: past end of configured sectors\n"); + return 1; + } + + if (drive->cfg_spt == drive->hdd_file.spt && drive->cfg_hpc == drive->hdd_file.hpc) + { + *addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) * + sectors) + (esdi->sector - 1); + } + else + { + /*When performing translation, the firmware seems to leave 1 + sector per track inaccessible (spare sector)*/ + int c, h, s; + *addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) * + sectors) + (esdi->sector - 1); + + s = *addr % (drive->hdd_file.spt - 1); + h = (*addr / (drive->hdd_file.spt - 1)) % drive->hdd_file.hpc; + c = (*addr / (drive->hdd_file.spt - 1)) / drive->hdd_file.hpc; + + *addr = ((((off64_t) c * drive->hdd_file.hpc) + h) * + drive->hdd_file.spt) + s; + } + + return 0; +} + +/** + * Move to the next sector using CHS addressing + */ +void esdi_next_sector(esdi_t *esdi) +{ + esdi_drive_t *drive = &esdi->drives[esdi->drive_sel]; + + esdi->sector++; + if (esdi->sector == (drive->cfg_spt + 1)) + { + esdi->sector = 1; + esdi->head++; + if (esdi->head == drive->cfg_hpc) + { + esdi->head = 0; + esdi->cylinder++; + if (drive->current_cylinder < drive->hdd_file.tracks) + drive->current_cylinder++; + } + } +} + +void esdi_write(uint16_t port, uint8_t val, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + +// pclog("esdi_write: addr=%04x val=%02x\n", port, val); + switch (port) + { + case 0x1F0: /* Data */ + esdi_writew(port, val | (val << 8), p); + return; + + case 0x1F1: /* Write precompenstation */ + esdi->cylprecomp = val; + return; + + case 0x1F2: /* Sector count */ + esdi->secount = val; + return; + + case 0x1F3: /* Sector */ + esdi->sector = val; + return; + + case 0x1F4: /* Cylinder low */ + esdi->cylinder = (esdi->cylinder & 0xFF00) | val; + return; + + case 0x1F5: /* Cylinder high */ + esdi->cylinder = (esdi->cylinder & 0xFF) | (val << 8); + return; + + case 0x1F6: /* Drive/Head */ + esdi->head = val & 0xF; + esdi->drive_sel = (val & 0x10) ? 1 : 0; + if (esdi->drives[esdi->drive_sel].hdd_file.f == NULL) + esdi->status = 0; + else + esdi->status = STAT_READY | STAT_DSC; + return; + + case 0x1F7: /* Command register */ +// if (esdi->drives[esdi->drive_sel].hdd_file.f == NULL && val != CMD_SET_PARAMETERS && val != CMD_NOP && val != 0xe0 && (val & ~3) != 0x20 && (val & ~3) != 0x30 && (val & ~3) != 0x40 && val != 0x90 && val != CMD_READ_PARAMETERS) +// fatal("Command %02x on non-present drive\n", val); + + esdi_irq_lower(esdi); + esdi->command = val; + esdi->error = 0; + + switch (val & 0xf0) + { + case CMD_RESTORE: +// pclog("Restore\n"); + esdi->command &= ~0x0f; /*Mask off step rate*/ + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 200*IDE_TIME); + break; + + case CMD_SEEK: +// pclog("Seek to cylinder %i\n", esdi->cylinder); + esdi->command &= ~0x0f; /*Mask off step rate*/ + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 200*IDE_TIME); + break; + + default: + switch (val) + { + case CMD_NOP: + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 200*IDE_TIME); + break; + + case CMD_READ: case CMD_READ+1: + case CMD_READ+2: case CMD_READ+3: +// pclog("Read %i sectors from sector %i cylinder %i head %i %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head,ins); + esdi->command &= ~3; + if (val & 2) + fatal("Read with ECC\n"); + case 0xa0: + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 200*IDE_TIME); + break; + + case CMD_WRITE: case CMD_WRITE+1: + case CMD_WRITE+2: case CMD_WRITE+3: +// pclog("Write %i sectors to sector %i cylinder %i head %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head); + esdi->command &= ~3; + if (val & 2) + fatal("Write with ECC\n"); + esdi->status = STAT_DRQ | STAT_DSC;// | STAT_BUSY; + esdi->pos=0; + break; + + case CMD_VERIFY: case CMD_VERIFY+1: +// pclog("Read verify %i sectors from sector %i cylinder %i head %i\n",esdi->secount,esdi->sector,esdi->cylinder,esdi->head); + esdi->command &= ~1; + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 200 * IDE_TIME); + break; + + case CMD_FORMAT: +// pclog("Format track %i head %i\n", esdi->cylinder, esdi->head); + esdi->status = STAT_DRQ;// | STAT_BUSY; + esdi->pos=0; + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 30*IDE_TIME); + break; + + case CMD_DIAGNOSE: /* Execute Drive Diagnostics */ + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 200*IDE_TIME); + break; + + case 0xe0: /*???*/ + case CMD_READ_PARAMETERS: + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 200*IDE_TIME); + break; + + default: + pclog("Bad esdi command %02X\n", val); + case 0xe8: /*???*/ + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 200*IDE_TIME); + break; + } + } + break; + + case 0x3F6: /* Device control */ + if ((esdi->fdisk & 4) && !(val & 4)) + { + timer_set_delay_u64(&esdi->callback_timer, 500*IDE_TIME); + esdi->reset = 1; + esdi->status = STAT_BUSY; +// pclog("esdi Reset\n"); + } + if (val & 4) + { + /*Drive held in reset*/ + timer_disable(&esdi->callback_timer); + esdi->status = STAT_BUSY; + } + esdi->fdisk = val; + esdi_irq_update(esdi); + return; + } +// fatal("Bad ESDI write %04X %02X\n", port, val); +} + +void esdi_writew(uint16_t port, uint16_t val, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + +// pclog("Write ESDIw %04X\n",val); + esdi->buffer[esdi->pos >> 1] = val; + esdi->pos += 2; + + if (esdi->pos >= 512) + { + esdi->pos = 0; + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 6*IDE_TIME); + } +} + +uint8_t esdi_read(uint16_t port, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + uint8_t temp = 0xff; + + switch (port) + { + case 0x1F0: /* Data */ + temp = esdi_readw(port, esdi) & 0xff; + break; + + case 0x1F1: /* Error */ + temp = esdi->error; + break; + + case 0x1F2: /* Sector count */ + temp = (uint8_t)esdi->secount; + break; + + case 0x1F3: /* Sector */ + temp = (uint8_t)esdi->sector; + break; + + case 0x1F4: /* Cylinder low */ + temp = (uint8_t)(esdi->cylinder&0xFF); + break; + + case 0x1F5: /* Cylinder high */ + temp = (uint8_t)(esdi->cylinder>>8); + break; + + case 0x1F6: /* Drive/Head */ + temp = (uint8_t)(esdi->head | (esdi->drive_sel ? 0x10 : 0) | 0xa0); + break; + + case 0x1F7: /* Status */ + esdi_irq_lower(esdi); + temp = esdi->status; + break; + } + +// if (port != 0x1f7) pclog("esdi_read: addr=%04x val=%02x %04X:%04x\n", port, temp, CS, cpu_state.pc); + return temp; +} + +uint16_t esdi_readw(uint16_t port, void *p) +{ + esdi_t *esdi = (esdi_t *)p; + uint16_t temp; + + temp = esdi->buffer[esdi->pos >> 1]; + esdi->pos += 2; + + if (esdi->pos >= 512) + { +// pclog("Over! packlen %i %i\n",ide->packlen,ide->pos); + esdi->pos=0; + esdi->status = STAT_READY | STAT_DSC; + if (esdi->command == CMD_READ || esdi->command == 0xa0) + { + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) + { + esdi_next_sector(esdi); + esdi->status = STAT_BUSY; + timer_set_delay_u64(&esdi->callback_timer, 6*IDE_TIME); + } + } + } + +// pclog("esdi_readw: temp=%04x %i\n", temp, esdi->pos); + return temp; +} + +void esdi_callback(void *p) +{ + esdi_t *esdi = (esdi_t *)p; + esdi_drive_t *drive = &esdi->drives[esdi->drive_sel]; + off64_t addr; + +// pclog("esdi_callback: command=%02x reset=%i\n", esdi->command, esdi->reset); + + if (esdi->reset) + { + esdi->status = STAT_READY | STAT_DSC; + esdi->error = 1; + esdi->secount = 1; + esdi->sector = 1; + esdi->head = 0; + esdi->cylinder = 0; + esdi->reset = 0; +// pclog("Reset callback\n"); + return; + } + switch (esdi->command) + { + case CMD_RESTORE: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + drive->current_cylinder = 0; + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_SEEK: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_READ: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + if (esdi_get_sector(esdi, &addr)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + if (hdd_read_sectors(&drive->hdd_file, addr, 1, esdi->buffer)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + esdi->pos = 0; + esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; +// 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; + esdi_irq_raise(esdi); + readflash_set(READFLASH_HDC, esdi->drive_sel); + } + break; + + case CMD_WRITE: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + if (esdi_get_sector(esdi, &addr)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + if (hdd_write_sectors(&drive->hdd_file, addr, 1, esdi->buffer)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + esdi_irq_raise(esdi); + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) + { + esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; + esdi->pos = 0; + esdi_next_sector(esdi); + } + else + esdi->status = STAT_READY | STAT_DSC; + readflash_set(READFLASH_HDC, esdi->drive_sel); + } + break; + + case CMD_VERIFY: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + if (esdi_get_sector(esdi, &addr)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + if (hdd_read_sectors(&drive->hdd_file, addr, 1, esdi->buffer)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + readflash_set(READFLASH_HDC, esdi->drive_sel); + esdi_next_sector(esdi); + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) + timer_set_delay_u64(&esdi->callback_timer, 6*IDE_TIME); + else + { + esdi->pos = 0; + esdi->status = STAT_READY | STAT_DSC; +// pclog("Read verify callback %i %i %i offset %08X %i left\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount); + esdi_irq_raise(esdi); + } + } + break; + + case CMD_FORMAT: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + if (esdi_get_sector(esdi, &addr)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + if (hdd_format_sectors(&drive->hdd_file, addr, esdi->secount)) + { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY | STAT_DSC | STAT_ERR; + esdi_irq_raise(esdi); + break; + } + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + readflash_set(READFLASH_HDC, esdi->drive_sel); + } + break; + + case CMD_DIAGNOSE: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + esdi->error = 1; /*No error detected*/ + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + drive->cfg_spt = esdi->secount; + drive->cfg_hpc = esdi->head+1; + pclog("Parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc); + if (!esdi->secount) + fatal("secount=0\n"); + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case CMD_NOP: + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + break; + + case 0xe0: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + switch (esdi->cylinder >> 8) + { + case 0x31: + esdi->cylinder = drive->hdd_file.tracks; + break; + case 0x33: + esdi->cylinder = drive->hdd_file.hpc; + break; + case 0x35: + esdi->cylinder = 0x200; + break; + case 0x36: + esdi->cylinder = drive->hdd_file.spt; + break; + default: + pclog("EDSI Bad read config %02x\n", esdi->cylinder >> 8); + } + esdi->status = STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + case 0xa0: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + memset(esdi->buffer, 0, 512); + memset(&esdi->buffer[3], 0xff, 512-6); + esdi->pos = 0; + esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; +// 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; + esdi_irq_raise(esdi); + } + break; + + case CMD_READ_PARAMETERS: + if (!drive->hdd_file.f) + { + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + } + else + { + memset(esdi->buffer, 0, 512); + + esdi->buffer[0] = 0x44; /* general configuration */ + esdi->buffer[1] = drive->hdd_file.tracks; /* number of non-removable cylinders */ + esdi->buffer[2] = 0; /* number of removable cylinders */ + esdi->buffer[3] = drive->hdd_file.hpc; /* number of heads */ + esdi->buffer[5] = esdi->buffer[4] * drive->hdd_file.spt; /* number of unformatted bytes/sector */ + esdi->buffer[4] = 600; /* number of unformatted bytes/track */ + esdi->buffer[6] = drive->hdd_file.spt; /* number of sectors */ + esdi->buffer[7] = 0; /*minimum bytes in inter-sector gap*/ + esdi->buffer[8] = 0; /* minimum bytes in postamble */ + esdi->buffer[9] = 0; /* number of words of vendor status */ + /* controller info */ +// char wdp_cnsn[20]; /* controller serial number */ + esdi->buffer[20] = 2; /* controller type */ + esdi->buffer[21] = 1; /* sector buffer size, in sectors */ + esdi->buffer[22] = 0; /* ecc bytes appended */ +// char wdp_rev[8]; /* firmware revision */ + //27 + esdi->buffer[27] = 'W' | ('D' << 8); + esdi->buffer[28] = '1' | ('0' << 8); + esdi->buffer[29] = '0' | ('7' << 8); + esdi->buffer[30] = 'V' | ('-' << 8); + esdi->buffer[31] = 'S' | ('E' << 8); + esdi->buffer[32] = '1'; + esdi->buffer[47] = 0; /* sectors per interrupt */ + esdi->buffer[48] = 0;/* can use double word read/write? */ + esdi->pos = 0; + esdi->status = STAT_DRQ | STAT_READY | STAT_DSC; + esdi_irq_raise(esdi); + } + break; + + default: + pclog("ESDI Callback on unknown command %02x\n", esdi->command); + case 0xe8: + esdi->status = STAT_READY | STAT_ERR | STAT_DSC; + esdi->error = ERR_ABRT; + esdi_irq_raise(esdi); + break; + } +} + +static void esdi_rom_write(uint32_t addr, uint8_t val, void *p) +{ + rom_t *rom = (rom_t *)p; + + addr &= rom->mask; + + if (addr >= 0x1f00 && addr < 0x2000) + rom->rom[addr] = val; +} + +void *wd1007vse1_init() +{ + esdi_t *esdi = malloc(sizeof(esdi_t)); + memset(esdi, 0, sizeof(esdi_t)); + + hdd_load(&esdi->drives[0].hdd_file, 0, ide_fn[0]); + hdd_load(&esdi->drives[1].hdd_file, 1, ide_fn[1]); + + esdi->drives[0].cfg_spt = esdi->drives[0].hdd_file.spt; + esdi->drives[0].cfg_hpc = esdi->drives[0].hdd_file.hpc; + esdi->drives[1].cfg_spt = esdi->drives[1].hdd_file.spt; + esdi->drives[1].cfg_hpc = esdi->drives[1].hdd_file.hpc; + + esdi->status = STAT_READY | STAT_DSC; + esdi->error = 1; /*No errors*/ + + rom_init(&esdi->bios_rom, "62-000279-061.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_set_handler(&esdi->bios_rom.mapping, + rom_read, rom_readw, rom_readl, + esdi_rom_write, NULL, NULL); + + io_sethandler(0x01f0, 0x0001, esdi_read, esdi_readw, NULL, esdi_write, esdi_writew, NULL, esdi); + io_sethandler(0x01f1, 0x0007, esdi_read, NULL, NULL, esdi_write, NULL, NULL, esdi); + io_sethandler(0x03f6, 0x0001, NULL, NULL, NULL, esdi_write, NULL, NULL, esdi); + + timer_add(&esdi->callback_timer, esdi_callback, esdi, 0); + + return esdi; +} + +void wd1007vse1_close(void *p) +{ + esdi_t *esdi = (esdi_t *)p; + + hdd_close(&esdi->drives[0].hdd_file); + hdd_close(&esdi->drives[1].hdd_file); + + free(esdi); +} + +static int wd1007vse1_available() +{ + return rom_present("62-000279-061.bin"); +} + +device_t wd1007vse1_device = +{ + "Western Digital WD1007V-SE1 (ESDI)", + DEVICE_AT, + wd1007vse1_init, + wd1007vse1_close, + wd1007vse1_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/esdi_at.h b/src/esdi_at.h new file mode 100644 index 0000000..75efd32 --- /dev/null +++ b/src/esdi_at.h @@ -0,0 +1 @@ +extern device_t wd1007vse1_device; diff --git a/src/f82c710_upc.c b/src/f82c710_upc.c new file mode 100644 index 0000000..40dfd19 --- /dev/null +++ b/src/f82c710_upc.c @@ -0,0 +1,529 @@ +/* + * Chips & Technologies F82C710 Universal Peripheral Controller (UPC) + * + * Copyright (c) 2020 Eluan Costa Miranda All rights reserved. + * + * 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 3 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, see . + * + * ============================================================================= + * + * This SuperIO chip is commonly seem paired with the Single-chip AT (SCAT) + * chip. Only the functionality needed for the Hyundai Super-286TR BIOS is + * implented for now. + * + * One of the goals of this chip was getting rid of jumpers and have everything + * configured by software, but there is no configuration for serial and + * parallel IRQs. Because of that, motherboards still supply jumpers for these + * two signals. + * + */ + +#include "ibm.h" + +#include "fdc.h" +#include "ide.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" +#include "x86.h" +#include "keyboard_at.h" +#include "pic.h" + +#define UPC_MOUSE_DEV_IDLE 0x01 /* bit 0, Device Idle */ +#define UPC_MOUSE_RX_FULL 0x02 /* bit 1, Device Char received */ +#define UPC_MOUSE_TX_IDLE 0x04 /* bit 2, Device XMIT Idle */ +#define UPC_MOUSE_RESET 0x08 /* bit 3, Device Reset */ +#define UPC_MOUSE_INTS_ON 0x10 /* bit 4, Device Interrupt On */ +#define UPC_MOUSE_ERROR_FLAG 0x20 /* bit 5, Device Error */ +#define UPC_MOUSE_CLEAR 0x40 /* bit 6, Device Clear */ +#define UPC_MOUSE_ENABLE 0x80 /* bit 7, Device Enable */ + +typedef struct upc_t +{ + int configuration_state; // state of algorithm to enter configuration mode + int configuration_mode; + uint8_t next_value; // next expected value of configuration algorithm + uint16_t cri_addr; // cri = configuration index register, addr is even + uint16_t cap_addr; // cap = configuration access port, addr is odd and is cri_addr + 1 + uint8_t cri; // currently indexed register + + // these regs are not affected by reset + uint8_t regs[15]; // there are 16 indexes, but there is no need to store the last one which is: R = cri_addr / 4, W = exit config mode + + int serial_irq; + int parallel_irq; // TODO: currently not implemented in PCem + + int mouse_irq; + uint16_t mdata_addr; // Address of PS/2 data register + uint16_t mstat_addr; // Address of PS/2 status register + uint8_t mouse_status; // Mouse interface status register + uint8_t mouse_data; // Mouse interface data register + void (*mouse_write)(uint8_t val, void *p); + void *mouse_p; + pc_timer_t mouse_delay_timer; +} upc_t; + +static upc_t upc; + +uint8_t upc_config_read(uint16_t port, void *priv); +void upc_config_write(uint16_t port, uint8_t val, void *priv); + +void upc_mouse_disable(upc_t *upc); +void upc_mouse_enable(upc_t *upc); +uint8_t upc_mouse_read(uint16_t port, void *priv); +void upc_mouse_write(uint16_t port, uint8_t val, void *priv); +void upc_mouse_poll(void *priv); + +void upc_update_config(upc_t *upc) +{ + switch(upc->cri) + { + case 0: + if (upc->regs[0] & 0x4) + { + serial1_set(upc->regs[4] * 4, upc->serial_irq); + pclog("UPC: UART at %04X, irq %d\n", upc->regs[4] * 4, upc->serial_irq); + } + else + { + serial1_remove(); + pclog("UPC: UART disabled\n"); + } + if (upc->regs[0] & 0x8) + { + lpt1_init(upc->regs[6] * 4); + pclog("UPC: PARALLEL at %04X, irq %d\n", upc->regs[6] * 4, upc->parallel_irq); + } + else + { + lpt1_remove(); + pclog("UPC: PARALLEL disabled\n"); + } + if ((upc->regs[0] & 0x60) != 0) + pclog("UPC: Oscillator control not implemented!\n"); + break; + + case 1: + if ((upc->regs[1] & 0x80) != 0) + pclog("UPC: Restricted serial reset not implemented!\n"); + if ((upc->regs[1] & 0x80) != 0) + pclog("UPC: Restricted serial reset not implemented!\n"); + if ((upc->regs[1] & 0x40) != 0) + pclog("UPC: Bidirectional parallel port support not implemented!\n"); + if ((upc->regs[1] & 0x38) != 0) + pclog("UPC: UART force CTS, DSR, DCD not implemented!\n"); + break; + + case 2: + if ((upc->regs[2] & 0x70) != 0) + pclog("UPC: UART clock control not implemented!\n"); + break; + + case 9: + if (upc->regs[9] == 0xb0) + pclog("UPC: GPCS not implemented! (at default address: %04X)\n", upc->regs[9] * 4); + else if (upc->regs[9] != 0) + pclog("UPC: GPCS not implemented! (at address: %04X)\n", upc->regs[9] * 4); + break; + + case 12: + /* Adding the IDE and floppy controllers when they are already present causes problems.*/ + /* FIX: remove floppy and IDE controllers before adding them again if needed. */ + fdc_remove(); + ide_pri_disable(); + if ((upc->regs[12] & 0x40) != 0) + { + pclog("UPC: IDE XT mode not implemented!\n"); + } + else + { + if (upc->regs[12] & 0x80) + { + ide_pri_enable(); + pclog("UPC: AT IDE enabled\n"); + } + else + { + pclog("UPC: AT IDE disabled\n"); + } + } + + if (upc->regs[12] & 0x20) + { + fdc_add(); + pclog("UPC: FDC enabled\n"); + } + else + { + pclog("UPC: FDC disabled\n"); + } + + if ((upc->regs[12] & 0x10) != 0) + pclog("UPC: FDC power down mode not implemented!\n"); + if ((upc->regs[12] & 0x0C) != 0) + pclog("UPC: RTCCS not implemented!\n"); + if ((upc->regs[12] & 0x01) != 0) + pclog("UPC: PS/2 mouse port power down not implemented!\n"); + break; + + case 13: + if (upc->regs[13] != 0) + { + upc->mdata_addr = upc->regs[13] * 4; + upc->mstat_addr = upc->mdata_addr + 1; + pclog("UPC: PS/2 mouse port at %04X, irq %d\n", upc->mdata_addr, upc->mouse_irq); + upc_mouse_enable(upc); + } + else + { + pclog("UPC: PS/2 mouse port disabled\n"); + upc_mouse_disable(upc); + } + + case 14: + if (upc->regs[14] != 0) + pclog("UPC: Test mode not implemented!\n"); + break; + } +} + +uint8_t upc_config_read(uint16_t port, void *priv) +{ + upc_t *upc = (upc_t *)priv; + uint8_t temp = 0xff; + + if (upc->configuration_mode) + { + if (port == upc->cri_addr) + { + temp = upc->cri; + } + else if (port == upc->cap_addr) + { + if (upc->cri == 0xf) + temp = upc->cri_addr / 4; + else + temp = upc->regs[upc->cri]; + } + } + +// pclog("UPC READ : %04X, %02X\n", port, temp); + return temp; +} + +void upc_config_write(uint16_t port, uint8_t val, void *priv) +{ + upc_t *upc = (upc_t *)priv; + int configuration_state_event = 0; + +// pclog("UPC WRITE: %04X, %02X\n", port, val); + + switch(port) + { + case 0x2fa: + /* Execute configuration step 1 for any value except 9, ff or 36 */ + if (upc->configuration_state == 0) + { + configuration_state_event = 1; + /* next value should be the 1's complement of the current one */ + upc->next_value = 0xff - val; + } + else if (upc->configuration_state == 4) + { + uint8_t addr_verify = upc->cri_addr / 4; + addr_verify += val; + if (addr_verify == 0xff) + { + upc->configuration_mode = 1; + // TODO: is the value of cri reset here or when exiting configuration mode? + io_sethandler(upc->cri_addr, 0x0002, upc_config_read, NULL, NULL, upc_config_write, NULL, NULL, upc); + pclog("UPC: in configuration mode at %04X\n", upc->cri_addr); + } + else + { + upc->configuration_mode = 0; + pclog("UPC: configuration mode failed (sum = %02X)\n", addr_verify); + } + } + break; + case 0x3fa: + /* go to configuration step 2 if value is the expected one */ + if (upc->configuration_state == 1 && val == upc->next_value) + configuration_state_event = 1; + else if (upc->configuration_state == 2 && val == 0x36) + configuration_state_event = 1; + else if (upc->configuration_state == 3) + { + upc->cri_addr = val * 4; + upc->cap_addr = upc->cri_addr + 1; + configuration_state_event = 1; + } + break; + default: + break; + } + if (upc->configuration_mode) + { + if (port == upc->cri_addr) + { + upc->cri = val & 0xf; + + } + else if (port == upc->cap_addr) + { + if (upc->cri == 0xf) + { + pclog("UPC: exiting configuration mode\n"); + upc->configuration_mode = 0; + io_removehandler(upc->cri_addr, 0x0002, upc_config_read, NULL, NULL, upc_config_write, NULL, NULL, upc); + } + else + { + upc->regs[upc->cri] = val; + /* configuration should be updated at each register write, otherwise PC5086 do not detect ports correctly */ + upc_update_config(upc); + } + } + } + + // TODO: is the state only reset when accessing 0x2fa and 0x3fa wrongly? + if ((port == 0x2fa || port == 0x3fa) && configuration_state_event) + upc->configuration_state++; + else + upc->configuration_state = 0; +} + +static void *upc_init() +{ + pclog("UPC INIT\n"); + + /* Disable all peripherals. upc_update_config will enable configured peripherals */ + serial1_remove(); + serial2_remove(); + lpt1_remove(); + lpt2_remove(); + fdc_remove(); + ide_pri_disable(); + ide_sec_disable(); + serial1_set_has_fifo(0); + + memset(&upc, 0, sizeof(upc)); + + upc.serial_irq = device_get_config_int("serial_irq"); + upc.parallel_irq = device_get_config_int("parallel_irq"); + + // because of these addresses, serial ports must be 16450 without fifos + io_sethandler(0x02fa, 0x0001, NULL, NULL, NULL, upc_config_write, NULL, NULL, &upc); + io_sethandler(0x03fa, 0x0001, NULL, NULL, NULL, upc_config_write, NULL, NULL, &upc); + + upc.regs[0] = 0x0c; + upc.regs[1] = 0x00; + upc.regs[2] = 0x00; + upc.regs[3] = 0x00; + upc.regs[4] = 0xfe; + upc.regs[5] = 0x00; + upc.regs[6] = 0x9e; + upc.regs[7] = 0x00; + upc.regs[8] = 0x00; + upc.regs[9] = 0xb0; + upc.regs[10] = 0x00; + upc.regs[11] = 0x00; + upc.regs[12] = 0xa0; + upc.regs[13] = 0x00; + upc.regs[14] = 0x00; + + for (upc.cri = 0; upc.cri < 15; upc.cri++) + upc_update_config(&upc); + upc.cri = 0; + + /********************* Initialize mouse interface ********************/ + if(romset == ROM_PC5086) /* IRQ is 2 for PC5086 and 12 for others */ + upc.mouse_irq = 2; + else + upc.mouse_irq = 12; + upc.mdata_addr = upc.regs[13] * 4; + upc.mstat_addr = upc.mdata_addr + 1; + upc.mouse_status = UPC_MOUSE_DEV_IDLE | UPC_MOUSE_TX_IDLE; + upc.mouse_data = 0xff; + /* Set timer for mouse polling */ + timer_add(&upc.mouse_delay_timer, upc_mouse_poll, &upc, 1); + + return &upc; +} + +static device_config_t upc_config[] = +{ + { + .name = "serial_irq", + .description = "Serial Port IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 4 (for address 0x3F8/COM1)", + .value = 4 + }, + { + .description = "IRQ 3 (for address 0x2F8/COM2)", + .value = 3 + }, + { + .description = "Disabled", + .value = 0 // TODO: see if this breaks PCem's PIC + } + }, + .default_int = 4 + }, + { + .name = "parallel_irq", + .description = "Parallel Port IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 7 (for address 0x378/LPTB)", + .value = 7 + }, + { + .description = "IRQ 5 (for address 0x278/LPTC)", + .value = 5 + }, + { + .description = "Disabled", + .value = 0 // TODO: see if this breaks PCem's PIC + } + }, + .default_int = 7 + }, + // For the Hyundai Super-286TR, the only other jumper is the Color/Mono one and it's handled by the at keyboard controller code. + { + .type = -1 + } +}; + + +device_t f82c710_upc_device = +{ + "F82C710 UPC", + 0, + upc_init, + NULL, + NULL, + NULL, + NULL, + NULL, + upc_config +}; + +/****************** PS/2 mouse port *********************/ +uint8_t upc_mouse_read(uint16_t port, void *priv) +{ + upc_t *upc = (upc_t *)priv; + uint8_t temp = 0xff; + if (port == upc->mstat_addr) + { + temp = upc->mouse_status; + } + + if (port == upc->mdata_addr && (upc->mouse_status & UPC_MOUSE_RX_FULL)) + { + temp = upc->mouse_data; + upc->mouse_data = 0xff; + upc->mouse_status &= ~UPC_MOUSE_RX_FULL; + upc->mouse_status |= UPC_MOUSE_DEV_IDLE; + // pclog("%04X:%04X UPC mouse READ: %04X, %02X\n", CS, cpu_state.pc, port, temp); + } + + // pclog("%04X:%04X UPC mouse READ: %04X, %02X\n", CS, cpu_state.pc, port, temp); + return temp; +} + +void upc_mouse_write(uint16_t port, uint8_t val, void *priv) +{ + // pclog("%04X:%04X UPC mouse WRITE: %04X, %02X\n", CS, cpu_state.pc, port, val); + + upc_t *upc = (upc_t *)priv; + if (port == upc->mstat_addr) + { + /* write status bits + * DEV_IDLE, TX_IDLE, RX_FULL and ERROR_FLAG bits are unchanged + */ + upc->mouse_status = (val & 0xD8) | (upc->mouse_status & 0x27); + if (upc->mouse_status & UPC_MOUSE_ENABLE) + mouse_scan = 1; + else + mouse_scan = 0; + if (upc->mouse_status & (UPC_MOUSE_CLEAR | UPC_MOUSE_RESET)) + { + /* if CLEAR or RESET bit is set, clear mouse queue */ + mouse_queue_start = mouse_queue_end; + upc->mouse_status &= ~UPC_MOUSE_RX_FULL; + upc->mouse_status |= UPC_MOUSE_DEV_IDLE | UPC_MOUSE_TX_IDLE; + mouse_scan = 0; + } + } + + if (port == upc->mdata_addr) + { + if ((upc->mouse_status & UPC_MOUSE_TX_IDLE) && (upc->mouse_status & UPC_MOUSE_ENABLE)) + { + upc->mouse_data = val; + if (upc->mouse_write) + upc->mouse_write(val, upc->mouse_p); + } + } +} + +void upc_mouse_disable(upc_t *upc) +{ + io_removehandler(upc->mdata_addr, 0x0002, upc_mouse_read, NULL, NULL, upc_mouse_write, NULL, NULL, upc); +} + +void upc_mouse_enable(upc_t *upc) +{ + io_sethandler(upc->mdata_addr, 0x0002, upc_mouse_read, NULL, NULL, upc_mouse_write, NULL, NULL, upc); +} + +void upc_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p) +{ + upc.mouse_write = mouse_write; + upc.mouse_p = p; +} + +void upc_mouse_poll(void *priv) +{ + upc_t *upc = (upc_t *)priv; + timer_advance_u64(&upc->mouse_delay_timer, (1000 * TIMER_USEC)); + + /* check if there is something in the mouse queue */ + if (mouse_queue_start != mouse_queue_end) + { + // pclog("Mouse timer. %d %d %02X %02X\n", mouse_queue_start, mouse_queue_end, upc->mouse_status, upc->mouse_data); + if ((upc->mouse_status & UPC_MOUSE_ENABLE) && !(upc->mouse_status & UPC_MOUSE_RX_FULL)) + { + upc->mouse_data = mouse_queue[mouse_queue_start]; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + /* update mouse status */ + upc->mouse_status |= UPC_MOUSE_RX_FULL; + upc->mouse_status &= ~(UPC_MOUSE_DEV_IDLE); + // pclog("Reading %02X from the mouse queue at %i %i. New status is %02X\n", upc->mouse_data, mouse_queue_start, mouse_queue_end, upc->mouse_status); + /* raise IRQ if enabled */ + if (upc->mouse_status & UPC_MOUSE_INTS_ON) + { + picint(1 << upc->mouse_irq); + // pclog("upc_mouse : take IRQ %d\n", upc->mouse_irq); + } + } + } +} diff --git a/src/f82c710_upc.h b/src/f82c710_upc.h new file mode 100644 index 0000000..05764af --- /dev/null +++ b/src/f82c710_upc.h @@ -0,0 +1,6 @@ +#include "device.h" + +void upc_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p); + +extern device_t f82c710_upc_device; + diff --git a/src/fdc.c b/src/fdc.c index 3714324..eb70169 100644 --- a/src/fdc.c +++ b/src/fdc.c @@ -5,12 +5,22 @@ #include "disc.h" #include "disc_sector.h" #include "dma.h" +#include "fdc.h" #include "fdd.h" #include "io.h" #include "pic.h" #include "timer.h" +#include "x86.h" -extern int motoron; +#define ST1_DE (1 << 5) +#define ST1_ND (1 << 2) +#define ST1_NW (1 << 1) +#define ST1_MA (1 << 0) + +#define ST2_DD (1 << 5) +#define ST2_WC (1 << 4) /*Wrong cylinder*/ +#define ST2_BC (1 << 1) /*Bad cylinder*/ +#define ST2_MD (1 << 0) static int fdc_reset_stat = 0; /*FDC*/ @@ -35,11 +45,10 @@ typedef struct FDC int format_state; int tc; int written; - int in_seek_mt; - + int pcjr, ps1; - int watchdog_timer; + pc_timer_t watchdog_timer; int watchdog_count; int data_ready; @@ -63,12 +72,15 @@ typedef struct FDC int fifo, tfifo; int fifobufpos; uint8_t fifobuf[16]; + + int int_pending; + + pc_timer_t timer; } FDC; static FDC fdc; void fdc_callback(); -int timetolive; //#define SECTORS 9 int lastbyte=0; uint8_t disc_3f7; @@ -85,7 +97,7 @@ void fdc_reset() fdc.lock = 0; fdc.head = 0; fdc.abort = 0; - if (!AT) + if (!AT && romset != ROM_XI8088 && romset != ROM_PC5086) { fdc.rate = 2; // fdc_update_rate(); @@ -149,12 +161,11 @@ static void fdc_watchdog_poll(void *p) fdc->watchdog_count--; if (fdc->watchdog_count) - fdc->watchdog_timer += 1000 * TIMER_USEC; + timer_advance_u64(&fdc->watchdog_timer, 1000 * TIMER_USEC); else { // pclog("Watchdog timed out\n"); - fdc->watchdog_timer = 0; if (fdc->dor & 0x20) picint(1 << 6); } @@ -320,6 +331,8 @@ 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; + cycles -= ISA_CYCLES(8); + switch (addr&7) { case 1: return; @@ -330,44 +343,29 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) { if ((fdc.dor & 0x40) && !(val & 0x40)) { - fdc.watchdog_timer = 1000 * TIMER_USEC; + timer_set_delay_u64(&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(); + timer_set_delay_u64(&fdc.timer, 8 * TIMER_USEC); discint=-1; fdc_reset(); } - motoron = val & 0x01; + disc_set_motor_enable(val & 0x01); fdc.drive = 0; -/* if (motoron) - 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(); + timer_set_delay_u64(&fdc.timer, 8 * TIMER_USEC); discint=-1; fdc_reset(); } - timer_process(); - motoron = (val & 0xf0) ? 1 : 0; - timer_update_outstanding(); + disc_set_motor_enable((val & 0xf0) ? 1 : 0); fdc.drive = val & 3; } fdc.dor=val; @@ -384,9 +382,7 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) case 4: if (val & 0x80) { - timer_process(); - disctime = 128 * (1 << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc.timer, 8 * TIMER_USEC); discint=-1; fdc_reset(); } @@ -413,11 +409,10 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) { fdc.tc = 0; fdc.data_ready = 0; - fdc.in_seek_mt = 0; - + fdc.command=val; // pclog("Starting FDC command %02X\n",fdc.command); - switch (fdc.command&0x1F) + switch (fdc.command) { case 1: /*Mode*/ if (!fdc.is_nsc) goto bad_command; @@ -428,23 +423,23 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.format_state = 0; break; - case 2: /*Read track*/ + case 0x02: case 0x42: /*Read track*/ fdc.pnum=0; fdc.ptot=8; fdc.stat=0x90; fdc.pos=0; break; - case 3: /*Specify*/ + case 0x03: /*Specify*/ fdc.pnum=0; fdc.ptot=2; fdc.stat=0x90; break; - case 4: /*Sense drive status*/ + case 0x04: /*Sense drive status*/ fdc.pnum=0; fdc.ptot=1; fdc.stat=0x90; break; - case 5: /*Write data*/ + case 0x05: case 0x45: case 0x85: case 0xc5: /*Write data*/ // printf("Write data!\n"); fdc.pnum=0; fdc.ptot=8; @@ -452,40 +447,49 @@ void fdc_write(uint16_t addr, uint8_t val, void *priv) fdc.pos=0; // readflash=1; break; - case 6: /*Read data*/ + case 0x06: case 0x26: case 0x46: case 0x66: /*Read data*/ + case 0x86: case 0xa6: case 0xc6: case 0xe6: fdc.pnum=0; fdc.ptot=8; fdc.stat=0x90; fdc.pos=0; break; - case 7: /*Recalibrate*/ + case 0x07: /*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(); + case 0x08: /*Sense interrupt status*/ + if (fdc.int_pending || fdc_reset_stat) + { +// printf("Sense interrupt status %i\n",curdrive); + fdc.lastdrive = fdc.drive; +// fdc.stat = 0x10 | (fdc.stat & 0xf); + discint = 8; + fdc.pos = 0; + fdc_callback(); + } + else + { + fdc.stat=0x10; + discint=0xfc; + timer_set_delay_u64(&fdc.timer, 100 * TIMER_USEC); + } break; - case 10: /*Read sector ID*/ + case 0x0a: case 0x4a: /*Read sector ID*/ fdc.pnum=0; fdc.ptot=1; fdc.stat=0x90; fdc.pos=0; break; - case 0x0d: /*Format track*/ + case 0x0d: case 0x4d: case 0x8d: case 0xcd: /*Format track*/ fdc.pnum=0; fdc.ptot=5; fdc.stat=0x90; fdc.pos=0; fdc.format_state = 0; break; - case 15: /*Seek*/ + case 0x0f: /*Seek*/ fdc.pnum=0; fdc.ptot=2; fdc.stat=0x90; @@ -540,9 +544,7 @@ bad_command: // exit(-1); fdc.stat=0x10; discint=0xfc; - timer_process(); - disctime = 200 * (1 << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc.timer, 100 * TIMER_USEC); break; } } @@ -551,19 +553,19 @@ bad_command: fdc.params[fdc.pnum++]=val; if (fdc.pnum==fdc.ptot) { + uint64_t time; + // 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(); + timer_set_delay_u64(&fdc.timer, 256 * TIMER_USEC); // fdc.drive = fdc.params[0] & 3; disc_drivesel = fdc.drive & 1; fdc_reset_stat = 0; disc_set_drivesel(fdc.drive & 1); - switch (discint) + discint = fdc.command & 0x1f; + switch (fdc.command) { - case 2: /*Read a track*/ + case 0x02: case 0x42: /*Read track*/ fdc_rate(fdc.drive); fdc.head=fdc.params[2]; fdc.sector=fdc.params[3]; @@ -574,64 +576,71 @@ bad_command: fdc.track[fdc.drive]=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]); disc_readsector(fdc.drive, SECTOR_FIRST, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]); - disctime = 0; - readflash = 1; + timer_disable(&fdc.timer); + readflash_set(READFLASH_FDC, fdc.drive); fdc.inread = 1; break; - case 3: /*Specify*/ + case 0x03: /*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; + timer_disable(&fdc.timer); break; - case 5: /*Write data*/ + case 0x05: case 0x45: case 0x85: case 0xc5: /*Write data*/ fdc_rate(fdc.drive); fdc.head=fdc.params[2]; fdc.sector=fdc.params[3]; fdc.sector_size = fdc.params[4]; fdc.eot[fdc.drive] = fdc.params[5]; - if (fdc.config & 0x40) - fdd_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); - fdc.track[fdc.drive]=fdc.params[1]; fdc.rw_track = fdc.params[1]; - - disc_writesector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]); - disctime = 0; + if (fdc.config & 0x40) + { + fdd_seek(fdc.drive, fdc.rw_track - fdc.track[fdc.drive]); + fdc.track[fdc.drive] = fdc.rw_track; + } + + disc_writesector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); + timer_disable(&fdc.timer); fdc.written = 0; - readflash = 1; + readflash_set(READFLASH_FDC, fdc.drive); fdc.pos = 0; if (fdc.pcjr) fdc.stat = 0xb0; // ioc_fiq(IOC_FIQ_DISC_DATA); break; - case 6: /*Read data*/ + case 0x06: case 0x26: case 0x46: case 0x66: /*Read data*/ + case 0x86: case 0xa6: case 0xc6: case 0xe6: fdc_rate(fdc.drive); fdc.head=fdc.params[2]; fdc.sector=fdc.params[3]; fdc.sector_size = fdc.params[4]; fdc.eot[fdc.drive] = fdc.params[5]; - if (fdc.config & 0x40) - fdd_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); - fdc.track[fdc.drive]=fdc.params[1]; fdc.rw_track = fdc.params[1]; + if (fdc.config & 0x40) + { + fdd_seek(fdc.drive, fdc.rw_track - fdc.track[fdc.drive]); + fdc.track[fdc.drive] = fdc.rw_track; + } - disc_readsector(fdc.drive, fdc.sector, fdc.track[fdc.drive], fdc.head, fdc.rate, fdc.params[4]); - disctime = 0; - readflash = 1; + disc_readsector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); + timer_disable(&fdc.timer); + readflash_set(READFLASH_FDC, fdc.drive); fdc.inread = 1; break; - case 7: /*Recalibrate*/ + case 0x07: /*Recalibrate*/ fdc.stat = 1 << fdc.drive; - disctime = 0; - fdd_seek(fdc.drive, SEEK_RECALIBRATE); + timer_disable(&fdc.timer); + time = fdd_seek(fdc.drive, SEEK_RECALIBRATE); + if (time) + timer_set_delay_u64(&fdc.timer, time); break; - case 0x0d: /*Format*/ + case 0x0d: case 0x4d: case 0x8d: case 0xcd: /*Format*/ fdc_rate(fdc.drive); fdc.head = (fdc.params[0] & 4) ? 1 : 0; fdc.format_state = 1; @@ -639,27 +648,34 @@ bad_command: fdc.stat = 0x30; break; - case 0xf: /*Seek*/ + case 0x0f: /*Seek*/ fdc.stat = 1 << fdc.drive; - fdc.head = (fdc.params[0] & 4) ? 1 : 0; - disctime = 0; - fdd_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + fdc.head = 0; + timer_disable(&fdc.timer); + time = fdd_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + if (time) + timer_set_delay_u64(&fdc.timer, time); // pclog("Seek to %i\n", fdc.params[1]); break; - case 10: /*Read sector ID*/ + case 0x0a: case 0x4a: /*Read sector ID*/ fdc_rate(fdc.drive); - disctime = 0; + timer_disable(&fdc.timer); fdc.head = (fdc.params[0] & 4) ? 1 : 0; // pclog("Read sector ID %i %i\n", fdc.rate, fdc.drive); disc_readaddress(fdc.drive, fdc.track[fdc.drive], fdc.head, fdc.rate); break; + + case 0x94: /*Unlock*/ + discint = 0x94; + break; } } } return; case 7: - if (!AT) return; + if (!AT && romset != ROM_XI8088 && romset != ROM_PC5086) + return; fdc.rate=val&3; disc_3f7=val; @@ -675,6 +691,9 @@ uint8_t fdc_read(uint16_t addr, void *priv) { uint8_t temp; int drive; + + cycles -= ISA_CYCLES(8); + // /*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) { @@ -755,12 +774,6 @@ uint8_t fdc_read(uint16_t addr, void *priv) 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*/ @@ -788,11 +801,9 @@ uint8_t fdc_read(uint16_t addr, void *priv) void fdc_callback() { int temp; - int doseek = 0; int drive; - disctime = 0; -// pclog("fdc_callback %i %i\n", discint, disctime); +// pclog("fdc_callback %i\n", discint); // if (fdc.inread) // rpclog("c82c711_fdc_callback : while inread! %08X %i %02X %i\n", discint, fdc.drive, fdc.st0, ins); switch (discint) @@ -815,7 +826,7 @@ void fdc_callback() return; case 2: /*Read track*/ - readflash = 1; + readflash_set(READFLASH_FDC, fdc.drive); fdc.eot[fdc.drive]--; // pclog("Read a track callback, eot=%i\n", fdc.eot[fdc.drive]); if (!fdc.eot[fdc.drive] || fdc.tc) @@ -856,105 +867,84 @@ void fdc_callback() fdc.stat = (fdc.stat & 0xf) | 0xd0; paramstogo = 1; discint = 0; - disctime = 0; return; case 5: /*Write data*/ - if (!fdc.in_seek_mt) + readflash_set(READFLASH_FDC, fdc.drive); + if (fdc.sector == fdc.params[5]) { - readflash = 1; - fdc.sector++; - if (fdc.sector > fdc.params[5]) + fdc.sector = 1; + if (fdc.command & 0x80) { - fdc.sector = 1; - if (fdc.command & 0x80) - { - fdc.head ^= 1; - if (!fdc.head) - { - fdc.rw_track++; - doseek = 1; - } - } - else + fdc.head ^= 1; + if (!fdc.head) { fdc.rw_track++; fdc.tc = 1; } } - if (fdc.tc) + else { - discint=-2; - fdc_int(); - 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 (doseek) - { - fdd_seek(fdc.drive, 1); - fdc.in_seek_mt = 1; - /*Allow seek to complete before starting next sector write*/ - return; + fdc.rw_track++; + fdc.tc = 1; } } - fdc.in_seek_mt = 0; + else + fdc.sector++; + if (fdc.tc) + { + discint=-2; + fdc_int(); + 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; + } 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); - if (!fdc.in_seek_mt) + readflash_set(READFLASH_FDC, fdc.drive); + if (fdc.sector == fdc.params[5]) { - readflash = 1; - fdc.sector++; - if (fdc.sector > fdc.params[5]) + fdc.sector = 1; + if (fdc.command & 0x80) { - fdc.sector = 1; - if (fdc.command & 0x80) - { - fdc.head ^= 1; - if (!fdc.head) - { - fdc.rw_track++; - doseek = 1; - } - } - else + fdc.head ^= 1; + if (!fdc.head) { fdc.rw_track++; fdc.tc = 1; } } - if (fdc.tc) + else { - fdc.inread = 0; - discint=-2; - fdc_int(); - 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 (doseek) - { - fdd_seek(fdc.drive, 1); - fdc.in_seek_mt = 1; - /*Allow seek to complete before starting next sector read*/ - return; + fdc.rw_track++; + fdc.tc = 1; } } - fdc.in_seek_mt = 0; + else + fdc.sector++; + if (fdc.tc) + { + fdc.inread = 0; + discint=-2; + fdc_int(); + 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; + } disc_readsector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); fdc.inread = 1; return; @@ -967,10 +957,9 @@ void fdc_callback() fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0); else fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdc.head?4:0); + fdc.int_pending = 1; discint=-3; - timer_process(); - disctime = 2048 * (1 << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc.timer, 2048 * TIMER_USEC); // printf("Recalibrate complete!\n"); fdc.stat = 0x80 | (1 << fdc.drive); return; @@ -987,11 +976,10 @@ void fdc_callback() if (fdc_reset_stat) fdc_reset_stat--; if (!fdc_reset_stat) - fdc.st0 = 0x80; + fdc.int_pending = 0; paramstogo = 2; discint = 0; - disctime = 0; return; case 0x0d: /*Format track*/ @@ -1000,26 +988,20 @@ void fdc_callback() { // ioc_fiq(IOC_FIQ_DISC_DATA); fdc.format_state = 2; - timer_process(); - disctime = 128 * (1 << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc.timer, 8 * TIMER_USEC); } 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(); + timer_set_delay_u64(&fdc.timer, 8 * TIMER_USEC); 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(); + timer_set_delay_u64(&fdc.timer, 8 * TIMER_USEC); } else if (fdc.format_state == 3) { @@ -1053,26 +1035,26 @@ void fdc_callback() fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0); else fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdc.head?4:0); + fdc.int_pending = 1; discint=-3; - timer_process(); - disctime = 2048 * (1 << TIMER_SHIFT); - timer_update_outstanding(); + timer_set_delay_u64(&fdc.timer, 1024 * TIMER_USEC); 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); + fdc.res[1] = fdc.track[0]; + fdc.res[2] = fdc.track[1]; + fdc.res[3] = 0; + fdc.res[4] = 0; + fdc.res[5] = fdc.specify[0]; + fdc.res[6] = fdc.specify[1]; + fdc.res[7] = fdc.eot[fdc.drive]; + fdc.res[8] = (fdc.perp & 0x7f) | ((fdc.lock) ? 0x80 : 0); + fdc.res[9] = fdc.config; + fdc.res[10] = fdc.pretrk; paramstogo=10; discint=0; - disctime = 0; return; case 0x10: /*Version*/ @@ -1080,13 +1062,11 @@ void fdc_callback() 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*/ @@ -1096,7 +1076,6 @@ void fdc_callback() 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*/ @@ -1105,7 +1084,6 @@ void fdc_callback() fdc.res[10] = 0; paramstogo=1; discint=0; - disctime = 0; return; case 0x94: /*Lock*/ fdc.lock = 1; @@ -1113,7 +1091,6 @@ void fdc_callback() fdc.res[10] = 0x10; paramstogo=1; discint=0; - disctime = 0; return; case 0x18: /*NSC*/ @@ -1121,7 +1098,6 @@ void fdc_callback() fdc.res[10] = 0x73; paramstogo=1; discint=0; - disctime = 0; return; case 0xfc: /*Invalid*/ @@ -1133,7 +1109,6 @@ void fdc_callback() fdc.res[10] = fdc.st0; paramstogo=1; discint=0; - disctime = 0; return; } // printf("Bad FDC disc int %i\n",discint); @@ -1144,7 +1119,7 @@ void fdc_callback() void fdc_overrun() { disc_sector_stop(); - disctime = 0; + timer_disable(&fdc.timer); fdc_int(); fdc.stat=0xD0; @@ -1218,19 +1193,37 @@ int fdc_data(uint8_t data) void fdc_finishread() { fdc.inread = 0; - disctime = 200 * TIMER_USEC; + timer_set_delay_u64(&fdc.timer, 200 * TIMER_USEC); // rpclog("fdc_finishread\n"); } -void fdc_notfound() +void fdc_notfound(int reason) { - disctime = 0; +// pclog("fdc_notfound: reason=%i\n", reason); + timer_disable(&fdc.timer); fdc_int(); fdc.stat=0xD0; fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; - fdc.res[5]=5; - fdc.res[6]=0; + switch (reason) + { + case FDC_STATUS_AM_NOT_FOUND: + fdc.res[5] = ST1_ND | ST1_MA; + fdc.res[6] = 0; + break; + case FDC_STATUS_NOT_FOUND: + fdc.res[5] = ST1_ND; + fdc.res[6] = 0; + break; + case FDC_STATUS_WRONG_CYLINDER: + fdc.res[5] = ST1_ND; + fdc.res[6] = ST2_WC; + break; + case FDC_STATUS_BAD_CYLINDER: + fdc.res[5] = ST1_ND; + fdc.res[6] = ST2_WC | ST2_BC; + break; + } fdc.res[7] = fdc.rw_track; fdc.res[8] = fdc.head; fdc.res[9] = fdc.sector; @@ -1241,7 +1234,7 @@ void fdc_notfound() void fdc_datacrcerror() { - disctime = 0; + timer_disable(&fdc.timer); fdc_int(); fdc.stat=0xD0; @@ -1258,7 +1251,7 @@ void fdc_datacrcerror() void fdc_headercrcerror() { - disctime = 0; + timer_disable(&fdc.timer); fdc_int(); fdc.stat=0xD0; @@ -1275,7 +1268,7 @@ void fdc_headercrcerror() void fdc_writeprotect() { - disctime = 0; + timer_disable(&fdc.timer); fdc_int(); fdc.stat=0xD0; @@ -1364,7 +1357,7 @@ void fdc_indexpulse() void fdc_init() { - timer_add(fdc_callback, &disctime, &disctime, NULL); + timer_add(&fdc.timer, fdc_callback, NULL, 0); fdc.dskchg_activelow = 0; fdc.enable_3f1 = 1; @@ -1388,7 +1381,7 @@ void fdc_add() 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); + timer_add(&fdc.watchdog_timer, fdc_watchdog_poll, &fdc, 0); fdc.pcjr = 1; fdc.ps1 = 0; } @@ -1405,6 +1398,11 @@ void fdc_discchange_clear(int drive) disc_changed[drive] = 0; } +int fdc_discchange_read() +{ + return (disc_changed[fdc.drive] || drive_empty[fdc.drive]) ? 1 : 0; +} + void fdc_set_dskchg_activelow() { fdc.dskchg_activelow = 1; diff --git a/src/fdc.h b/src/fdc.h index 618cf19..f0aecce 100644 --- a/src/fdc.h +++ b/src/fdc.h @@ -7,10 +7,12 @@ void fdc_reset(); void fdc_poll(); void fdc_abort(); void fdc_discchange_clear(int drive); +int fdc_discchange_read(); void fdc_set_dskchg_activelow(); void fdc_3f1_enable(int enable); void fdc_set_ps1(); int fdc_get_bitcell_period(); +uint8_t fdc_read(uint16_t addr, void *priv); /* A few functions to communicate between Super I/O chips and the FDC. */ void fdc_update_is_nsc(int is_nsc); @@ -22,3 +24,13 @@ 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); + + + +enum +{ + FDC_STATUS_AM_NOT_FOUND, + FDC_STATUS_NOT_FOUND, + FDC_STATUS_WRONG_CYLINDER, + FDC_STATUS_BAD_CYLINDER +}; diff --git a/src/fdc37c93x.c b/src/fdc37c93x.c new file mode 100644 index 0000000..890d95d --- /dev/null +++ b/src/fdc37c93x.c @@ -0,0 +1,253 @@ +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" +#include "fdc37c93x.h" + +typedef struct fdc37c93x_t +{ + int index; + + uint8_t global_regs[0x30]; + uint8_t fdc_regs[0x100]; + uint8_t ide1_regs[0x100]; + uint8_t ide2_regs[0x100]; + uint8_t lpt_regs[0x100]; + uint8_t com1_regs[0x100]; + uint8_t com2_regs[0x100]; + uint8_t rtc_regs[0x100]; + uint8_t kbd_regs[0x100]; + uint8_t auxio_regs[0x100]; + uint8_t accessbus_regs[0x100]; + + uint8_t lock[2]; +} fdc37c93x_t; + +static fdc37c93x_t fdc37c93x_global; + +static void write_lock(fdc37c93x_t *fdc37c93x, uint8_t val) +{ + if (val == 0x55 && fdc37c93x->lock[1] == 0x55) + fdc_3f1_enable(0); + if (fdc37c93x->lock[0] == 0x55 && fdc37c93x->lock[1] == 0x55 && val != 0x55) + fdc_3f1_enable(1); + + fdc37c93x->lock[0] = fdc37c93x->lock[1]; + fdc37c93x->lock[1] = val; +} + +void fdc37c93x_write(uint16_t port, uint8_t val, void *p) +{ + fdc37c93x_t *fdc37c93x = (fdc37c93x_t *)p; + +// pclog("Write SuperIO %04x %02x\n", port, val); + if (fdc37c93x->lock[0] == 0x55 && fdc37c93x->lock[1] == 0x55) + { + if (port == 0x3f0) + { + if (val == 0xaa) + write_lock(fdc37c93x, val); + else + fdc37c93x->index = val; + } + else + { + uint16_t addr; + int irq; + +// pclog("fdc37c93x_write: index=%02x dev=%i val=%02x\n", fdc37c93x->index, fdc37c93x->global_regs[7], val); + if (fdc37c93x->index < 0x30) + { + if (fdc37c93x->index != 0x20 && fdc37c93x->index != 0x21) + fdc37c93x->global_regs[fdc37c93x->index] = val; + } + else switch (fdc37c93x->global_regs[7]) + { + case 0: + fdc37c93x->fdc_regs[fdc37c93x->index] = val; + break; + case 1: + fdc37c93x->ide1_regs[fdc37c93x->index] = val; + break; + case 2: + fdc37c93x->ide2_regs[fdc37c93x->index] = val; + break; + case 3: + fdc37c93x->lpt_regs[fdc37c93x->index] = val; + break; + case 4: + fdc37c93x->com1_regs[fdc37c93x->index] = val; + break; + case 5: + fdc37c93x->com2_regs[fdc37c93x->index] = val; + break; + case 6: + fdc37c93x->rtc_regs[fdc37c93x->index] = val; + break; + case 7: + fdc37c93x->kbd_regs[fdc37c93x->index] = val; + break; + case 8: + fdc37c93x->auxio_regs[fdc37c93x->index] = val; + break; + case 9: + fdc37c93x->accessbus_regs[fdc37c93x->index] = val; + break; + } + + fdc_remove(); + if ((fdc37c93x->global_regs[0x22] & 0x01) && (fdc37c93x->fdc_regs[0x30] & 0x01)) + { +// pclog("FDC enabled\n"); + fdc_add(); + } +/* else + pclog("FDC disabled\n");*/ + + lpt1_remove(); + lpt2_remove(); + addr = (fdc37c93x->lpt_regs[0x61] & 0xfc) | ((fdc37c93x->lpt_regs[0x60] & 3) << 8); + if ((fdc37c93x->global_regs[0x22] & (1 << 3)) && (fdc37c93x->lpt_regs[0x30] & 0x01)) + { +// pclog("LPT addr = %04x\n", addr); + lpt1_init(addr); + } +/* else + pclog("LPT disabled\n");*/ + + serial1_remove(); + addr = (fdc37c93x->com1_regs[0x61] & 0xf8) | ((fdc37c93x->com1_regs[0x60] & 3) << 8); + irq = fdc37c93x->com1_regs[0x70] & 0xf; + if ((fdc37c93x->global_regs[0x22] & (1 << 4)) && (fdc37c93x->com1_regs[0x30] & 0x01)) + { +// pclog("COM1 addr = %04x, IRQ = %i\n", addr, irq); + serial1_set(addr, irq); + } +/* else + pclog("COM1 disabled\n");*/ + + serial2_remove(); + addr = (fdc37c93x->com2_regs[0x61] & 0xf8) | ((fdc37c93x->com2_regs[0x60] & 3) << 8); + irq = fdc37c93x->com2_regs[0x70] & 0xf; + if ((fdc37c93x->global_regs[0x22] & (1 << 5)) && (fdc37c93x->com2_regs[0x30] & 0x01)) + { +// pclog("COM2 addr = %04x, IRQ = %i\n", addr, irq); + serial2_set(addr, irq); + } +/* else + pclog("COM2 disabled\n");*/ + + + fdc_update_enh_mode(fdc37c93x->fdc_regs[0xf0] & 1); + + fdc_update_densel_force((fdc37c93x->fdc_regs[0xf1] & 0x0c) >> 2); + fdd_swap = (fdc37c93x->fdc_regs[0xf0] & (1 << 4)) ? 1 : 0; + } + } + else + { + if (port == 0x3f0) + write_lock(fdc37c93x, val); + } +} + +uint8_t fdc37c93x_read(uint16_t port, void *p) +{ + fdc37c93x_t *fdc37c93x = (fdc37c93x_t *)p; + +// pclog("Read SuperIO %04x %02x\n", port, fdc37c665_curreg); + if (fdc37c93x->lock[0] == 0x55 && fdc37c93x->lock[1] == 0x55) + { + if (port == 0x3f1) + { + if (fdc37c93x->index < 0x30) + return fdc37c93x->global_regs[fdc37c93x->index]; + else switch (fdc37c93x->global_regs[7]) + { + case 0: + return fdc37c93x->fdc_regs[fdc37c93x->index]; + case 1: + return fdc37c93x->ide1_regs[fdc37c93x->index]; + case 2: + return fdc37c93x->ide2_regs[fdc37c93x->index]; + case 3: + return fdc37c93x->lpt_regs[fdc37c93x->index]; + case 4: + return fdc37c93x->com1_regs[fdc37c93x->index]; + case 5: + return fdc37c93x->com2_regs[fdc37c93x->index]; + case 6: + return fdc37c93x->rtc_regs[fdc37c93x->index]; + case 7: + return fdc37c93x->kbd_regs[fdc37c93x->index]; + case 8: + return fdc37c93x->auxio_regs[fdc37c93x->index]; + case 9: + return fdc37c93x->accessbus_regs[fdc37c93x->index]; + } + } + } + return 0xff; +} + +void fdc37c932fr_init() +{ + fdc37c93x_t *fdc37c93x = &fdc37c93x_global; + int c; + + io_sethandler(0x03f0, 0x0002, fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, fdc37c93x); + + fdc_update_is_nsc(0); + + memset(&fdc37c93x_global, 0, sizeof(fdc37c93x_global)); + + fdc37c93x->global_regs[0x03] = 0x03; + fdc37c93x->global_regs[0x20] = 0x03; + fdc37c93x->global_regs[0x21] = 0x01; + fdc37c93x->global_regs[0x24] = 0x04; + fdc37c93x->global_regs[0x26] = 0xf0; + fdc37c93x->global_regs[0x27] = 0x03; + + fdc37c93x->fdc_regs[0x60] = 0x03; + fdc37c93x->fdc_regs[0x61] = 0xf0; + fdc37c93x->fdc_regs[0x70] = 0x06; + fdc37c93x->fdc_regs[0x74] = 0x02; + fdc37c93x->fdc_regs[0xf0] = 0x0e; + fdc37c93x->fdc_regs[0xf2] = 0xff; + + fdc37c93x->ide1_regs[0x60] = 0x01; + fdc37c93x->ide1_regs[0x61] = 0xf0; + fdc37c93x->ide1_regs[0x62] = 0x03; + fdc37c93x->ide1_regs[0x63] = 0xf6; + fdc37c93x->ide1_regs[0x70] = 0x0e; + fdc37c93x->ide1_regs[0xf0] = 0x0c; + fdc37c93x->ide1_regs[0xf1] = 0x0d; + + fdc37c93x->lpt_regs[0x74] = 0x04; + fdc37c93x->lpt_regs[0xf0] = 0x3c; + + fdc37c93x->com2_regs[0x74] = 0x04; + fdc37c93x->com2_regs[0xf1] = 0x02; + fdc37c93x->com2_regs[0xf2] = 0x03; + + fdc37c93x->rtc_regs[0x63] = 0x70; + fdc37c93x->rtc_regs[0xf4] = 0x03; + + fdc37c93x->auxio_regs[0xb1] = 0x80; + fdc37c93x->auxio_regs[0xc0] = 0x01; + fdc37c93x->auxio_regs[0xc1] = 0x01; + fdc37c93x->auxio_regs[0xc5] = 0x01; + fdc37c93x->auxio_regs[0xc6] = 0x01; + fdc37c93x->auxio_regs[0xc7] = 0x01; + fdc37c93x->auxio_regs[0xc8] = 0x01; + fdc37c93x->auxio_regs[0xc9] = 0x80; + for (c = 0xcb; c < 0xee; c++) + fdc37c93x->auxio_regs[c] = 0x01; + + fdc_update_densel_polarity(1); + fdc_update_densel_force(0); + fdd_swap = 0; +} diff --git a/src/fdc37c93x.h b/src/fdc37c93x.h new file mode 100644 index 0000000..e661c3d --- /dev/null +++ b/src/fdc37c93x.h @@ -0,0 +1 @@ +extern void fdc37c932fr_init(); diff --git a/src/fdd.c b/src/fdd.c index 7092f70..9c2c3fa 100644 --- a/src/fdd.c +++ b/src/fdd.c @@ -76,9 +76,12 @@ static struct int fdd_swap = 0; -void fdd_seek(int drive, int track_diff) +uint64_t fdd_seek(int drive, int track_diff) { drive ^= fdd_swap; + + if (drive >= 2) + return 1000 * TIMER_USEC; fdd[drive].track += track_diff; @@ -93,7 +96,7 @@ void fdd_seek(int drive, int track_diff) fdc_discchange_clear(drive); disc_seek(drive, fdd[drive].track); - disctime = 5000; + return 1000 * TIMER_USEC; } void fdd_disc_changed(int drive) @@ -101,13 +104,17 @@ void fdd_disc_changed(int drive) drive ^= fdd_swap; /*Force reload of current track data*/ - disc_seek(drive, fdd[drive].track); + if (drive < 2) + disc_seek(drive, fdd[drive].track); } int fdd_track0(int drive) { drive ^= fdd_swap; + if (drive >= 2) + return 0; + /* If drive is disabled, TRK0 never gets set. */ if (!drive_types[fdd[drive].type].max_track) return 0; @@ -122,9 +129,14 @@ void fdd_set_densel(int densel) int fdd_getrpm(int drive) { - int hole = disc_hole(drive); + int hole; drive ^= fdd_swap; + + if (drive >= 2) + return 0; + + hole = disc_hole(drive); if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) return 300; if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) return 360; @@ -162,9 +174,14 @@ void fdd_setswap(int swap) int fdd_can_read_medium(int drive) { - int hole = disc_hole(drive); + int hole; drive ^= fdd_swap; + + if (drive >= 2) + return 0; + + hole = disc_hole(drive); hole = 1 << (hole + 3); @@ -174,25 +191,34 @@ int fdd_can_read_medium(int drive) int fdd_doublestep_40(int drive) { + if (drive >= 2) + return 0; return drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP; } void fdd_set_type(int drive, int type) { - fdd[drive].type = type; + if (drive < 2) + fdd[drive].type = type; } int fdd_get_type(int drive) { + if (drive >= 2) + return 0; return fdd[drive].type; } int fdd_is_525(int drive) { + if (drive >= 2) + return 0; return drive_types[fdd[drive].type].flags & FLAG_525; } int fdd_is_ed(int drive) { + if (drive >= 2) + return 0; return drive_types[fdd[drive].type].flags & FLAG_HOLE2; } diff --git a/src/fdd.h b/src/fdd.h index 5581b73..76071a1 100644 --- a/src/fdd.h +++ b/src/fdd.h @@ -1,5 +1,5 @@ #define SEEK_RECALIBRATE -999 -void fdd_seek(int drive, int track_diff); +uint64_t fdd_seek(int drive, int track_diff); int fdd_track0(int drive); int fdd_getrpm(int drive); void fdd_set_densel(int densel); diff --git a/src/fdi2raw.c b/src/fdi2raw.c index 8dfd819..8573f7e 100644 --- a/src/fdi2raw.c +++ b/src/fdi2raw.c @@ -1628,7 +1628,7 @@ static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *mi randval = rand(); if (randval < (RAND_MAX / 2)) { if (randval > (RAND_MAX / 4)) { - if (randval <= (3 * RAND_MAX / 8)) + if (randval <= (3 * (int64_t)RAND_MAX / 8)) randval = (2 * randval) - (RAND_MAX /4); else randval = (4 * randval) - RAND_MAX; @@ -1637,7 +1637,7 @@ static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *mi } else { randval -= RAND_MAX / 2; if (randval > (RAND_MAX / 4)) { - if (randval <= (3 * RAND_MAX / 8)) + if (randval <= (3 * (int64_t)RAND_MAX / 8)) randval = (2 * randval) - (RAND_MAX /4); else randval = (4 * randval) - RAND_MAX; @@ -1663,7 +1663,7 @@ static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *mi randval = rand(); if (randval < (RAND_MAX / 2)) { if (randval > (RAND_MAX / 4)) { - if (randval <= (3 * RAND_MAX / 8)) + if (randval <= (3 * (int64_t)RAND_MAX / 8)) randval = (2 * randval) - (RAND_MAX /4); else randval = (4 * randval) - RAND_MAX; @@ -1672,7 +1672,7 @@ static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *mi } else { randval -= RAND_MAX / 2; if (randval > (RAND_MAX / 4)) { - if (randval <= (3 * RAND_MAX / 8)) + if (randval <= (3 * (int64_t)RAND_MAX / 8)) randval = (2 * randval) - (RAND_MAX /4); else randval = (4 * randval) - RAND_MAX; diff --git a/src/filters.h b/src/filters.h index 454a12a..6c84c04 100644 --- a/src/filters.h +++ b/src/filters.h @@ -132,11 +132,11 @@ static inline float high_cut_iir(int i, float NewSample) { #undef NCoef -#define NCoef 1 +#define NCoef 2 //fc=3.2kHz static inline float sb_iir(int i, float NewSample) { -/* float ACoef[NCoef+1] = { + float ACoef[NCoef+1] = { 0.03356837051492005100, 0.06713674102984010200, 0.03356837051492005100 @@ -146,9 +146,9 @@ static inline float sb_iir(int i, float NewSample) { 1.00000000000000000000, -1.41898265221812010000, 0.55326988968868285000 - };*/ + }; - float ACoef[NCoef+1] = { +/* float ACoef[NCoef+1] = { 0.17529642630084405000, 0.17529642630084405000 }; @@ -156,7 +156,7 @@ static inline float sb_iir(int i, float NewSample) { 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; @@ -279,3 +279,99 @@ static inline float adgold_pseudo_stereo_iir(float NewSample) { return y[0]; } + +//fc=3.2kHz - probably incorrect +static inline float dss_iir(float NewSample) { + float ACoef[NCoef+1] = { + 0.03356837051492005100, + 0.06713674102984010200, + 0.03356837051492005100 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.41898265221812010000, + 0.55326988968868285000 + }; + + 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]; +} + +#undef NCoef +#define NCoef 1 +/*Basic high pass to remove DC bias. fc=10Hz*/ +static inline float dac_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.99901119820285345000, + -0.99901119820285345000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -0.99869185905052738000 + }; + + 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]; +} + + +#define SB16_NCoef 51 + +extern float low_fir_sb16_coef[SB16_NCoef]; + +static inline float low_fir_sb16(int i, float NewSample) +{ + static float x[2][SB16_NCoef+1]; //input samples + static int pos = 0; + float out = 0.0; + int n; + + //Calculate the new output + x[i][pos] = NewSample; + + for (n = 0; n < ((SB16_NCoef+1)-pos) && n < SB16_NCoef; n++) + out += low_fir_sb16_coef[n] * x[i][n+pos]; + for (; n < SB16_NCoef; n++) + out += low_fir_sb16_coef[n] * x[i][(n+pos) - (SB16_NCoef+1)]; + + if (i == 1) + { + pos++; + if (pos > SB16_NCoef) + pos = 0; + } + + return out; +} diff --git a/src/gameport.c b/src/gameport.c index 5d16123..9b797b4 100644 --- a/src/gameport.c +++ b/src/gameport.c @@ -4,6 +4,7 @@ #include "io.h" #include "plat-joystick.h" #include "timer.h" +#include "x86.h" #include "gameport.h" #include "joystick_ch_flightstick_pro.h" @@ -69,7 +70,7 @@ char *joystick_get_pov_name(int joystick, int id) typedef struct gameport_axis_t { - int count; + pc_timer_t timer; int axis_nr; struct gameport_t *gameport; } gameport_axis_t; @@ -86,29 +87,32 @@ typedef struct gameport_t static gameport_t *gameport_global = NULL; -static int gameport_time(int axis) +static void gameport_time(gameport_t *gameport, int nr, 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*/ + { + timer_disable(&gameport->axis[nr].timer); + } + else + { + axis += 32768; + axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 11) / 1000; + timer_set_delay_u64(&gameport->axis[nr].timer, 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_time(gameport, 0, gameport->joystick->read_axis(gameport->joystick_dat, 0)); + gameport_time(gameport, 1, gameport->joystick->read_axis(gameport->joystick_dat, 1)); + gameport_time(gameport, 2, gameport->joystick->read_axis(gameport->joystick_dat, 2)); + gameport_time(gameport, 3, gameport->joystick->read_axis(gameport->joystick_dat, 3)); gameport->joystick->write(gameport->joystick_dat); @@ -120,7 +124,6 @@ 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 @@ -139,7 +142,6 @@ void gameport_timer_over(void *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); @@ -161,10 +163,10 @@ void *gameport_init_common() 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]); + timer_add(&gameport->axis[0].timer, gameport_timer_over, &gameport->axis[0], 0); + timer_add(&gameport->axis[1].timer, gameport_timer_over, &gameport->axis[1], 0); + timer_add(&gameport->axis[2].timer, gameport_timer_over, &gameport->axis[2], 0); + timer_add(&gameport->axis[3].timer, gameport_timer_over, &gameport->axis[3], 0); gameport->joystick = joystick_list[joystick_type]; gameport->joystick_dat = gameport->joystick->init(); diff --git a/src/hdd.c b/src/hdd.c index 41e5a1d..00b246d 100644 --- a/src/hdd.c +++ b/src/hdd.c @@ -2,9 +2,14 @@ #include "device.h" #include "hdd.h" +#include "esdi_at.h" #include "hdd_esdi.h" +#include "ide.h" #include "mfm_at.h" #include "mfm_xebec.h" +#include "scsi_53c400.h" +#include "scsi_aha1540.h" +#include "scsi_ibm.h" #include "xtide.h" char hdd_controller_name[16]; @@ -19,16 +24,27 @@ static struct char internal_name[16]; device_t *device; int is_mfm; + int is_ide; + int is_scsi; } hdd_controllers[] = { - {"None", "none", &null_hdd_device, 0}, - {"AT Fixed Disk Adapter", "mfm_at", &mfm_at_device, 1}, - {"DTC 5150X", "dtc5150x", &dtc_5150x_device, 1}, - {"Fixed Disk Adapter (Xebec)", "mfm_xebec", &mfm_xebec_device, 1}, - {"IBM ESDI Fixed Disk Adapter (MCA)", "esdi_mca", &hdd_esdi_device, 1}, - {"XTIDE", "xtide", &xtide_device, 0}, - {"XTIDE (AT)", "xtide_at", &xtide_at_device, 0}, - {"", "", NULL, 0} + {"None", "none", &null_hdd_device, 0, 0, 0}, + {"[MFM] AT Fixed Disk Adapter", "mfm_at", &mfm_at_device, 1, 0, 0}, + {"[MFM] DTC 5150X", "dtc5150x", &dtc_5150x_device, 1, 0, 0}, + {"[MFM] Fixed Disk Adapter (Xebec)", "mfm_xebec", &mfm_xebec_device, 1, 0, 0}, + {"[ESDI] IBM ESDI Fixed Disk Controller", "esdi_mca", &hdd_esdi_device, 1, 0, 0}, + {"[ESDI] Western Digital WD1007V-SE1", "wd1007vse1", &wd1007vse1_device, 0, 0, 0}, + {"[IDE] Standard IDE", "ide", &ide_device, 0, 1, 0}, + {"[IDE] XTIDE", "xtide", &xtide_device, 0, 1, 0}, + {"[IDE] XTIDE (AT)", "xtide_at", &xtide_at_device, 0, 1, 0}, + {"[IDE] XTIDE (PS/1)", "xtide_ps1", &xtide_ps1_device, 0, 1, 0}, + {"[SCSI] Adaptec AHA-1542C", "aha1542c", &scsi_aha1542c_device, 0, 0, 1}, + {"[SCSI] BusLogic BT-545S", "bt545s", &scsi_bt545s_device, 0, 0, 1}, + {"[SCSI] IBM SCSI Adapter with Cache", "ibmscsi_mca",&scsi_ibm_device, 0, 0, 1}, + {"[SCSI] Longshine LCS-6821N", "lcs6821n", &scsi_lcs6821n_device, 0, 0, 1}, + {"[SCSI] Rancho RT1000B", "rt1000b", &scsi_rt1000b_device, 0, 0, 1}, + {"[SCSI] Trantor T130B", "t130b", &scsi_t130b_device, 0, 0, 1}, + {"", "", NULL, 0, 0} }; char *hdd_controller_get_name(int hdd) @@ -51,16 +67,16 @@ int hdd_controller_available(int hdd) return device_available(hdd_controllers[hdd].device); } -int hdd_controller_current_is_mfm() +int hdd_controller_is_mfm(char *internal_name) { int c = 0; while (hdd_controllers[c].device) { - if (!strcmp(hdd_controller_name, hdd_controllers[c].internal_name)) + if (!strcmp(internal_name, hdd_controllers[c].internal_name)) { hdd_controller_current = c; - if (strcmp(hdd_controller_name, "none")) + if (strcmp(internal_name, "none")) return hdd_controllers[c].is_mfm; } c++; @@ -68,6 +84,88 @@ int hdd_controller_current_is_mfm() return 0; } +int hdd_controller_is_ide(char *internal_name) +{ + int c = 0; + + while (hdd_controllers[c].device) + { + if (!strcmp(internal_name, hdd_controllers[c].internal_name)) + { + hdd_controller_current = c; + if (strcmp(internal_name, "none")) + return hdd_controllers[c].is_ide; + } + c++; + } + + return 0; +} +int hdd_controller_is_scsi(char *internal_name) +{ + int c = 0; + + while (hdd_controllers[c].device) + { + if (!strcmp(internal_name, hdd_controllers[c].internal_name)) + { + hdd_controller_current = c; + if (strcmp(internal_name, "none")) + return hdd_controllers[c].is_scsi; + } + c++; + } + + return 0; +} +int hdd_controller_has_config(char *internal_name) +{ + int c = 0; + + while (hdd_controllers[c].device) + { + if (!strcmp(internal_name, hdd_controllers[c].internal_name)) + { + hdd_controller_current = c; + if (strcmp(internal_name, "none")) + return hdd_controllers[c].device->config ? 1 : 0; + } + c++; + } + + return 0; +} + +device_t *hdd_controller_get_device(char *internal_name) +{ + int c = 0; + + while (hdd_controllers[c].device) + { + if (!strcmp(internal_name, hdd_controllers[c].internal_name)) + { + hdd_controller_current = c; + if (strcmp(internal_name, "none")) + return hdd_controllers[c].device; + } + c++; + } + + return NULL; +} + +int hdd_controller_current_is_mfm() +{ + return hdd_controller_is_mfm(hdd_controller_name); +} +int hdd_controller_current_is_ide() +{ + return hdd_controller_is_ide(hdd_controller_name); +} +int hdd_controller_current_is_scsi() +{ + return hdd_controller_is_scsi(hdd_controller_name); +} void hdd_controller_init(char *internal_name) { diff --git a/src/hdd.h b/src/hdd.h index c0443e0..47a02c0 100644 --- a/src/hdd.h +++ b/src/hdd.h @@ -1,8 +1,17 @@ +#include "device.h" + char *hdd_controller_get_name(int hdd); char *hdd_controller_get_internal_name(int hdd); int hdd_controller_get_flags(int hdd); int hdd_controller_available(int hdd); +int hdd_controller_is_mfm(char* internal_name); +int hdd_controller_is_ide(char *internal_name); +int hdd_controller_is_scsi(char *internal_name); +int hdd_controller_has_config(char *internal_name); +device_t *hdd_controller_get_device(char *internal_name); int hdd_controller_current_is_mfm(); +int hdd_controller_current_is_ide(); +int hdd_controller_current_is_scsi(); void hdd_controller_init(char *internal_name); extern char hdd_controller_name[16]; diff --git a/src/hdd_esdi.c b/src/hdd_esdi.c index db708ec..04c4317 100644 --- a/src/hdd_esdi.c +++ b/src/hdd_esdi.c @@ -12,6 +12,7 @@ #include "device.h" #include "dma.h" +#include "hdd_file.h" #include "io.h" #include "mca.h" #include "mem.h" @@ -21,19 +22,11 @@ #include "hdd_esdi.h" -#define ESDI_TIME (2000 * TIMER_USEC) +#define ESDI_TIME (500 * TIMER_USEC) #define CMD_ADAPTER 0 -extern char ide_fn[4][512]; - -typedef struct esdi_drive_t -{ - int spt, hpc; - int tracks; - int sectors; - FILE *hdfile; -} esdi_drive_t; +extern char ide_fn[7][512]; typedef struct esdi_t { @@ -56,7 +49,7 @@ typedef struct esdi_t int data_pos; uint16_t data[256]; - uint16_t sector_buffer[16][256]; + uint16_t sector_buffer[256][256]; int sector_pos; int sector_count; @@ -65,7 +58,7 @@ typedef struct esdi_t int cmd_state; int in_reset; - int callback; + pc_timer_t callback_timer; uint32_t rba; @@ -74,7 +67,7 @@ typedef struct esdi_t int req_in_progress; } cmds[3]; - esdi_drive_t drives[2]; + hdd_file_t hdd_file[2]; uint8_t pos_regs[8]; } esdi_t; @@ -117,10 +110,12 @@ typedef struct esdi_t #define CMD_READ_VERIFY 0x03 #define CMD_WRITE_VERIFY 0x04 #define CMD_SEEK 0x05 +#define CMD_GET_DEV_STATUS 0x08 #define CMD_GET_DEV_CONFIG 0x09 #define CMD_GET_POS_INFO 0x0a #define STATUS_LEN(x) ((x) << 8) +#define STATUS_DEVICE(x) ((x) << 5) #define STATUS_DEVICE_HOST_ADAPTER (7 << 5) static inline void esdi_set_irq(esdi_t *esdi) @@ -168,7 +163,7 @@ static void esdi_write(uint16_t port, uint8_t val, void *p) { // pclog("ESDI reset\n"); esdi->in_reset = 1; - esdi->callback = ESDI_TIME * 50; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME * 50); esdi->status = STATUS_BUSY; } esdi->basic_ctrl = val; @@ -188,6 +183,7 @@ static void esdi_write(uint16_t port, uint8_t val, void *p) esdi->cmd_dev = ATTN_HOST_ADAPTER; esdi->status |= STATUS_BUSY; esdi->cmd_pos = 0; + esdi->status_pos = 0; break; case ATTN_EOI: @@ -199,7 +195,7 @@ static void esdi_write(uint16_t port, uint8_t val, void *p) case ATTN_RESET: // pclog("ESDI reset\n"); esdi->in_reset = 1; - esdi->callback = ESDI_TIME * 50; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME * 50); esdi->status = STATUS_BUSY; break; @@ -218,6 +214,7 @@ static void esdi_write(uint16_t port, uint8_t val, void *p) esdi->cmd_dev = ATTN_DEVICE_0; esdi->status |= STATUS_BUSY; esdi->cmd_pos = 0; + esdi->status_pos = 0; break; case ATTN_EOI: @@ -241,6 +238,7 @@ static void esdi_write(uint16_t port, uint8_t val, void *p) esdi->cmd_dev = ATTN_DEVICE_1; esdi->status |= STATUS_BUSY; esdi->cmd_pos = 0; + esdi->status_pos = 0; break; case ATTN_EOI: @@ -274,7 +272,7 @@ static uint16_t esdi_readw(uint16_t port, void *p) case 0x3510: /*Status Interface Register*/ if (esdi->status_pos >= esdi->status_len) return 0; - temp = esdi->status_data[esdi->status_pos++]; + temp = esdi->status_data[esdi->status_pos++]; if (esdi->status_pos >= esdi->status_len) { esdi->status &= ~STATUS_STATUS_OUT_FULL; @@ -313,7 +311,7 @@ static void esdi_writew(uint16_t port, uint16_t val, void *p) if ((esdi->cmd_data[0] & CMD_DEVICE_SEL) != esdi->cmd_dev) fatal("Command device mismatch with attn\n"); esdi->command = esdi->cmd_data[0] & CMD_MASK; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); esdi->status = STATUS_BUSY; esdi->data_pos = 0; } @@ -362,6 +360,40 @@ static void device_not_present(esdi_t *esdi) esdi_set_irq(esdi); } +static void rba_out_of_range(esdi_t *esdi) +{ + esdi->status_len = 9; + esdi->status_data[0] = esdi->command | STATUS_LEN(9) | esdi->cmd_dev; + esdi->status_data[1] = 0x0e01; /*Command block error, invalid parameter*/ + esdi->status_data[2] = 0x0007; /*RBA out of range*/ + esdi->status_data[3] = 0; + esdi->status_data[4] = 0; + esdi->status_data[5] = 0; + esdi->status_data[6] = 0; + esdi->status_data[7] = 0; + esdi->status_data[8] = 0; + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_FAILURE; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); +} + +static void complete_command_status(esdi_t *esdi) +{ + esdi->status_len = 7; + if (esdi->cmd_dev == ATTN_DEVICE_0) + esdi->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(0); + else + esdi->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(1); + esdi->status_data[1] = 0x0000; /*Error bits*/ + esdi->status_data[2] = 0x1900; /*Device status*/ + esdi->status_data[3] = 0; /*Number of blocks left to do*/ + esdi->status_data[4] = (esdi->rba-1) & 0xffff; /*Last RBA processed*/ + esdi->status_data[5] = (esdi->rba-1) >> 8; + esdi->status_data[6] = 0; /*Number of blocks requiring error recovery*/ +} + #define ESDI_ADAPTER_ONLY() do \ { \ if (esdi->cmd_dev != ATTN_HOST_ADAPTER) \ @@ -379,17 +411,15 @@ static void device_not_present(esdi_t *esdi) return; \ } \ if (esdi->cmd_dev == ATTN_DEVICE_0) \ - drive = &esdi->drives[0]; \ + hdd_file = &esdi->hdd_file[0]; \ else \ - drive = &esdi->drives[1]; \ + hdd_file = &esdi->hdd_file[1]; \ } while (0) static void esdi_callback(void *p) { esdi_t *esdi = (esdi_t *)p; - esdi_drive_t *drive; - - esdi->callback = 0; + hdd_file_t *hdd_file; // pclog("esdi_callback: in_reset=%i command=%x\n", esdi->in_reset, esdi->command); if (esdi->in_reset) @@ -406,7 +436,7 @@ static void esdi_callback(void *p) case CMD_READ: ESDI_DRIVE_ONLY(); - if (!drive->hdfile) + if (!hdd_file->f) { device_not_present(esdi); return; @@ -419,6 +449,12 @@ static void esdi_callback(void *p) esdi->sector_pos = 0; esdi->sector_count = esdi->cmd_data[1]; + + if ((esdi->rba + esdi->sector_count) >= hdd_file->sectors) + { + rba_out_of_range(esdi); + return; + } esdi->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; esdi->irq_status = esdi->cmd_dev | IRQ_DATA_TRANSFER_READY; @@ -426,7 +462,7 @@ static void esdi_callback(void *p) esdi_set_irq(esdi); esdi->cmd_state = 1; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); esdi->data_pos = 0; break; @@ -434,18 +470,17 @@ static void esdi_callback(void *p) if (!(esdi->basic_ctrl & CTRL_DMA_ENA)) { // pclog("DMA not enabled\n"); - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); return; } while (esdi->sector_pos < esdi->sector_count) { if (!esdi->data_pos) { - if (esdi->rba >= drive->sectors) + if (esdi->rba >= hdd_file->sectors) fatal("Read past end of drive\n"); - fseek(drive->hdfile, esdi->rba * 512, SEEK_SET); - fread(esdi->data, 512, 1, drive->hdfile); - readflash = 1; + hdd_read_sectors(hdd_file, esdi->rba, 1, esdi->data); + readflash_set(READFLASH_HDC, esdi->cmd_dev == ATTN_DEVICE_0 ? 0 : 1); } // pclog("Read sector %i %i %08x\n", esdi->sector_pos, esdi->data_pos, esdi->rba*512); while (esdi->data_pos < 256) @@ -455,7 +490,7 @@ static void esdi_callback(void *p) if (val == DMA_NODATA) { // pclog("DMA out of data\n"); - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); return; } @@ -469,12 +504,14 @@ static void esdi_callback(void *p) esdi->status = STATUS_CMD_IN_PROGRESS; esdi->cmd_state = 2; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); break; case 2: // pclog("Read sector complete\n"); - esdi->status = STATUS_IRQ; + complete_command_status(esdi); + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; esdi->irq_in_progress = 1; esdi_set_irq(esdi); @@ -486,7 +523,7 @@ static void esdi_callback(void *p) case CMD_WRITE_VERIFY: ESDI_DRIVE_ONLY(); - if (!drive->hdfile) + if (!hdd_file->f) { device_not_present(esdi); return; @@ -500,13 +537,19 @@ static void esdi_callback(void *p) esdi->sector_pos = 0; esdi->sector_count = esdi->cmd_data[1]; + if ((esdi->rba + esdi->sector_count) >= hdd_file->sectors) + { + rba_out_of_range(esdi); + return; + } + esdi->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; esdi->irq_status = esdi->cmd_dev | IRQ_DATA_TRANSFER_READY; esdi->irq_in_progress = 1; esdi_set_irq(esdi); esdi->cmd_state = 1; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); esdi->data_pos = 0; break; @@ -514,7 +557,7 @@ static void esdi_callback(void *p) if (!(esdi->basic_ctrl & CTRL_DMA_ENA)) { // pclog("DMA not enabled\n"); - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); return; } while (esdi->sector_pos < esdi->sector_count) @@ -527,32 +570,33 @@ static void esdi_callback(void *p) if (val == DMA_NODATA) { // pclog("DMA out of data\n"); - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); return; } esdi->data[esdi->data_pos++] = val & 0xffff; } - if (esdi->rba >= drive->sectors) + if (esdi->rba >= hdd_file->sectors) fatal("Write past end of drive\n"); - fseek(drive->hdfile, esdi->rba * 512, SEEK_SET); - fwrite(esdi->data, 512, 1, drive->hdfile); + hdd_write_sectors(hdd_file, esdi->rba, 1, esdi->data); esdi->rba++; esdi->sector_pos++; - readflash = 1; + readflash_set(READFLASH_HDC, esdi->cmd_dev == ATTN_DEVICE_0 ? 0 : 1); esdi->data_pos = 0; } esdi->status = STATUS_CMD_IN_PROGRESS; esdi->cmd_state = 2; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); break; case 2: // pclog("Write sector complete\n"); - esdi->status = STATUS_IRQ; + complete_command_status(esdi); + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; esdi->irq_in_progress = 1; esdi_set_irq(esdi); @@ -563,13 +607,20 @@ static void esdi_callback(void *p) case CMD_READ_VERIFY: ESDI_DRIVE_ONLY(); - if (!drive->hdfile) + if (!hdd_file->f) { device_not_present(esdi); return; } - esdi->status = STATUS_IRQ; + if ((esdi->rba + esdi->sector_count) >= hdd_file->sectors) + { + rba_out_of_range(esdi); + return; + } + esdi->rba += esdi->sector_count; + complete_command_status(esdi); + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; esdi->irq_in_progress = 1; esdi_set_irq(esdi); @@ -578,13 +629,43 @@ static void esdi_callback(void *p) case CMD_SEEK: ESDI_DRIVE_ONLY(); - if (!drive->hdfile) + if (!hdd_file->f) { device_not_present(esdi); return; } - esdi->status = STATUS_IRQ; + complete_command_status(esdi); + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + esdi->irq_in_progress = 1; + esdi_set_irq(esdi); + break; + + case CMD_GET_DEV_STATUS: + ESDI_DRIVE_ONLY(); + + if (!hdd_file->f) + { + device_not_present(esdi); + return; + } + + if ((esdi->status & STATUS_IRQ) || esdi->irq_in_progress) + fatal("IRQ in progress %02x %i\n", esdi->status, esdi->irq_in_progress); + + esdi->status_len = 9; + esdi->status_data[0] = CMD_GET_DEV_STATUS | STATUS_LEN(9) | STATUS_DEVICE_HOST_ADAPTER; + esdi->status_data[1] = 0x0000; /*Error bits*/ + esdi->status_data[2] = 0x1900; /*Device status*/ + esdi->status_data[3] = 0; /*ESDI Standard Status*/ + esdi->status_data[4] = 0; /*ESDI Vendor Unique Status*/ + esdi->status_data[5] = 0; + esdi->status_data[6] = 0; + esdi->status_data[7] = 0; + esdi->status_data[8] = 0; + + esdi->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; esdi->irq_status = esdi->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; esdi->irq_in_progress = 1; esdi_set_irq(esdi); @@ -593,24 +674,22 @@ static void esdi_callback(void *p) case CMD_GET_DEV_CONFIG: ESDI_DRIVE_ONLY(); - if (!drive->hdfile) + if (!hdd_file->f) { device_not_present(esdi); return; } - if (esdi->status_pos) - fatal("Status send in progress\n"); if ((esdi->status & STATUS_IRQ) || esdi->irq_in_progress) fatal("IRQ in progress %02x %i\n", esdi->status, esdi->irq_in_progress); esdi->status_len = 6; - esdi->status_data[0] = CMD_GET_POS_INFO | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER; + esdi->status_data[0] = CMD_GET_DEV_CONFIG | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER; esdi->status_data[1] = 0x10; /*Zero defect*/ - esdi->status_data[2] = drive->sectors & 0xffff; - esdi->status_data[3] = drive->sectors >> 16; - esdi->status_data[4] = drive->tracks; - esdi->status_data[5] = drive->hpc | (drive->spt << 16); + esdi->status_data[2] = hdd_file->sectors & 0xffff; + esdi->status_data[3] = hdd_file->sectors >> 16; + esdi->status_data[4] = hdd_file->tracks; + esdi->status_data[5] = hdd_file->hpc | (hdd_file->spt << 16); /* pclog("CMD_GET_DEV_CONFIG %i %04x %04x %04x %04x %04x %04x\n", drive->sectors, esdi->status_data[0], esdi->status_data[1], @@ -625,8 +704,7 @@ static void esdi_callback(void *p) case CMD_GET_POS_INFO: ESDI_ADAPTER_ONLY(); - if (esdi->status_pos) - fatal("Status send in progress\n"); + if ((esdi->status & STATUS_IRQ) || esdi->irq_in_progress) fatal("IRQ in progress %02x %i\n", esdi->status, esdi->irq_in_progress); @@ -650,7 +728,7 @@ static void esdi_callback(void *p) case 0: esdi->sector_pos = 0; esdi->sector_count = esdi->cmd_data[1]; - if (esdi->sector_count > 16) + if (esdi->sector_count > 256) fatal("Read sector buffer count %04x\n", esdi->cmd_data[1]); esdi->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; @@ -659,7 +737,7 @@ static void esdi_callback(void *p) esdi_set_irq(esdi); esdi->cmd_state = 1; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); esdi->data_pos = 0; break; @@ -667,7 +745,7 @@ static void esdi_callback(void *p) if (!(esdi->basic_ctrl & CTRL_DMA_ENA)) { // pclog("DMA not enabled\n"); - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); return; } while (esdi->sector_pos < esdi->sector_count) @@ -682,7 +760,7 @@ static void esdi_callback(void *p) if (val == DMA_NODATA) { // pclog("DMA out of data\n"); - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); return; } @@ -694,7 +772,7 @@ static void esdi_callback(void *p) esdi->status = STATUS_CMD_IN_PROGRESS; esdi->cmd_state = 2; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); break; case 2: @@ -714,7 +792,7 @@ static void esdi_callback(void *p) case 0: esdi->sector_pos = 0; esdi->sector_count = esdi->cmd_data[1]; - if (esdi->sector_count > 16) + if (esdi->sector_count > 256) fatal("Write sector buffer count %04x\n", esdi->cmd_data[1]); esdi->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; @@ -723,7 +801,7 @@ static void esdi_callback(void *p) esdi_set_irq(esdi); esdi->cmd_state = 1; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); esdi->data_pos = 0; break; @@ -731,7 +809,7 @@ static void esdi_callback(void *p) if (!(esdi->basic_ctrl & CTRL_DMA_ENA)) { // pclog("DMA not enabled\n"); - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); return; } while (esdi->sector_pos < esdi->sector_count) @@ -744,7 +822,7 @@ static void esdi_callback(void *p) if (val == DMA_NODATA) { // pclog("DMA out of data\n"); - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); return; } @@ -757,7 +835,7 @@ static void esdi_callback(void *p) esdi->status = STATUS_CMD_IN_PROGRESS; esdi->cmd_state = 2; - esdi->callback = ESDI_TIME; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME); break; case 2: @@ -772,8 +850,7 @@ static void esdi_callback(void *p) case 0x12: ESDI_ADAPTER_ONLY(); - if (esdi->status_pos) - fatal("Status send in progress\n"); + if ((esdi->status & STATUS_IRQ) || esdi->irq_in_progress) fatal("IRQ in progress %02x %i\n", esdi->status, esdi->irq_in_progress); @@ -827,65 +904,26 @@ static void esdi_mca_write(int port, uint8_t val, void *p) } } -static void loadhd(esdi_t *esdi, int d, const char *fn) -{ - esdi_drive_t *drive = &esdi->drives[d]; - - if (drive->hdfile == NULL) - { - /* Try to open existing hard disk image */ - drive->hdfile = fopen64(fn, "rb+"); - if (drive->hdfile == NULL) - { - /* Failed to open existing hard disk image */ - if (errno == ENOENT) - { - /* Failed because it does not exist, - so try to create new file */ - drive->hdfile = fopen64(fn, "wb+"); - if (drive->hdfile == NULL) - { - pclog("Cannot create file '%s': %s", - fn, strerror(errno)); - return; - } - } - else - { - /* Failed for another reason */ - pclog("Cannot open file '%s': %s", - fn, strerror(errno)); - return; - } - } - } - - drive->spt = hdc[d].spt; - drive->hpc = hdc[d].hpc; - drive->tracks = hdc[d].tracks; - drive->sectors = hdc[d].spt * hdc[d].hpc * hdc[d].tracks; -} - static void *esdi_init() { esdi_t *esdi = malloc(sizeof(esdi_t)); memset(esdi, 0, sizeof(esdi_t)); - rom_init_interleaved(&esdi->bios_rom, "roms/90x8970.bin", "roms/90x8969.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + rom_init_interleaved(&esdi->bios_rom, "90x8970.bin", "90x8969.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); mem_mapping_disable(&esdi->bios_rom.mapping); - loadhd(esdi, 0, ide_fn[0]); - loadhd(esdi, 1, ide_fn[1]); + hdd_load(&esdi->hdd_file[0], 0, ide_fn[0]); + hdd_load(&esdi->hdd_file[1], 1, ide_fn[1]); - timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi); + timer_add(&esdi->callback_timer, esdi_callback, esdi, 0); - mca_add(esdi_mca_read, esdi_mca_write, esdi); + mca_add(esdi_mca_read, esdi_mca_write, NULL, esdi); esdi->pos_regs[0] = 0xff; esdi->pos_regs[1] = 0xdd; esdi->in_reset = 1; - esdi->callback = ESDI_TIME * 50; + timer_set_delay_u64(&esdi->callback_timer, ESDI_TIME * 50); esdi->status = STATUS_BUSY; return esdi; @@ -894,22 +932,16 @@ static void *esdi_init() static void esdi_close(void *p) { esdi_t *esdi = (esdi_t *)p; - int d; - - for (d = 0; d < 2; d++) - { - esdi_drive_t *drive = &esdi->drives[d]; - - if (drive->hdfile != NULL) - fclose(drive->hdfile); - } + hdd_close(&esdi->hdd_file[0]); + hdd_close(&esdi->hdd_file[1]); + free(esdi); } static int esdi_available() { - return rom_present("roms/90x8969.bin") && rom_present("roms/90x8970.bin"); + return rom_present("90x8969.bin") && rom_present("90x8970.bin"); } device_t hdd_esdi_device = diff --git a/src/hdd_file.c b/src/hdd_file.c new file mode 100644 index 0000000..f5c4ffd --- /dev/null +++ b/src/hdd_file.c @@ -0,0 +1,202 @@ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include + +#include "ibm.h" +#include "hdd_file.h" +#include "minivhd/minivhd.h" +#include "minivhd/minivhd_util.h" + +void hdd_load_ext(hdd_file_t *hdd, const char *fn, int spt, int hpc, int tracks, int read_only) +{ + if (hdd->f == NULL) + { + /* Try to open existing hard disk image */ + if (read_only) + hdd->f = (void*)fopen64(fn, "rb"); + else + hdd->f = (void*)fopen64(fn, "rb+"); + if (hdd->f != NULL) + { + hdd->img_type = HDD_IMG_RAW; + /* Check if the file we opened is a VHD */ + if (mvhd_file_is_vhd((FILE*)hdd->f)) + { + int err; + fclose((FILE*)hdd->f); + MVHDMeta *vhdm = mvhd_open(fn, (bool)read_only, &err); + if (vhdm == NULL) + { + hdd->f = NULL; + if (err == MVHD_ERR_FILE) + { + pclog("Cannot open VHD file '%s' : %s", + fn, strerror(mvhd_errno)); + } + else + { + pclog("Cannot open VHD file '%s' : %s", + fn, mvhd_strerr(err)); + } + return; + } + else if (err == MVHD_ERR_TIMESTAMP) + { + pclog("VHD: Parent/child timestamp mismatch"); + mvhd_close(vhdm); + hdd->f = NULL; + return; + } + hdd->f = (void*)vhdm; + hdd->img_type = HDD_IMG_VHD; + } + } + else + { + /* Failed to open existing hard disk image */ + if (errno == ENOENT && !read_only) + { + /* Failed because it does not exist, + so try to create new file */ + hdd->f = (void*)fopen64(fn, "wb+"); + if (hdd->f == NULL) + { + pclog("Cannot create file '%s': %s", + fn, strerror(errno)); + return; + } + } + else + { + /* Failed for another reason */ + pclog("Cannot open file '%s': %s", + fn, strerror(errno)); + return; + } + hdd->img_type = HDD_IMG_RAW; + } + } + if (hdd->img_type == HDD_IMG_VHD) + { + MVHDMeta *vhdm = (MVHDMeta*)hdd->f; + MVHDGeom geom = mvhd_get_geometry(vhdm); + hdd->spt = geom.spt; + hdd->hpc = geom.heads; + hdd->tracks = geom.cyl; + } + else if (hdd->img_type == HDD_IMG_RAW) + { + hdd->spt = spt; + hdd->hpc = hpc; + hdd->tracks = tracks; + } + hdd->sectors = hdd->spt * hdd->hpc * hdd->tracks; + hdd->read_only = read_only; +} + +void hdd_load(hdd_file_t *hdd, int d, const char *fn) +{ + hdd_load_ext(hdd, fn, hdc[d].spt, hdc[d].hpc, hdc[d].tracks, 0); +} + +void hdd_close(hdd_file_t *hdd) +{ + if (hdd->f) + { + if (hdd->img_type == HDD_IMG_VHD) + mvhd_close((MVHDMeta*)hdd->f); + else if (hdd->img_type == HDD_IMG_RAW) + fclose((FILE*)hdd->f); + } + hdd->img_type = HDD_IMG_RAW; + hdd->f = NULL; +} + +int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer) +{ + if (hdd->img_type == HDD_IMG_VHD) + { + return mvhd_read_sectors((MVHDMeta*)hdd->f, offset, nr_sectors, buffer); + } + else if (hdd->img_type == HDD_IMG_RAW) + { + off64_t addr; + int transfer_sectors = nr_sectors; + + if ((hdd->sectors - offset) < transfer_sectors) + transfer_sectors = hdd->sectors - offset; + addr = (uint64_t)offset * 512; + + fseeko64((FILE*)hdd->f, addr, SEEK_SET); + fread(buffer, transfer_sectors*512, 1, (FILE*)hdd->f); + + if (nr_sectors != transfer_sectors) + return 1; + return 0; + } + /* Keep the compiler happy */ + return 1; +} + +int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer) +{ + if (hdd->img_type == HDD_IMG_VHD) + { + return mvhd_write_sectors((MVHDMeta*)hdd->f, offset, nr_sectors, buffer); + } + else if (hdd->img_type == HDD_IMG_RAW) + { + off64_t addr; + int transfer_sectors = nr_sectors; + + if (hdd->read_only) + return 1; + + if ((hdd->sectors - offset) < transfer_sectors) + transfer_sectors = hdd->sectors - offset; + addr = (uint64_t)offset * 512; + + fseeko64((FILE*)hdd->f, addr, SEEK_SET); + fwrite(buffer, transfer_sectors*512, 1, (FILE*)hdd->f); + + if (nr_sectors != transfer_sectors) + return 1; + return 0; + } + /* Keep the compiler happy */ + return 1; +} + +int hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors) +{ + if (hdd->img_type == HDD_IMG_VHD) + { + return mvhd_format_sectors((MVHDMeta*)hdd->f, offset, nr_sectors); + } + else if (hdd->img_type == HDD_IMG_RAW) + { + off64_t addr; + int c; + uint8_t zero_buffer[512]; + int transfer_sectors = nr_sectors; + + if (hdd->read_only) + return 1; + + memset(zero_buffer, 0, 512); + + if ((hdd->sectors - offset) < transfer_sectors) + transfer_sectors = hdd->sectors - offset; + addr = (uint64_t)offset * 512; + fseeko64((FILE*)hdd->f, addr, SEEK_SET); + for (c = 0; c < transfer_sectors; c++) + fwrite(zero_buffer, 512, 1, (FILE*)hdd->f); + + if (nr_sectors != transfer_sectors) + return 1; + return 0; + } + /* Keep the compiler happy */ + return 1; +} diff --git a/src/hdd_file.h b/src/hdd_file.h new file mode 100644 index 0000000..485e09f --- /dev/null +++ b/src/hdd_file.h @@ -0,0 +1,23 @@ +typedef enum hdd_img_type +{ + HDD_IMG_RAW, + HDD_IMG_VHD, +} hdd_img_type; + +typedef struct hdd_file_t +{ + void *f; + int spt; + int hpc; + int tracks; + int sectors; + int read_only; + hdd_img_type img_type; +} hdd_file_t; + +void hdd_load(hdd_file_t *hdd, int d, const char *fn); +void hdd_load_ext(hdd_file_t *hdd, const char *fn, int spt, int hpc, int tracks, int read_only); +void hdd_close(hdd_file_t *hdd); +int hdd_read_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer); +int hdd_write_sectors(hdd_file_t *hdd, int offset, int nr_sectors, void *buffer); +int hdd_format_sectors(hdd_file_t *hdd, int offset, int nr_sectors); diff --git a/src/headland.c b/src/headland.c index b4f460f..0208c5d 100644 --- a/src/headland.c +++ b/src/headland.c @@ -2,45 +2,533 @@ #include "io.h" #include "mem.h" #include "cpu.h" +#include "x86.h" #include "headland.h" static int headland_index; static uint8_t headland_regs[256]; +static uint8_t headland_port_92 = 0xFC, headland_ems_mar = 0, headland_cri = 0; +static uint8_t headland_regs_cr[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static uint16_t headland_ems_mr[64]; + +static mem_mapping_t headland_low_mapping; +static mem_mapping_t headland_ems_mapping[64]; +static mem_mapping_t headland_mid_mapping; +static mem_mapping_t headland_high_mapping; +static mem_mapping_t headland_4000_9FFF_mapping[24]; + +// TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet, so memory configuration is hardcoded now. +static int headland_mem_conf_cr0[41] = { 0x00, 0x00, 0x20, 0x40, 0x60, 0xA0, 0x40, 0xE0, + 0xA0, 0xC0, 0xE0, 0xE0, 0xC0, 0xE0, 0xE0, 0xE0, + 0xE0, 0x20, 0x40, 0x40, 0xA0, 0xC0, 0xE0, 0xE0, + 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0x20, 0x40, 0x60, 0x60, 0xC0, 0xE0, 0xE0, 0xE0, + 0xE0 }; +static int headland_mem_conf_cr1[41] = { 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, + 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x40 }; + +uint32_t get_headland_addr(uint32_t addr, uint16_t *mr) +{ + if (mr && (headland_regs_cr[0] & 2) && (*mr & 0x200)) + { + addr = (addr & 0x3fff) | ((*mr & 0x1F) << 14); + + if(headland_regs_cr[1] & 0x40) + { + if((headland_regs_cr[4] & 0x80) && (headland_regs_cr[6] & 1)) + { + if(headland_regs_cr[0] & 0x80) + { + addr |= (*mr & 0x60) << 14; + if(*mr & 0x100) + addr += ((*mr & 0xC00) << 13) + (((*mr & 0x80) + 0x80) << 15); + else + addr += (*mr & 0x80) << 14; + } + else if(*mr & 0x100) + addr += ((*mr & 0xC00) << 13) + (((*mr & 0x80) + 0x20) << 15); + else + addr += (*mr & 0x80) << 12; + } + else if(headland_regs_cr[0] & 0x80) + addr |= (*mr & 0x100) ? ((*mr & 0x80) + 0x400) << 12 : (*mr & 0xE0) << 14; + else + addr |= (*mr & 0x100) ? ((*mr & 0xE0) + 0x40) << 14 : (*mr & 0x80) << 12; + } + else + { + if((headland_regs_cr[4] & 0x80) && (headland_regs_cr[6] & 1)) + { + if(headland_regs_cr[0] & 0x80) + { + addr |= ((*mr & 0x60) << 14); + if(*mr & 0x180) + addr += ((*mr & 0xC00) << 13) + (((*mr & 0x180) - 0x60) << 16); + } + else + addr |= ((*mr & 0x60) << 14) | ((*mr & 0x180) << 16) | ((*mr & 0xC00) << 13); + } + else if(headland_regs_cr[0] & 0x80) + addr |= (*mr & 0x1E0) << 14; + else + addr |= (*mr & 0x180) << 12; + } + } + else if(mr == NULL && (headland_regs_cr[0] & 4) == 0 && mem_size >= 1024 && addr >= 0x100000) + addr -= 0x60000; + + return addr; +} + +void headland_set_global_EMS_state(int state) +{ + int i; + uint32_t base_addr, virt_addr; + + for(i=0; i<32; i++) + { + base_addr = (i + 16) << 14; + if(i >= 24) + base_addr += 0x20000; + if((state & 2) && (headland_ems_mr[((state & 1) << 5) | i] & 0x200)) + { + virt_addr = get_headland_addr(base_addr, &headland_ems_mr[((state & 1) << 5) | i]); + if(i < 24) mem_mapping_disable(&headland_4000_9FFF_mapping[i]); + mem_mapping_disable(&headland_ems_mapping[(((state ^ 1) & 1) << 5) | i]); + mem_mapping_enable(&headland_ems_mapping[((state & 1) << 5) | i]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], ram + virt_addr); + else mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], NULL); + } + else + { + mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], ram + base_addr); + mem_mapping_disable(&headland_ems_mapping[(((state ^ 1) & 1) << 5) | i]); + mem_mapping_disable(&headland_ems_mapping[((state & 1) << 5) | i]); + + if(i < 24) + mem_mapping_enable(&headland_4000_9FFF_mapping[i]); + } + } + flushmmucache(); +} + +void headland_memmap_state_update() +{ + int i; + uint32_t addr; + + for(i=0;i<24;i++) + { + addr = get_headland_addr(0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&headland_4000_9FFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); + //pclog("headland_memmap_state_update : Address %06X to %06X\n", 0x40000 + (i << 14), addr); + } + + mem_set_mem_state(0xA0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + if (mem_size > 640) + { + if ((headland_regs_cr[0] & 4) == 0) + { + mem_mapping_set_addr(&headland_mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + mem_mapping_set_exec(&headland_mid_mapping, ram + 0xA0000); + if (mem_size > 1024) + { + mem_mapping_set_addr(&headland_high_mapping, 0x160000, (mem_size - 1024) << 10); + mem_mapping_set_exec(&headland_high_mapping, ram + 0x100000); + } + } + else + { + mem_mapping_set_addr(&headland_mid_mapping, 0xA0000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + mem_mapping_set_exec(&headland_mid_mapping, ram + 0xA0000); + if (mem_size > 1024) + { + mem_mapping_set_addr(&headland_high_mapping, 0x100000, (mem_size - 1024) << 10); + mem_mapping_set_exec(&headland_high_mapping, ram + 0x100000); + } + } + } + + headland_set_global_EMS_state(headland_regs_cr[0] & 3); +} void headland_write(uint16_t addr, uint8_t val, void *priv) { - if (addr & 1) + uint8_t old_val, index; + uint32_t base_addr, virt_addr; + + switch(addr) { + case 0x22: + headland_index = val; + break; + + case 0x23: + old_val = headland_regs[headland_index]; + if (headland_index == 0xc1 && !is486) val = 0; headland_regs[headland_index] = val; - pclog("Headland write %02X %02X\n",headland_index,val); + //pclog("Headland write %02X %02X at %04X:%04X\n",headland_index,val,CS,cpu_state.oldpc); if (headland_index == 0x82) { - shadowbios = val & 0x10; - shadowbios_write = !(val & 0x10); - if (shadowbios) + if (val & 0x10) 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 if (headland_index == 0x87) + { + if ((val & 1) && !(old_val & 1)) + softresetx86(); + } + break; + + case 0x92: + if ((mem_a20_alt ^ val) & 2) + { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~headland_port_92 & val) & 1) + { + softresetx86(); + cpu_set_edx(); + } + headland_port_92 = val | 0xFC; + break; + + case 0x1EC: + //pclog("Set EMS Map Register to %02X(actually FF%02X) at %04X:%04X\n", val, val, CS, cpu_state.oldpc); + headland_ems_mr[headland_ems_mar & 0x3F] = val | 0xFF00; + index = headland_ems_mar & 0x1F; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x20000; + if((headland_regs_cr[0] & 2) && ((headland_regs_cr[0] & 1) == ((headland_ems_mar & 0x20) >> 5))) + { + virt_addr = get_headland_addr(base_addr, &headland_ems_mr[headland_ems_mar & 0x3F]); + if(index < 24) mem_mapping_disable(&headland_4000_9FFF_mapping[index]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + virt_addr); + else mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], NULL); + mem_mapping_enable(&headland_ems_mapping[headland_ems_mar & 0x3F]); + pclog("Map page %d(address %05X) to address %06X\n", index, base_addr, virt_addr); + flushmmucache(); + } + if(headland_ems_mar & 0x80) headland_ems_mar++; + break; + + case 0x1ED: + //pclog("Set Control Register Index to %02X at %04X:%04X\n", val, CS, cpu_state.oldpc); + headland_cri = val; + break; + + case 0x1EE: + //pclog("Set EMS Map Address Register to %02X at %04X:%04X\n", val, CS, cpu_state.oldpc); + headland_ems_mar = val; + break; + + case 0x1EF: + //pclog("Set Control Register %1X to %02X at %04X:%04X\n", headland_cri, val, CS, cpu_state.oldpc); + old_val = headland_regs_cr[headland_cri]; + switch(headland_cri) + { + case 0: + headland_regs_cr[0] = (val & 0x1F) | headland_mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + mem_set_mem_state(0xE0000, 0x10000, (val & 8 ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED); + mem_set_mem_state(0xF0000, 0x10000, (val & 0x10 ? MEM_READ_INTERNAL: MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED); + headland_memmap_state_update(); + break; + case 1: + headland_regs_cr[1] = (val & 0xBF) | headland_mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + headland_memmap_state_update(); + break; + case 2: + case 3: + case 5: + headland_regs_cr[headland_cri] = val; + headland_memmap_state_update(); + break; + case 4: + headland_regs_cr[4] = (headland_regs_cr[4] & 0xF0) | (val & 0x0F); + if(val & 1) + { + mem_mapping_disable(&bios_mapping[0]); + mem_mapping_disable(&bios_mapping[1]); + mem_mapping_disable(&bios_mapping[2]); + mem_mapping_disable(&bios_mapping[3]); + } + else + { + mem_mapping_enable(&bios_mapping[0]); + mem_mapping_enable(&bios_mapping[1]); + mem_mapping_enable(&bios_mapping[2]); + mem_mapping_enable(&bios_mapping[3]); + } + break; + case 6: + if(headland_regs_cr[4] & 0x80) + { + headland_regs_cr[headland_cri] = (val & 0xFE) | (mem_size > 8192 ? 1 : 0); + headland_memmap_state_update(); + } + break; + default: + break; + } + break; + + default: + break; + } +} + +void headland_writew(uint16_t addr, uint16_t val, void *priv) +{ + uint8_t index; + uint32_t base_addr, virt_addr; + + switch(addr) + { + case 0x1EC: + //pclog("Set EMS Map Register to %04X at %04X:%04X\n", val, CS, cpu_state.oldpc); + headland_ems_mr[headland_ems_mar & 0x3F] = val; + index = headland_ems_mar & 0x1F; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x20000; + if((headland_regs_cr[0] & 2) && (headland_regs_cr[0] & 1) == ((headland_ems_mar & 0x20) >> 5)) + { + if(val & 0x200) + { + virt_addr = get_headland_addr(base_addr, &headland_ems_mr[headland_ems_mar & 0x3F]); + if(index < 24) mem_mapping_disable(&headland_4000_9FFF_mapping[index]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + virt_addr); + else mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], NULL); + mem_mapping_enable(&headland_ems_mapping[headland_ems_mar & 0x3F]); + //pclog("Map page %d(address %05X) to address %07X(val=%04X)\n", index, base_addr, virt_addr, val); + } + else + { + mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + base_addr); + mem_mapping_disable(&headland_ems_mapping[headland_ems_mar & 0x3F]); + if(index < 24) mem_mapping_enable(&headland_4000_9FFF_mapping[index]); + //pclog("Unmap page %d(address %05X)\n", index, base_addr); + } + flushmmucache(); + } + if(headland_ems_mar & 0x80) headland_ems_mar++; + break; + + default: + break; } - else - headland_index = val; } uint8_t headland_read(uint16_t addr, void *priv) { - if (addr & 1) + uint8_t val; + + switch(addr) { + case 0x22: + val = headland_index; + break; + + case 0x23: if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix) - return 0xff; /*Don't conflict with Cyrix config registers*/ - return headland_regs[headland_index]; + val = 0xff; /*Don't conflict with Cyrix config registers*/ + else + val = headland_regs[headland_index]; + break; + + case 0x92: + val = headland_port_92 | 0xFC; + break; + + case 0x1EC: + val = headland_ems_mr[headland_ems_mar & 0x3F]; + if(headland_ems_mar & 0x80) headland_ems_mar++; + break; + + case 0x1ED: + val = headland_cri; + break; + + case 0x1EE: + val = headland_ems_mar; + break; + + case 0x1EF: + switch(headland_cri) + { + case 0: + val = (headland_regs_cr[0] & 0x1F) | headland_mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + break; + case 1: + val = (headland_regs_cr[1] & 0xBF) | headland_mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + break; + case 6: + if(headland_regs_cr[4] & 0x80) + val = (headland_regs_cr[6] & 0xFE) | (mem_size > 8192 ? 1 : 0); + else + val = 0; + break; + default: + val = headland_regs_cr[headland_cri]; + break; + } + break; + + default: + val = 0xFF; + break; } - return headland_index; + + return val; +} + +uint16_t headland_readw(uint16_t addr, void *priv) +{ + uint16_t val; + + switch(addr) + { + case 0x1EC: + val = headland_ems_mr[headland_ems_mar & 0x3F] | ((headland_regs_cr[4] & 0x80) ? 0xF000 : 0xFC00); + if(headland_ems_mar & 0x80) headland_ems_mar++; + break; + + default: + val = 0xFFFF; + break; + } + + return val; +} + +uint8_t mem_read_headlandb(uint32_t addr, void *priv) +{ + uint8_t val = 0xff; + + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + val = ram[addr]; + + return val; +} + +void mem_write_headlandb(uint32_t addr, uint8_t val, void *priv) +{ + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + ram[addr] = val; +} + +uint16_t mem_read_headlandw(uint32_t addr, void *priv) +{ + uint16_t val = 0xffff; + + if((addr & 0x3FFF) == 0x3FFF) pclog("mem_read_headlandw(%08X, %p) called.\n", addr, priv); + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + val = *(uint16_t *)&ram[addr]; + + return val; +} + +void mem_write_headlandw(uint32_t addr, uint16_t val, void *priv) +{ + if((addr & 0x3FFF) == 0x3FFF) pclog("mem_write_headlandw(%08X, %04X, %p) called.\n", addr, val, priv); + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + +uint32_t mem_read_headlandl(uint32_t addr, void *priv) +{ + uint32_t val = 0xffffffff; + + if((addr & 0x3FFF) > 0x3FFC) pclog("mem_read_headlandl(%08X, %p) called.\n", addr, priv); + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + val = *(uint32_t *)&ram[addr]; + + return val; +} + +void mem_write_headlandl(uint32_t addr, uint32_t val, void *priv) +{ + if((addr & 0x3FFF) > 0x3FFC) pclog("mem_write_headland(%08X, %08X, %p) called.\n", addr, val, priv); + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + *(uint32_t *)&ram[addr] = val; } void headland_init() { - io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); + int i; + + for(i=0; i<8; i++) + headland_regs_cr[i] = 0; + headland_regs_cr[0] = 4; + + switch(romset) + { + case ROM_AMI386SX: + // Remark - Previously distributed AMI386 BIOS doesn't seem to be for the Headland chipset. + io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); + break; + case ROM_AMA932J: + headland_regs_cr[4] = 0x20; + io_sethandler(0x0092, 0x0001, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); + break; + default: + headland_regs_cr[4] = 0; + break; + } + + io_sethandler(0x01EC, 0x0001, headland_read, headland_readw, NULL, headland_write, headland_writew, NULL, NULL); + io_sethandler(0x01ED, 0x0003, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); + + for(i=0; i<64; i++) + headland_ems_mr[i] = 0; + + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + + mem_mapping_add(&headland_low_mapping, 0, 0x40000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram, MEM_MAPPING_INTERNAL, NULL); + + if(mem_size > 640) + { + mem_mapping_add(&headland_mid_mapping, 0xA0000, 0x60000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&headland_mid_mapping); + } + + if(mem_size > 1024) + { + mem_mapping_add(&headland_high_mapping, 0x100000, ((mem_size - 1024) * 1024), mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&headland_high_mapping); + } + + for (i = 0; i < 24; i++) + { + mem_mapping_add(&headland_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&headland_4000_9FFF_mapping[i]); + } + + for (i = 0; i < 64; i++) + { + headland_ems_mr[i] = 0; + mem_mapping_add(&headland_ems_mapping[i], ((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14, 0x04000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + (((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14), 0, &headland_ems_mr[i]); + mem_mapping_disable(&headland_ems_mapping[i]); + } + + headland_memmap_state_update(); } diff --git a/src/i430fx.c b/src/i430fx.c index 5b7cf7f..678c824 100644 --- a/src/i430fx.c +++ b/src/i430fx.c @@ -34,20 +34,37 @@ static void i430fx_map(uint32_t addr, uint32_t size, int state) void i430fx_write(int func, int addr, uint8_t val, void *priv) { if (func) - return; + return; + + if (addr >= 0x10 && addr < 0x4f) + return; switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + 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; @@ -89,6 +106,30 @@ void i430fx_write(int func, int addr, uint8_t val, void *priv) i430fx_map(0xec000, 0x04000, val >> 4); pclog("i430fx_write : PAM6 write %02X\n", val); break; + + case 0x72: /*SMRAM*/ + pclog("Write SMRAM %02x\n", val); + val = (val & 0x78) | 2; /*SMRAM always at A0000-BFFFF*/ + val |= (card_i430fx[0x72] & 0x10); /*D_LCK can not be cleared by software*/ + if (val & 0x10) /*D_LCK locks D_OPEN and G_SMRAME*/ + { + val &= ~0x48; /*D_OPEN is forced to 0, G_SMRAME is read only*/ + val |= (card_i430fx[0x72] & 0x08); + } + if ((card_i430fx[0x72] ^ val) & 0x40) + { + if (val & 0x40) /*SMRAM enabled*/ + { + pclog("Enable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + else + { + pclog("Disable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + break; } card_i430fx[addr] = val; @@ -102,21 +143,15 @@ uint8_t i430fx_read(int func, int addr, void *priv) return card_i430fx[addr]; } -static uint8_t trc = 0; - -void i430fx_trc_write(uint16_t port, uint8_t val, void *p) +static void i430fx_smram_enable(void) { - 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*/ - keyboard_at_reset(); /*Reset keyboard controller to reset system flag*/ - } - resetx86(); - } - - trc = val; + if (card_i430fx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); +} +static void i430fx_smram_disable(void) +{ + if (card_i430fx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); } void i430fx_init() @@ -125,7 +160,7 @@ void i430fx_init() 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[0x02] = 0x2d; card_i430fx[0x03] = 0x12; /*SB82437FX-66*/ card_i430fx[0x04] = 0x06; card_i430fx[0x05] = 0x00; card_i430fx[0x06] = 0x00; card_i430fx[0x07] = 0x82; card_i430fx[0x08] = 0x00; /*A0 stepping*/ @@ -142,5 +177,11 @@ void i430fx_init() // card_i430fx[0x74] = 0x0e; // card_i430fx[0x78] = 0x23; - io_sethandler(0x0cf9, 0x0001, NULL, NULL, NULL, i430fx_trc_write, NULL, NULL, NULL); + smram_enable = i430fx_smram_enable; + smram_disable = i430fx_smram_disable; +} + +void i430fx_reset() +{ + i430fx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ } diff --git a/src/i430fx.h b/src/i430fx.h index fff11d2..0265f27 100644 --- a/src/i430fx.h +++ b/src/i430fx.h @@ -1 +1,2 @@ void i430fx_init(); +void i430fx_reset(); diff --git a/src/i430hx.c b/src/i430hx.c new file mode 100644 index 0000000..466b002 --- /dev/null +++ b/src/i430hx.c @@ -0,0 +1,186 @@ +#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; + + if (addr >= 0x10 && addr < 0x4f) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val &= 0x80; + val |= 0x02; + break; + + 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; + + case 0x72: /*SMRAM*/ + pclog("Write SMRAM %02x\n", val); + val = (val & 0x78) | 2; /*SMRAM always at A0000-BFFFF*/ + val |= (card_i430hx[0x72] & 0x10); /*D_LCK can not be cleared by software*/ + if (val & 0x10) /*D_LCK locks D_OPEN and G_SMRAME*/ + { + val &= ~0x48; /*D_OPEN is forced to 0, G_SMRAME is read only*/ + val |= (card_i430hx[0x72] & 0x08); + } + if ((card_i430hx[0x72] ^ val) & 0x40) + { + if (val & 0x40) /*SMRAM enabled*/ + { + pclog("Enable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + else + { + pclog("Disable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + break; + } + + card_i430hx[addr] = val; +} + +uint8_t i430hx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430hx[addr]; +} + +static void i430hx_smram_enable(void) +{ + if (card_i430hx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); +} +static void i430hx_smram_disable(void) +{ + if (card_i430hx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + +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[0x07] = 0x02; + card_i430hx[0x08] = 0x00; /*A0 stepping*/ + card_i430hx[0x0B] = 0x06; + card_i430hx[0x51] = 0x20; + card_i430hx[0x52] = 0xB5; /*512kb cache*/ + card_i430hx[0x56] = 0x52; /*DRAM control*/ + card_i430hx[0x59] = 0x40; + card_i430hx[0x5A] = card_i430hx[0x5B] = card_i430hx[0x5C] = card_i430hx[0x5D] = 0x44; + card_i430hx[0x5E] = card_i430hx[0x5F] = 0x44; + card_i430hx[0x60] = card_i430hx[0x61] = card_i430hx[0x62] = card_i430hx[0x63] = 0x02; + card_i430hx[0x64] = card_i430hx[0x5F] = 0x02; + card_i430hx[0x65] = card_i430hx[0x66] = card_i430hx[0x67] = 0x02; + card_i430hx[0x68] = 0x11; + + smram_enable = i430hx_smram_enable; + smram_disable = i430hx_smram_disable; +} + +void i430hx_reset() +{ + i430hx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ +} diff --git a/src/i430hx.h b/src/i430hx.h new file mode 100644 index 0000000..30a6685 --- /dev/null +++ b/src/i430hx.h @@ -0,0 +1,2 @@ +void i430hx_init(); +void i430hx_reset(); diff --git a/src/i430lx.c b/src/i430lx.c index 1f6a874..4d2bb74 100644 --- a/src/i430lx.c +++ b/src/i430lx.c @@ -1,10 +1,12 @@ #include #include "ibm.h" +#include "ide.h" #include "io.h" #include "keyboard_at.h" #include "mem.h" #include "pci.h" +#include "sio.h" #include "x86.h" #include "i430lx.h" @@ -36,18 +38,35 @@ void i430lx_write(int func, int addr, uint8_t val, void *priv) if (func) return; + if (addr >= 0x10 && addr < 0x4f) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + case 0x04: /*Command register*/ + val &= 0x42; + val |= 0x04; + break; + case 0x05: + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + 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; @@ -89,6 +108,30 @@ void i430lx_write(int func, int addr, uint8_t val, void *priv) i430lx_map(0xec000, 0x04000, val >> 4); pclog("i430lx_write : PAM6 write %02X\n", val); break; + + case 0x72: /*SMRAM*/ + pclog("Write SMRAM %02x\n", val); + val = (val & 0x38) | 2; /*SMRAM always at A0000-BFFFF*/ + val |= (card_i430lx[0x72] & 0x08); /*D_LCK can not be cleared by software*/ + if (val & 0x08) /*D_LCK locks D_OPEN*/ + { + val &= ~0x20; /*D_OPEN is forced to 0*/ + } + val |= (card_i430lx[0x72] & 0x08); + if ((card_i430lx[0x72] ^ val) & 0x20) + { + if (val & 0x20) /*SMRAM enabled*/ + { + pclog("Enable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + else + { + pclog("Disable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + break; } card_i430lx[addr] = val; @@ -116,14 +159,27 @@ void i430lx_trc_write(uint16_t port, uint8_t val, void *p) 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*/ + card_i430lx[0x72] = 0; /*Also clear SMRAM register so BIOS will relocate SMBASE*/ keyboard_at_reset(); /*Reset keyboard controller to reset system flag*/ + ide_reset_devices(); + resetx86(); } - resetx86(); + else + softresetx86(); } - + trc = val; } +static void i430lx_smram_enable(void) +{ + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); +} +static void i430lx_smram_disable(void) +{ + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + void i430lx_init() { pci_add_specific(0, i430lx_read, i430lx_write, NULL); @@ -149,4 +205,7 @@ void i430lx_init() // card_i430lx[0x78] = 0x23; io_sethandler(0x0cf9, 0x0001, i430lx_trc_read, NULL, NULL, i430lx_trc_write, NULL, NULL, NULL); + + smram_enable = i430lx_smram_enable; + smram_disable = i430lx_smram_disable; } diff --git a/src/i430vx.c b/src/i430vx.c index 5f2cb05..fde2258 100644 --- a/src/i430vx.c +++ b/src/i430vx.c @@ -34,18 +34,36 @@ void i430vx_write(int func, int addr, uint8_t val, void *priv) if (func) return; + if (addr >= 0x10 && addr < 0x4f) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: - case 0x0e: + case 0x0c: case 0x0e: return; + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val &= 0x80; + val |= 0x02; + break; + 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; @@ -87,6 +105,30 @@ void i430vx_write(int func, int addr, uint8_t val, void *priv) i430vx_map(0xec000, 0x04000, val >> 4); pclog("i430vx_write : PAM6 write %02X\n", val); break; + + case 0x72: /*SMRAM*/ + pclog("Write SMRAM %02x\n", val); + val = (val & 0x78) | 2; /*SMRAM always at A0000-BFFFF*/ + val |= (card_i430vx[0x72] & 0x10); /*D_LCK can not be cleared by software*/ + if (val & 0x10) /*D_LCK locks D_OPEN and G_SMRAME*/ + { + val &= ~0x48; /*D_OPEN is forced to 0, G_SMRAME is read only*/ + val |= (card_i430vx[0x72] & 0x08); + } + if ((card_i430vx[0x72] ^ val) & 0x40) + { + if (val & 0x40) /*SMRAM enabled*/ + { + pclog("Enable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + else + { + pclog("Disable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + break; } card_i430vx[addr] = val; @@ -100,7 +142,17 @@ uint8_t i430vx_read(int func, int addr, void *priv) return card_i430vx[addr]; } - +static void i430vx_smram_enable(void) +{ + if (card_i430vx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); +} +static void i430vx_smram_disable(void) +{ + if (card_i430vx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + void i430vx_init() { pci_add_specific(0, i430vx_read, i430vx_write, NULL); @@ -123,4 +175,12 @@ void i430vx_init() card_i430vx[0x72] = 0x02; card_i430vx[0x74] = 0x0e; card_i430vx[0x78] = 0x23; + + smram_enable = i430vx_smram_enable; + smram_disable = i430vx_smram_disable; +} + +void i430vx_reset() +{ + i430vx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ } diff --git a/src/i430vx.h b/src/i430vx.h index 22bde47..25cda4a 100644 --- a/src/i430vx.h +++ b/src/i430vx.h @@ -1 +1,2 @@ void i430vx_init(); +void i430vx_reset(); diff --git a/src/i440bx.c b/src/i440bx.c new file mode 100644 index 0000000..910f71b --- /dev/null +++ b/src/i440bx.c @@ -0,0 +1,192 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "keyboard_at.h" +#include "mem.h" +#include "pci.h" +#include "x86.h" + +#include "i440bx.h" + +static uint8_t card_i440bx[256]; + +static void i440bx_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 i440bx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + if (addr >= 0x10 && addr < 0x4f) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x59: /*PAM0*/ + if ((card_i440bx[0x59] ^ val) & 0xf0) + { + i440bx_map(0xf0000, 0x10000, val >> 4); + } + pclog("i440bx_write : PAM0 write %02X\n", val); +// if (val == 0x10) +// output = 3; + break; + case 0x5a: /*PAM1*/ + if ((card_i440bx[0x5a] ^ val) & 0x0f) + i440bx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i440bx[0x5a] ^ val) & 0xf0) + i440bx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i440bx[0x5b] ^ val) & 0x0f) + i440bx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i440bx[0x5b] ^ val) & 0xf0) + i440bx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i440bx[0x5c] ^ val) & 0x0f) + i440bx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i440bx[0x5c] ^ val) & 0xf0) + i440bx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i440bx[0x5d] ^ val) & 0x0f) + i440bx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i440bx[0x5d] ^ val) & 0xf0) + i440bx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i440bx[0x5e] ^ val) & 0x0f) + i440bx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i440bx[0x5e] ^ val) & 0xf0) + i440bx_map(0xe4000, 0x04000, val >> 4); + pclog("i440bx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i440bx[0x5f] ^ val) & 0x0f) + i440bx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i440bx[0x5f] ^ val) & 0xf0) + i440bx_map(0xec000, 0x04000, val >> 4); + pclog("i440bx_write : PAM6 write %02X\n", val); + break; + + case 0x72: /*SMRAM*/ +// pclog("Write SMRAM %02x was %02x\n", val, + val = (val & 0x78) | 2; /*SMRAM always at A0000-BFFFF*/ + val |= (card_i440bx[0x72] & 0x10); /*D_LCK can not be cleared by software*/ + if (val & 0x10) /*D_LCK locks D_OPEN and G_SMRAME*/ + { + val &= ~0x48; /*D_OPEN is forced to 0, G_SMRAME is read only*/ + val |= (card_i440bx[0x72] & 0x08); + } + if ((card_i440bx[0x72] ^ val) & 0x40) + { + if (val & 0x40) /*SMRAM enabled*/ + { + pclog("Enable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + else + { + pclog("Disable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + break; + } + + card_i440bx[addr] = val; +} + +uint8_t i440bx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i440bx[addr]; +} + +static void i440bx_smram_enable(void) +{ +// pclog("i440bx_smram_enable: 440BX 0x72=%02x\n", card_i440bx[0x72]); + if (card_i440bx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); +} +static void i440bx_smram_disable(void) +{ +// pclog("i440bx_smram_disable: 440BX 0x72=%02x\n", card_i440bx[0x72]); + if (card_i440bx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + +void i440bx_init() +{ + pci_add_specific(0, i440bx_read, i440bx_write, NULL); + + memset(card_i440bx, 0, 256); + card_i440bx[0x00] = 0x86; card_i440bx[0x01] = 0x80; /*Intel*/ + card_i440bx[0x02] = 0x92; card_i440bx[0x03] = 0x71; /*82441FX*/ + card_i440bx[0x04] = 0x06; card_i440bx[0x05] = 0x00; + card_i440bx[0x06] = 0x00; card_i440bx[0x07] = 0x02; + card_i440bx[0x08] = 0x02; /*B1 stepping*/ + card_i440bx[0x09] = 0x00; card_i440bx[0x0a] = 0x00; card_i440bx[0x0b] = 0x06; + card_i440bx[0x51] = 0x20; /*66 MHz bus*/ + card_i440bx[0x60] = card_i440bx[0x61] = card_i440bx[0x62] = card_i440bx[0x63] = 0x01; + card_i440bx[0x64] = card_i440bx[0x65] = card_i440bx[0x66] = card_i440bx[0x67] = 0x01; + card_i440bx[0x72] = 0x02; + card_i440bx[0x73] = 0x38; + card_i440bx[0x7a] = 0x02; /*AGP disabled*/ + + smram_enable = i440bx_smram_enable; + smram_disable = i440bx_smram_disable; +} + +void i440bx_reset() +{ + i440bx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ + i440bx_write(0, 0x5a, 0x0, NULL); + i440bx_write(0, 0x5b, 0x0, NULL); + i440bx_write(0, 0x5c, 0x0, NULL); + i440bx_write(0, 0x5d, 0x0, NULL); + i440bx_write(0, 0x5e, 0x0, NULL); + i440bx_write(0, 0x5f, 0x0, NULL); +} diff --git a/src/i440bx.h b/src/i440bx.h new file mode 100644 index 0000000..8ed559f --- /dev/null +++ b/src/i440bx.h @@ -0,0 +1,2 @@ +void i440bx_init(); +void i440bx_reset(); diff --git a/src/i440fx.c b/src/i440fx.c new file mode 100644 index 0000000..87d1dfe --- /dev/null +++ b/src/i440fx.c @@ -0,0 +1,183 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "keyboard_at.h" +#include "mem.h" +#include "pci.h" +#include "x86.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; + + if (addr >= 0x10 && addr < 0x4f) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x02; + val |= 0x04; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x59: /*PAM0*/ + if ((card_i440fx[0x59] ^ val) & 0xf0) + { + i440fx_map(0xf0000, 0x10000, val >> 4); + } + 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; + + case 0x72: /*SMRAM*/ + pclog("Write SMRAM %02x\n", val); + val = (val & 0x78) | 2; /*SMRAM always at A0000-BFFFF*/ + val |= (card_i440fx[0x72] & 0x10); /*D_LCK can not be cleared by software*/ + if (val & 0x10) /*D_LCK locks D_OPEN and G_SMRAME*/ + { + val &= ~0x48; /*D_OPEN is forced to 0, G_SMRAME is read only*/ + val |= (card_i440fx[0x72] & 0x08); + } + if ((card_i440fx[0x72] ^ val) & 0x40) + { + if (val & 0x40) /*SMRAM enabled*/ + { + pclog("Enable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + else + { + pclog("Disable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + break; + } + + card_i440fx[addr] = val; +} + +uint8_t i440fx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i440fx[addr]; +} + +static void i440fx_smram_enable(void) +{ + if (card_i440fx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); +} +static void i440fx_smram_disable(void) +{ + if (card_i440fx[0x72] & 8) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + +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] = 0x06; card_i440fx[0x05] = 0x00; + card_i440fx[0x06] = 0x80; card_i440fx[0x07] = 0x02; + card_i440fx[0x08] = 0x00; /*A0 stepping*/ + card_i440fx[0x09] = 0x00; card_i440fx[0x0a] = 0x00; card_i440fx[0x0b] = 0x06; + card_i440fx[0x51] = 0x84; /*Uniprocessor, 66 MHz bus*/ + card_i440fx[0x53] = 0x80; + card_i440fx[0x57] = 0x01; + card_i440fx[0x58] = 0x10; + card_i440fx[0x60] = card_i440fx[0x61] = card_i440fx[0x62] = card_i440fx[0x63] = card_i440fx[0x64] = 0x01; + card_i440fx[0x71] = 0x10; + card_i440fx[0x72] = 0x02; + + smram_enable = i440fx_smram_enable; + smram_disable = i440fx_smram_disable; +} + +void i440fx_reset() +{ + i440fx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ +} diff --git a/src/i440fx.h b/src/i440fx.h new file mode 100644 index 0000000..e16eab7 --- /dev/null +++ b/src/i440fx.h @@ -0,0 +1,2 @@ +void i440fx_init(); +void i440fx_reset(); diff --git a/src/ibm.h b/src/ibm.h index c06010f..c1b6581 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -1,8 +1,33 @@ #include #include #include + +#include "timer.h" + + +#ifdef PCEM_BUILD_VERSION +#define STRINGISE2(string) #string +#define STRINGISE(string) STRINGISE2(string) +#define PCEM_VERSION_STRING "build " STRINGISE(PCEM_BUILD_VERSION) +#else +#define PCEM_VERSION_STRING "v17" +#endif + +#ifdef ABS +#undef ABS +#endif + +#define ABS(x) ((x) > 0 ? (x) : -(x)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + #define printf pclog +#define READFLASH_FDC 0 +#define READFLASH_HDC 4 +#define readflash_set(offset, drive) readflash |= 1<<((offset)+(drive)) +#define readflash_clear(offset, drive) readflash &= ~(1<<((offset)+(drive))) +#define readflash_get(offset, drive) ((readflash&(1<<((offset)+(drive)))) != 0) + /*Memory*/ uint8_t *ram; @@ -17,27 +42,14 @@ 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); +uint16_t readmemwl(uint32_t addr); +void writememwl(uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t addr); +void writememll(uint32_t addr, uint32_t val); +uint64_t readmemql(uint32_t addr); +void writememql(uint32_t addr, uint64_t val); uint8_t *getpccache(uint32_t a); @@ -56,200 +68,14 @@ 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 mem_size; extern int readlnum,writelnum; /*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 +extern int ins, output, timetolive; -typedef union -{ - uint32_t l; - uint16_t w; - struct - { - uint8_t l,h; - } b; -} x86reg; - -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; - -typedef union MMX_REG -{ - uint64_t q; - int64_t sq; - uint32_t l[2]; - int32_t sl[2]; - uint16_t w[4]; - int16_t sw[4]; - uint8_t b[8]; - int8_t sb[8]; -} MMX_REG; - -struct -{ - x86reg regs[8]; - - uint8_t tag[8]; - - x86seg *ea_seg; - uint32_t eaaddr; - - int flags_op; - uint32_t flags_res; - uint32_t flags_op1, flags_op2; - - uint32_t pc; - uint32_t oldpc; - uint32_t op32; - - int TOP; - - union - { - struct - { - int8_t rm, mod, reg; - } rm_mod_reg; - uint32_t rm_mod_reg_data; - } rm_data; - - int8_t ssegs; - int8_t ismmx; - int8_t abrt; - - int _cycles; - int cpu_recomp_ins; - - uint16_t npxs, npxc; - - double ST[8]; - - uint16_t MM_w4[8]; - - MMX_REG MM[8]; - - uint16_t old_npxc, new_npxc; -} cpu_state; - -#define cycles cpu_state._cycles - -#define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; - -COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128); - -#define cpu_state_offset(MEMBER) ((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128) - -uint16_t flags,eflags; -uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; - -extern int ins,output; -extern int cycdiff; - -x86seg gdt,ldt,idt,tr; -x86seg _cs,_ds,_es,_ss,_fs,_gs; -x86seg _oldds; - -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*/ -#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_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_nr @@ -261,7 +87,7 @@ typedef struct PIT_nr typedef struct PIT { uint32_t l[3]; - int c[3]; + pc_timer_t timer[3]; uint8_t m[3]; uint8_t ctrl,ctrls[3]; int wp,rm[3],wm[3]; @@ -279,12 +105,12 @@ typedef struct PIT int initial[3]; int latched[3]; int disabled[3]; - + uint8_t read_status[3]; int do_read_status[3]; - + PIT_nr pit_nr[3]; - + void (*set_out_funcs[3])(int new_out, int old_out); } PIT; @@ -300,27 +126,24 @@ float pit_timer0_freq(); /*DMA*/ -typedef struct DMA +typedef struct dma_t { - uint32_t ab[4],ac[4]; - uint16_t cb[4]; - int cc[4]; + uint32_t ab, ac; + uint16_t cb; + int cc; int wp; - uint8_t m,mode[4]; - uint8_t page[4]; - uint8_t stat; + uint8_t m, mode; + uint8_t page; + uint8_t stat, stat_rq; uint8_t command; - - int xfr_command, xfr_channel; - int byte_ptr; - - int is_ps2; - uint8_t arb_level[4]; - uint8_t ps2_mode[4]; -} DMA; + int size; -DMA dma,dma16; + uint8_t ps2_mode; + uint8_t arb_level; + uint16_t io_addr; +} dma_t; +dma_t dma[8]; /*PPI*/ typedef struct PPI @@ -339,28 +162,25 @@ typedef struct PIC int icw; uint8_t vector; int read; + uint8_t level_sensitive; } PIC; PIC pic,pic2; extern int pic_intpending; -int disctime; char discfns[2][256]; int driveempty[2]; -#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR || gfxcard==GFX_GENIUS) && (romset=ROM_IBMAT)) -#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && gfxcard!=GFX_COLORPLUS && gfxcard!=GFX_INCOLOR && gfxcard!=GFX_WY700 && gfxcard!=GFX_GENIUS && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) #define PCJR (romset == ROM_IBMPCJR) -#define AMIBIOS (romset==ROM_AMI386SX || romset==ROM_AMI486 || romset == ROM_WIN486) int GAMEBLASTER, GUS, SSI2001, voodoo_enabled; -extern int AMSTRAD, AT, is386, PCI, TANDY; +extern int AMSTRAD, AT, is386, PCI, TANDY, MCA; enum { - ROM_IBMPC = 0, /*301 keyboard error, 131 cassette (!!!) error*/ - ROM_IBMXT, /*301 keyboard error*/ + ROM_IBMPC = 0, + ROM_IBMXT, ROM_IBMPCJR, ROM_GENXT, /*'Generic XT BIOS'*/ ROM_DTKXT, @@ -371,7 +191,7 @@ enum ROM_PC200, ROM_PC1640, ROM_PC2086, - ROM_PC3086, + ROM_PC3086, ROM_AMIXT, /*XT Clone with AMI BIOS*/ ROM_LTXT, ROM_LXT3, @@ -384,17 +204,29 @@ enum ROM_IBMAT, ROM_CMDPC30, ROM_AMI286, + ROM_TG286M, ROM_AWARD286, + ROM_GDC212M, + ROM_GW286CT, + ROM_SPC4200P, + ROM_SPC4216P, + ROM_SPC4620P, ROM_DELL200, ROM_MISC286, ROM_IBMAT386, ROM_ACER386, + ROM_KMXC02, ROM_MEGAPC, + ROM_AMA932J, ROM_AMI386SX, + ROM_SPC6000A, + ROM_SPC6033P, ROM_AMI486, ROM_WIN486, ROM_PCI486, ROM_SIS496, + ROM_P55VA, /* Epox P55-VA/430VX/Award/SMC FDC37C932FR*/ + ROM_P55TVP4, /* ASUS P/I-P55TVP4/430VX/Award/Winbond W8387F*/ ROM_430VX, ROM_ENDEAVOR, ROM_REVENGE, @@ -403,11 +235,48 @@ enum ROM_IBMPS1_2121, ROM_AMI386DX_OPTI495, ROM_MR386DX_OPTI495, + ROM_P55T2P4, /* ASUS P/I-P55T2P4/430HX/Award/Winbond W8387F*/ ROM_IBMPS2_M30_286, ROM_IBMPS2_M50, ROM_IBMPS2_M55SX, ROM_IBMPS2_M80, - + ROM_ATARIPC3, + ROM_IBMXT286, + ROM_EPSON_PCAX, + ROM_EPSON_PCAX2E, + ROM_EPSON_PCAX3, + ROM_T3100E, + ROM_T1000, + ROM_T1200, + ROM_PB_L300SX, + ROM_NCR_PC4I, + ROM_TO16_PC, + ROM_COMPAQ_PII, + ROM_ELX_PC425X, + ROM_PB570, + ROM_ZAPPA, + ROM_PB520R, + ROM_COMPAQ_PIP, + ROM_XI8088, + ROM_IBMPS2_M70_TYPE3, + ROM_IBMPS2_M70_TYPE4, + ROM_TULIP_TC7, + ROM_ZD_SUPERS, /* [8088] Zenith Data Systems SupersPort */ + ROM_PB410A, + ROM_PPC512, + ROM_BULL_MICRAL_45, + ROM_FIC_VA503P, + ROM_CBM_SL386SX25, + ROM_IBMPS1_2133_451, + ROM_ECS_386_32, + ROM_LEDGE_MODELM, + ROM_HYUNDAI_SUPER286TR, + ROM_ITAUTEC_INFOWAYM, + ROM_DESKPRO, + ROM_VS440FX, + ROM_GA686BX, + ROM_PC5086, + ROM_MAX }; @@ -418,19 +287,23 @@ int romset; enum { + GFX_BUILTIN = -1, GFX_CGA = 0, GFX_MDA, GFX_HERCULES, GFX_EGA, /*Using IBM EGA BIOS*/ GFX_TVGA, /*Using Trident TVGA8900D BIOS*/ GFX_ET4000, /*Tseng ET4000*/ + GFX_KASAN16VGA, /*Kasan Hangulmadang-16 (Tseng ET4000AX)*/ + GFX_TGKOREANVGA, /*Trigem Korean VGA(Tseng ET4000AX)*/ 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_VGA, /*IBM VGA*/ GFX_VGAEDGE16, /*ATI VGA Edge-16 (18800-1)*/ + GFX_ATIKOREANVGA, /*ATI Korean VGA (28800-5)*/ GFX_VGACHARGER, /*ATI VGA Charger (28800-5)*/ GFX_OTI067, /*Oak OTI-067*/ GFX_MACH64GX, /*ATI Graphics Pro Turbo (Mach64)*/ @@ -438,11 +311,31 @@ enum GFX_VIRGEDX, /*S3 Virge/DX*/ GFX_PHOENIX_TRIO32, /*S3 732/Trio32 (Phoenix)*/ GFX_PHOENIX_TRIO64, /*S3 764/Trio64 (Phoenix)*/ - GFX_INCOLOR, /* Hercules InColor */ + GFX_INCOLOR, /* Hercules InColor */ GFX_COLORPLUS, /* Plantronics ColorPlus */ GFX_WY700, /* Wyse 700 */ GFX_GENIUS, /* MDSI Genius */ GFX_MACH64VT2, /*ATI Mach64 VT2*/ + GFX_OLIVETTI_GO481, /*Olivetti GO481 PVGA1A*/ + GFX_TGUI9400CXI, /*Trident TGUI9440CXi*/ + GFX_CL_GD5430, /*Cirrus Logic CL-GD5430*/ + GFX_CL_GD5434, /*Cirrus Logic CL-GD5434*/ + GFX_OTI037, /*Oak OTI-037*/ + GFX_COMPAQ_CGA, /*Compaq CGA*/ + GFX_SIGMA400, /*Sigma Designs Color 400 */ + GFX_PGC, /*Professional Graphics Controller */ + GFX_IM1024, /*Vermont Microsystems IM1024 */ + GFX_EGAWONDER800, /*ATI EGA Wonder 800+*/ + GFX_MYSTIQUE, /*Matrox Mystique*/ + GFX_AVGA2, /*Acumos AVGA2 / Cirrus Logic CL-GD5402*/ + GFX_CL_GD5428, /*Cirrus Logic CL-GD5428*/ + GFX_IBM_GD5428, /*IBM 1MB SVGA Adapter/A*/ + GFX_TVGA9000B, /*Trident TVGA9000B*/ + GFX_BANSHEE, /*Voodoo Banshee - reference PCI board with SGRAM*/ + GFX_CL_BANSHEE, /*Creative Labs Voodoo Blaster Banshee PCI - with SDRAM*/ + GFX_VOODOO_3_2000, /*Voodoo 3 2000*/ + GFX_VOODOO_3_3000, /*Voodoo 3 3000*/ + GFX_MAX }; @@ -465,14 +358,12 @@ extern int changeframecount; /*Sound*/ int ppispeakon; -float CGACONST; -float MDACONST; -float VGACONST1,VGACONST2; -float RTCCONST; +extern uint64_t CGACONST; +extern uint64_t MDACONST; +extern uint64_t VGACONST1,VGACONST2; +extern uint64_t RTCCONST; int gated,speakval,speakon; -#define SOUNDBUFLEN (48000/20) - /*Sound Blaster*/ #define SADLIB 1 /*No DSP*/ @@ -486,8 +377,6 @@ int gated,speakval,speakon; #define SND_WSS 9 /*Windows Sound System*/ #define SND_PAS16 10 /*Pro Audio Spectrum 16*/ -char pcempath[512]; - /*Hard disc*/ @@ -498,7 +387,7 @@ typedef struct int tracks; } PcemHDC; -PcemHDC hdc[4]; +PcemHDC hdc[7]; /*Keyboard*/ int keybsenddelay; @@ -508,7 +397,6 @@ int keybsenddelay; extern int cdrom_drive; extern int old_cdrom_drive; extern int idecallback[2]; -extern int cdrom_enabled; #define CD_STATUS_EMPTY 0 #define CD_STATUS_DATA_ONLY 1 @@ -544,8 +432,6 @@ void resetpc_cad(); extern int start_in_fullscreen; extern int window_w, window_h, window_x, window_y, window_remember; -void get_executable_name(char *s, int size); - void startblit(); void endblit(); @@ -561,6 +447,12 @@ void resetpchard(); void speedchanged(); void saveconfig(char *fn); -void getpath(); +void saveconfig_global_only(); #define UNUSED(x) (void)x + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +void ide_padstr(char *str, const char *src, int len); + +void stop_emulation_now(void); diff --git a/src/icons/16x16/cd.png b/src/icons/16x16/cd.png new file mode 100644 index 0000000..6afc04b Binary files /dev/null and b/src/icons/16x16/cd.png differ diff --git a/src/icons/16x16/computer_add.png b/src/icons/16x16/computer_add.png new file mode 100644 index 0000000..e89c1df Binary files /dev/null and b/src/icons/16x16/computer_add.png differ diff --git a/src/icons/16x16/computer_delete.png b/src/icons/16x16/computer_delete.png new file mode 100644 index 0000000..06eb7c6 Binary files /dev/null and b/src/icons/16x16/computer_delete.png differ diff --git a/src/icons/16x16/computer_edit.png b/src/icons/16x16/computer_edit.png new file mode 100644 index 0000000..88f128f Binary files /dev/null and b/src/icons/16x16/computer_edit.png differ diff --git a/src/icons/16x16/computer_go.png b/src/icons/16x16/computer_go.png new file mode 100644 index 0000000..2cf1c6b Binary files /dev/null and b/src/icons/16x16/computer_go.png differ diff --git a/src/icons/16x16/control_eject.png b/src/icons/16x16/control_eject.png new file mode 100644 index 0000000..00deee0 Binary files /dev/null and b/src/icons/16x16/control_eject.png differ diff --git a/src/icons/16x16/control_play_blue.png b/src/icons/16x16/control_play_blue.png new file mode 100644 index 0000000..184be23 Binary files /dev/null and b/src/icons/16x16/control_play_blue.png differ diff --git a/src/icons/16x16/diskette.png b/src/icons/16x16/diskette.png new file mode 100644 index 0000000..d0d400e Binary files /dev/null and b/src/icons/16x16/diskette.png differ diff --git a/src/icons/16x16/door_out.png b/src/icons/16x16/door_out.png new file mode 100644 index 0000000..23805d2 Binary files /dev/null and b/src/icons/16x16/door_out.png differ diff --git a/src/icons/16x16/drive.png b/src/icons/16x16/drive.png new file mode 100644 index 0000000..e3979a8 Binary files /dev/null and b/src/icons/16x16/drive.png differ diff --git a/src/icons/16x16/drive_add.png b/src/icons/16x16/drive_add.png new file mode 100644 index 0000000..0a6b97c Binary files /dev/null and b/src/icons/16x16/drive_add.png differ diff --git a/src/icons/16x16/folder.png b/src/icons/16x16/folder.png new file mode 100644 index 0000000..f1ed9ab Binary files /dev/null and b/src/icons/16x16/folder.png differ diff --git a/src/icons/16x16/joystick.png b/src/icons/16x16/joystick.png new file mode 100644 index 0000000..ee165ef Binary files /dev/null and b/src/icons/16x16/joystick.png differ diff --git a/src/icons/16x16/network_ethernet.png b/src/icons/16x16/network_ethernet.png new file mode 100644 index 0000000..01b1d4c Binary files /dev/null and b/src/icons/16x16/network_ethernet.png differ diff --git a/src/icons/16x16/setting_tools.png b/src/icons/16x16/setting_tools.png new file mode 100644 index 0000000..81857cd Binary files /dev/null and b/src/icons/16x16/setting_tools.png differ diff --git a/src/icons/16x16/widescreen.png b/src/icons/16x16/widescreen.png new file mode 100644 index 0000000..ba7e1c4 Binary files /dev/null and b/src/icons/16x16/widescreen.png differ diff --git a/src/icons/24x24/pause.png b/src/icons/24x24/pause.png new file mode 100644 index 0000000..7e2e38d Binary files /dev/null and b/src/icons/24x24/pause.png differ diff --git a/src/icons/24x24/play.png b/src/icons/24x24/play.png new file mode 100644 index 0000000..bf72ed1 Binary files /dev/null and b/src/icons/24x24/play.png differ diff --git a/src/icons/24x24/refresh.png b/src/icons/24x24/refresh.png new file mode 100644 index 0000000..c5054b3 Binary files /dev/null and b/src/icons/24x24/refresh.png differ diff --git a/src/icons/24x24/stop.png b/src/icons/24x24/stop.png new file mode 100644 index 0000000..8792c93 Binary files /dev/null and b/src/icons/24x24/stop.png differ diff --git a/src/icons/32x32/add.png b/src/icons/32x32/add.png new file mode 100644 index 0000000..60a7a29 Binary files /dev/null and b/src/icons/32x32/add.png differ diff --git a/src/icons/32x32/computer_add.png b/src/icons/32x32/computer_add.png new file mode 100644 index 0000000..a08763b Binary files /dev/null and b/src/icons/32x32/computer_add.png differ diff --git a/src/icons/32x32/computer_delete.png b/src/icons/32x32/computer_delete.png new file mode 100644 index 0000000..5a4416e Binary files /dev/null and b/src/icons/32x32/computer_delete.png differ diff --git a/src/icons/32x32/computer_edit.png b/src/icons/32x32/computer_edit.png new file mode 100644 index 0000000..07a0101 Binary files /dev/null and b/src/icons/32x32/computer_edit.png differ diff --git a/src/icons/32x32/computer_go.png b/src/icons/32x32/computer_go.png new file mode 100644 index 0000000..89e2b46 Binary files /dev/null and b/src/icons/32x32/computer_go.png differ diff --git a/src/icons/32x32/control_play_blue.png b/src/icons/32x32/control_play_blue.png new file mode 100644 index 0000000..a1f7345 Binary files /dev/null and b/src/icons/32x32/control_play_blue.png differ diff --git a/src/icons/32x32/delete.png b/src/icons/32x32/delete.png new file mode 100644 index 0000000..30a45b8 Binary files /dev/null and b/src/icons/32x32/delete.png differ diff --git a/src/icons/32x32/door_in.png b/src/icons/32x32/door_in.png new file mode 100644 index 0000000..a65ed58 Binary files /dev/null and b/src/icons/32x32/door_in.png differ diff --git a/src/icons/32x32/door_out.png b/src/icons/32x32/door_out.png new file mode 100644 index 0000000..e4efe06 Binary files /dev/null and b/src/icons/32x32/door_out.png differ diff --git a/src/icons/32x32/drive.png b/src/icons/32x32/drive.png new file mode 100644 index 0000000..1b21050 Binary files /dev/null and b/src/icons/32x32/drive.png differ diff --git a/src/icons/32x32/joystick.png b/src/icons/32x32/joystick.png new file mode 100644 index 0000000..c7fb11e Binary files /dev/null and b/src/icons/32x32/joystick.png differ diff --git a/src/icons/32x32/motherboard.png b/src/icons/32x32/motherboard.png new file mode 100644 index 0000000..ce695b1 Binary files /dev/null and b/src/icons/32x32/motherboard.png differ diff --git a/src/icons/32x32/mouse_pc.png b/src/icons/32x32/mouse_pc.png new file mode 100644 index 0000000..d3c75d2 Binary files /dev/null and b/src/icons/32x32/mouse_pc.png differ diff --git a/src/icons/32x32/network_ethernet.png b/src/icons/32x32/network_ethernet.png new file mode 100644 index 0000000..9df8b73 Binary files /dev/null and b/src/icons/32x32/network_ethernet.png differ diff --git a/src/icons/32x32/setting_tools.png b/src/icons/32x32/setting_tools.png new file mode 100644 index 0000000..2a1e727 Binary files /dev/null and b/src/icons/32x32/setting_tools.png differ diff --git a/src/icons/32x32/sound.png b/src/icons/32x32/sound.png new file mode 100644 index 0000000..8c2baf0 Binary files /dev/null and b/src/icons/32x32/sound.png differ diff --git a/src/icons/32x32/textfield_rename.png b/src/icons/32x32/textfield_rename.png new file mode 100644 index 0000000..d35927f Binary files /dev/null and b/src/icons/32x32/textfield_rename.png differ diff --git a/src/icons/32x32/video_mode.png b/src/icons/32x32/video_mode.png new file mode 100644 index 0000000..e5ee86c Binary files /dev/null and b/src/icons/32x32/video_mode.png differ diff --git a/src/icons/32x32/widescreen.png b/src/icons/32x32/widescreen.png new file mode 100644 index 0000000..60042ac Binary files /dev/null and b/src/icons/32x32/widescreen.png differ diff --git a/src/icons/cd.png b/src/icons/cd.png new file mode 100644 index 0000000..ef43223 Binary files /dev/null and b/src/icons/cd.png differ diff --git a/src/icons/disk.png b/src/icons/disk.png new file mode 100644 index 0000000..99d532e Binary files /dev/null and b/src/icons/disk.png differ diff --git a/src/icons/drive.png b/src/icons/drive.png new file mode 100644 index 0000000..37b7c9b Binary files /dev/null and b/src/icons/drive.png differ diff --git a/src/icons/pause.svg b/src/icons/pause.svg new file mode 100644 index 0000000..537fa7f --- /dev/null +++ b/src/icons/pause.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icons/pause24.png b/src/icons/pause24.png new file mode 100644 index 0000000..7e2e38d Binary files /dev/null and b/src/icons/pause24.png differ diff --git a/src/icons/play-button.svg b/src/icons/play-button.svg new file mode 100644 index 0000000..9f46031 --- /dev/null +++ b/src/icons/play-button.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icons/play24.png b/src/icons/play24.png new file mode 100644 index 0000000..bf72ed1 Binary files /dev/null and b/src/icons/play24.png differ diff --git a/src/icons/refresh.svg b/src/icons/refresh.svg new file mode 100644 index 0000000..f3f25f1 --- /dev/null +++ b/src/icons/refresh.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icons/refresh24.png b/src/icons/refresh24.png new file mode 100644 index 0000000..c5054b3 Binary files /dev/null and b/src/icons/refresh24.png differ diff --git a/src/icons/stop.svg b/src/icons/stop.svg new file mode 100644 index 0000000..65d7bf1 --- /dev/null +++ b/src/icons/stop.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icons/stop24.png b/src/icons/stop24.png new file mode 100644 index 0000000..8792c93 Binary files /dev/null and b/src/icons/stop24.png differ diff --git a/src/icons/svg/pause.svg b/src/icons/svg/pause.svg new file mode 100644 index 0000000..537fa7f --- /dev/null +++ b/src/icons/svg/pause.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icons/svg/play-button.svg b/src/icons/svg/play-button.svg new file mode 100644 index 0000000..9f46031 --- /dev/null +++ b/src/icons/svg/play-button.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icons/svg/refresh.svg b/src/icons/svg/refresh.svg new file mode 100644 index 0000000..f3f25f1 --- /dev/null +++ b/src/icons/svg/refresh.svg @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/icons/svg/stop.svg b/src/icons/svg/stop.svg new file mode 100644 index 0000000..65d7bf1 --- /dev/null +++ b/src/icons/svg/stop.svg @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/ide.c b/src/ide.c index 766a683..86a3619 100644 --- a/src/ide.c +++ b/src/ide.c @@ -1,8 +1,4 @@ -/*RPCemu v0.6 by Tom Walker - IDE emulation*/ -//#define RPCEMU_IDE - -#define IDE_TIME (5 * 100 * (1 << TIMER_SHIFT)) +#define IDE_TIME (10 * TIMER_USEC) #define _LARGEFILE_SOURCE #define _LARGEFILE64_SOURCE @@ -14,30 +10,17 @@ #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 "ibm.h" +#include "hdd.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "hdd_file.h" +#include "scsi.h" +#include "scsi_cd.h" +#include "scsi_zip.h" #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 @@ -60,174 +43,13 @@ #define WIN_READ_DMA 0xC8 #define WIN_WRITE_DMA 0xCA #define WIN_SETIDLE1 0xE3 +#define WIN_CHECK_POWER_MODE 0xE5 #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_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_SEND_DVD_STRUCTURE 0xad -#define GPCMD_SET_SPEED 0xbb -#define GPCMD_MECHANISM_STATUS 0xbd -#define GPCMD_READ_CD 0xbe - -/* 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_LBA_OUT_OF_RANGE 0x21 -#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 -#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 -#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 +#define WIN_SET_FEATURES 0xEF /** 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)*/ -/* 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 - -/* 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, - [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, - [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, - [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 { @@ -236,6 +58,8 @@ enum IDE_CDROM }; +struct IDE; + typedef struct IDE { int type; @@ -246,14 +70,7 @@ typedef struct IDE 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; @@ -261,41 +78,41 @@ typedef struct IDE uint32_t lba_addr; int skip512; int blocksize, blockcount; + uint8_t sector_buffer[256*512]; + int do_initial_read; + int sector_pos; + hdd_file_t hdd_file; + atapi_device_t atapi; } IDE; -IDE ide_drives[4]; +int cdrom_channel = 2; +int zip_channel = -1; + +IDE ide_drives[7]; IDE *ext_ide; -char ide_fn[4][512]; +char ide_fn[7][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); +int (*ide_bus_master_read_data)(int channel, uint8_t *data, int size, void *p); +int (*ide_bus_master_write_data)(int channel, uint8_t *data, int size, void *p); +void (*ide_bus_master_set_irq)(int channel, void *p); +void *ide_bus_master_p; -static void callnonreadcd(IDE *ide); -static void callreadcd(IDE *ide); -static void atapicommand(int ide_board); - -int idecallback[2] = {0, 0}; +pc_timer_t ide_timer[2]; int cur_ide[2]; uint8_t getstat(IDE *ide) { return ide->atastat; } -static inline void ide_irq_raise(IDE *ide) +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"); picint((ide->board)?(1<<15):(1<<14)); if (ide_bus_master_set_irq) - ide_bus_master_set_irq(ide->board); -#endif + ide_bus_master_set_irq(ide->board, ide_bus_master_p); } ide->irqstat=1; ide->service=1; @@ -305,34 +122,17 @@ 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 picintc((ide->board)?(1<<15):(1<<14)); -#endif // } ide->irqstat=0; } 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 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)); -#endif } /** * Copy a string into a buffer, padding with spaces, and placing characters as @@ -343,8 +143,7 @@ void ide_irq_update(IDE *ide) * @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) +void ide_padstr(char *str, const char *src, int len) { int i, v; @@ -358,29 +157,6 @@ ide_padstr(char *str, const char *src, int len) } } -/** - * 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 */ @@ -390,22 +166,17 @@ static void ide_identify(IDE *ide) //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 */ + if ((hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) >= 16514064) + ide->buffer[1] = 16383; + 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*/ @@ -415,138 +186,12 @@ static void ide_identify(IDE *ide) 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 ? 9 : 7] : 0xFF; -} - /* * Return the sector offset for the current register values */ @@ -558,8 +203,8 @@ static off64_t ide_get_sector(IDE *ide) } else { - int heads = ide->hpc; - int sectors = ide->spt; + int heads = ide->hdd_file.hpc; + int sectors = ide->hdd_file.spt; return ((((off64_t) ide->cylinder * heads) + ide->head) * sectors) + (ide->sector - 1) + ide->skip512; @@ -578,10 +223,12 @@ static void ide_next_sector(IDE *ide) else { ide->sector++; - if (ide->sector == (ide->spt + 1)) { + + if (ide->sector == (ide->hdd_file.spt + 1)) { ide->sector = 1; ide->head++; - if (ide->head == ide->hpc) { + + if (ide->head == ide->hdd_file.hpc) { ide->head = 0; ide->cylinder++; } @@ -589,94 +236,15 @@ static void ide_next_sector(IDE *ide) } } -#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; + hdd_load(&ide->hdd_file, d, fn); - rpclog("%i %i %i\n",ide->spt,ide->hpc,ide->skip512); + if (ide->hdd_file.f) + ide->type = IDE_HDD; + else + ide->type = IDE_NONE; } -#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) { @@ -684,7 +252,7 @@ void ide_set_signature(IDE *ide) 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; +// if (ide->type == IDE_HDD) ide->drive = 0; } void resetide(void) @@ -694,122 +262,73 @@ void resetide(void) /* 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; - } + hdd_close(&ide_drives[d].hdd_file); + ide_drives[d].atastat = READY_STAT | DSC_STAT; ide_drives[d].service = 0; ide_drives[d].board = (d & 2) ? 1 : 0; } - 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. */ + if (hdd_controller_current_is_ide()) + { + for (d = 0; d < 4; d++) + { + ide_drives[d].drive = d; - 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]); - } + if (cdrom_channel == d) + { + ide_drives[d].type = IDE_CDROM; + scsi_bus_atapi_init(&ide_drives[d].atapi.bus, &scsi_cd, d, &ide_drives[d].atapi); + } + else if (zip_channel == d) + { + ide_drives[d].type = IDE_CDROM; + scsi_bus_atapi_init(&ide_drives[d].atapi.bus, &scsi_zip, d, &ide_drives[d].atapi); + } + else + { + loadhd(&ide_drives[d], d, ide_fn[d]); + } - ide_set_signature(&ide_drives[d]); + ide_set_signature(&ide_drives[d]); + + ide_drives[d].atapi.ide = &ide_drives[d]; + ide_drives[d].atapi.board = (d & 2) ? 1 : 0; + ide_drives[d].atapi.atastat = &ide_drives[d].atastat; + ide_drives[d].atapi.error = &ide_drives[d].error; + ide_drives[d].atapi.cylinder = &ide_drives[d].cylinder; + } } -#endif + cur_ide[0] = 0; cur_ide[1] = 2; - -// 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)) + if (ide->command == WIN_PACKETCMD) { -// 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; + atapi_data_write(&ide->atapi, val); + } + else + { + 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)) + if (ide->pos>=512) { - 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); + ide->pos=0; + ide->atastat = BUSY_STAT; + if (ide->command == WIN_WRITE_MULTIPLE) + callbackide(ide_board); + else + timer_set_delay_u64(&ide_timer[ide_board], 6 * IDE_TIME); } - 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(); } } @@ -824,15 +343,15 @@ 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); +// if (ide_board) +// pclog("WriteIDE %04X %02X from %04X(%08X):%08X %i\n", addr, val, CS, cs, cpu_state.pc, ins); // return; addr|=0x80; // 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); @@ -907,8 +426,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) if (IDE_DRIVE_IS_CDROM(ide_other)) ide_other->cylinder=0xEB14; - idecallback[ide_board] = 0; - timer_update_outstanding(); + timer_disable(&ide_timer[ide_board]); return; } @@ -939,18 +457,14 @@ void writeide(int ide_board, uint16_t addr, uint8_t 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(); + timer_set_delay_u64(&ide_timer[ide_board], 100*IDE_TIME); 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(); + timer_set_delay_u64(&ide_timer[ide_board], 100*IDE_TIME); return; case WIN_READ_MULTIPLE: @@ -974,9 +488,8 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) 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(); + timer_set_delay_u64(&ide_timer[ide_board], 200*IDE_TIME); + ide->do_initial_read = 1; return; case WIN_WRITE_MULTIPLE: @@ -1008,9 +521,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) 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(); + timer_set_delay_u64(&ide_timer[ide_board], 200*IDE_TIME); return; case WIN_VERIFY: @@ -1020,9 +531,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) 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(); + timer_set_delay_u64(&ide_timer[ide_board], 200*IDE_TIME); return; case WIN_FORMAT: @@ -1034,42 +543,42 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) case WIN_SPECIFY: /* Initialize Drive Parameters */ ide->atastat = BUSY_STAT; - timer_process(); - idecallback[ide_board]=30*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&ide_timer[ide_board], 30*IDE_TIME); // pclog("SPECIFY\n"); // output=1; return; case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ + ide->atastat = BUSY_STAT; + timer_set_delay_u64(&ide_timer[ide_board], 200*IDE_TIME); + return; + case WIN_PIDENTIFY: /* Identify Packet Device */ case WIN_SET_MULTIPLE_MODE: /*Set Multiple Mode*/ // output=1; case WIN_SETIDLE1: /* Idle */ + case WIN_CHECK_POWER_MODE: 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: + case WIN_SET_FEATURES: // output=3; // timetolive=500; ide->atastat = BUSY_STAT; - timer_process(); - idecallback[ide_board]=200*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&ide_timer[ide_board], 200*IDE_TIME); return; case WIN_PACKETCMD: /* ATAPI Packet */ - ide->packetstatus = ATAPI_STATUS_IDLE; + if (ide->type == IDE_CDROM) + atapi_command_start(&ide->atapi, ide->cylprecomp); + ide->atastat = BUSY_STAT; - timer_process(); - idecallback[ide_board]=1;//30*IDE_TIME; - timer_update_outstanding(); - ide->pos=0; + timer_set_delay_u64(&ide_timer[ide_board], IDE_TIME); + + ide->atapi.bus_state = 0; return; case 0xF0: @@ -1086,9 +595,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) 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(); + timer_set_delay_u64(&ide_timer[ide_board], 500*IDE_TIME); ide->reset = ide_other->reset = 1; ide->atastat = ide_other->atastat = BUSY_STAT; // pclog("IDE Reset %i\n", ide_board); @@ -1096,9 +603,7 @@ void writeide(int ide_board, uint16_t addr, uint8_t val) if (val & 4) { /*Drive held in reset*/ - timer_process(); - idecallback[ide_board] = 0; - timer_update_outstanding(); + timer_disable(&ide_timer[ide_board]); ide->atastat = ide_other->atastat = BUSY_STAT; } ide->fdisk = ide_other->fdisk = val; @@ -1115,13 +620,12 @@ uint8_t readide(int ide_board, uint16_t addr) uint16_t tempw; addr|=0x80; -#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; @@ -1144,7 +648,10 @@ uint8_t readide(int ide_board, uint16_t addr) case 0x1F2: /* Sector count */ // pclog("Read sector count %02X\n",ide->secount); - temp = (uint8_t)ide->secount; + if (ide->type == IDE_CDROM && ide->command == WIN_PACKETCMD) + temp = atapi_read_iir(&ide->atapi); + else + temp = (uint8_t)ide->secount; break; case 0x1F3: /* Sector */ @@ -1177,6 +684,13 @@ uint8_t readide(int ide_board, uint16_t addr) { // 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); + if (ide->command == WIN_PACKETCMD) + { + if (atapi_read_drq(&ide->atapi)) + temp |= DRQ_STAT; + else + temp &= ~DRQ_STAT; + } } else { @@ -1199,6 +713,13 @@ uint8_t readide(int ide_board, uint16_t addr) { // 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); + if (ide->command == WIN_PACKETCMD) + { + if (atapi_read_drq(&ide->atapi)) + temp |= DRQ_STAT; + else + temp &= ~DRQ_STAT; + } } else { @@ -1208,7 +729,7 @@ uint8_t readide(int ide_board, uint16_t addr) } 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); +// 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,cpu_state.pc,ide_board); return temp; // fatal("Bad IDE read %04X\n", addr); } @@ -1217,54 +738,39 @@ 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)) + if (ide->command == WIN_PACKETCMD) { -// 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 + temp = atapi_data_read(&ide->atapi); + } + else + { + temp = ide->buffer[ide->pos >> 1]; + ide->pos += 2; + if (ide->pos >= 512 && ide->command) { +// pclog("Over! packlen %i %i\n",ide->packlen,ide->pos); + ide->pos = 0; 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(); + ide->atastat = BUSY_STAT | READY_STAT | DSC_STAT; if (ide->command == WIN_READ_MULTIPLE) - callbackide(ide_board); + callbackide(ide_board); else - idecallback[ide_board]=6*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&ide_timer[ide_board], 6 * IDE_TIME); // pclog("set idecallback\n"); // callbackide(ide_board); } @@ -1290,8 +796,8 @@ 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; + atapi_device_t *atapi_dev = &ide->atapi; + ext_ide = ide; // return; if (ide->command==0x30) times30++; @@ -1313,20 +819,24 @@ void callbackide(int ide_board) { ide->cylinder=0xEB14; atapi->stop(); + atapi_reset(&ide->atapi); } if (ide->type == IDE_NONE) { ide->cylinder=0xFFFF; + ide->error = 0xff; atapi->stop(); } if (IDE_DRIVE_IS_CDROM(ide_other)) { ide_other->cylinder=0xEB14; atapi->stop(); + atapi_reset(&ide_other->atapi); } if (ide_other->type == IDE_NONE) { ide_other->cylinder=0xFFFF; + ide_other->error = 0xff; atapi->stop(); } // pclog("Reset callback\n"); @@ -1364,40 +874,48 @@ void callbackide(int ide_board) ide_set_signature(ide); goto abort_cmd; } - addr = ide_get_sector(ide) * 512; + if (ide->do_initial_read) + { + ide->do_initial_read = 0; + ide->sector_pos = 0; + hdd_read_sectors(&ide->hdd_file, ide_get_sector(ide), ide->secount ? ide->secount : 256, ide->sector_buffer); + } + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + ide->sector_pos++; // 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 + + readflash_set(READFLASH_HDC, ide->drive); 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); + if (ide->do_initial_read) + { + ide->do_initial_read = 0; + ide->sector_pos = 0; + hdd_read_sectors(&ide->hdd_file, ide_get_sector(ide), ide->secount ? ide->secount : 256, ide->sector_buffer); + } ide->pos=0; - if (ide_bus_master_read_sector) + if (ide_bus_master_read_data) { - if (ide_bus_master_read_sector(ide_board, (uint8_t *)ide->buffer)) - idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ + if (ide_bus_master_read_data(ide_board, &ide->sector_buffer[ide->sector_pos*512], 512, ide_bus_master_p)) + timer_set_delay_u64(&ide_timer[ide_board], 6*IDE_TIME); /*DMA not performed, try again later*/ else { /*DMA successful*/ + ide->sector_pos++; ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; ide->secount = (ide->secount - 1) & 0xff; @@ -1405,7 +923,7 @@ void callbackide(int ide_board) { ide_next_sector(ide); ide->atastat = BUSY_STAT; - idecallback[ide_board]=6*IDE_TIME; + timer_set_delay_u64(&ide_timer[ide_board], 6*IDE_TIME); } else { @@ -1413,19 +931,22 @@ void callbackide(int ide_board) } } } -#ifndef RPCEMU_IDE - readflash=1; -#endif + + readflash_set(READFLASH_HDC, ide->drive); 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); + if (ide->do_initial_read) + { + ide->do_initial_read = 0; + ide->sector_pos = 0; + hdd_read_sectors(&ide->hdd_file, ide_get_sector(ide), ide->secount ? ide->secount : 256, ide->sector_buffer); + } + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + ide->sector_pos++; ide->pos=0; ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; if (!ide->blockcount)// || ide->secount == 1) @@ -1436,9 +957,8 @@ void callbackide(int ide_board) ide->blockcount++; if (ide->blockcount >= ide->blocksize) ide->blockcount = 0; -#ifndef RPCEMU_IDE - readflash=1; -#endif + + readflash_set(READFLASH_HDC, ide->drive); return; case WIN_WRITE: @@ -1446,10 +966,7 @@ void callbackide(int ide_board) 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); + hdd_write_sectors(&ide->hdd_file, ide_get_sector(ide), 1, ide->buffer); ide_irq_raise(ide); ide->secount = (ide->secount - 1) & 0xff; if (ide->secount) @@ -1460,9 +977,8 @@ void callbackide(int ide_board) } else ide->atastat = READY_STAT | DSC_STAT; -#ifndef RPCEMU_IDE - readflash=1; -#endif + + readflash_set(READFLASH_HDC, ide->drive); return; case WIN_WRITE_DMA: @@ -1470,16 +986,14 @@ void callbackide(int ide_board) goto abort_cmd; } - if (ide_bus_master_write_sector) + if (ide_bus_master_write_data) { - if (ide_bus_master_write_sector(ide_board, (uint8_t *)ide->buffer)) - idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ + if (ide_bus_master_write_data(ide_board, (uint8_t *)ide->buffer, 512, ide_bus_master_p)) + timer_set_delay_u64(&ide_timer[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); + hdd_write_sectors(&ide->hdd_file, ide_get_sector(ide), 1, ide->buffer); ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; @@ -1488,7 +1002,7 @@ void callbackide(int ide_board) { ide_next_sector(ide); ide->atastat = BUSY_STAT; - idecallback[ide_board]=6*IDE_TIME; + timer_set_delay_u64(&ide_timer[ide_board], 6*IDE_TIME); } else { @@ -1496,19 +1010,15 @@ void callbackide(int ide_board) } } } -#ifndef RPCEMU_IDE - readflash=1; -#endif + + readflash_set(READFLASH_HDC, ide->drive); 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); + hdd_write_sectors(&ide->hdd_file, ide_get_sector(ide), 1, ide->buffer); ide->blockcount++; if (ide->blockcount >= ide->blocksize || ide->secount == 1) { @@ -1524,9 +1034,8 @@ void callbackide(int ide_board) } else ide->atastat = READY_STAT | DSC_STAT; -#ifndef RPCEMU_IDE - readflash=1; -#endif + + readflash_set(READFLASH_HDC, ide->drive); return; case WIN_VERIFY: @@ -1538,28 +1047,19 @@ void callbackide(int ide_board) 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 + + readflash_set(READFLASH_HDC, ide->drive); 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); - } + hdd_format_sectors(&ide->hdd_file, ide_get_sector(ide), ide->secount); ide->atastat = READY_STAT | DSC_STAT; ide_irq_raise(ide); -#ifndef RPCEMU_IDE - readflash=1; -#endif + + readflash_set(READFLASH_HDC, ide->drive); return; case WIN_DRIVE_DIAGNOSTICS: @@ -1578,24 +1078,21 @@ void callbackide(int ide_board) 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->hdd_file.spt = ide->secount; + ide->hdd_file.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); + atapi_dev->bus.devices[0]->atapi_identify(ide->buffer, atapi_dev->bus.device_data[0]); + ide->pos=0; ide->error=0; ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; @@ -1607,21 +1104,16 @@ void callbackide(int ide_board) 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 */ @@ -1644,79 +1136,33 @@ void callbackide(int ide_board) } return; + case WIN_SET_FEATURES: + if (ide->type == IDE_NONE) + goto abort_cmd; + if (!IDE_DRIVE_IS_CDROM(ide)) + goto abort_cmd; + + if (!atapi_dev->bus.devices[0]->atapi_set_feature(ide->cylprecomp, ide->secount, atapi_dev->bus.device_data[0])) + goto abort_cmd; + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_CHECK_POWER_MODE: + if (ide->type == IDE_NONE) + { + goto abort_cmd; + } + ide->secount = 0xff; + ide->atastat = READY_STAT | DSC_STAT; + 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); - } + + atapi_process_packet(atapi_dev); + return; } @@ -1730,978 +1176,14 @@ abort_cmd: void ide_callback_pri() { - idecallback[0] = 0; callbackide(0); } void ide_callback_sec() { - idecallback[1] = 0; callbackide(1); } -/*ATAPI CD-ROM emulation*/ - -struct -{ - int sensekey,asc,ascq; -} atapi_sense; - -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; -} - -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*/ - alloc_length = (idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; - - if (alloc_length == 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; - } - - if (atapi->readsector(idebufferb,ide->cdpos)) - { -// pclog("Read sector failed\n"); - atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; - atapi_sense.asc = ASC_LBA_OUT_OF_RANGE; - atapi_sense.ascq = 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_ILLEGAL_OPCODE; - ide->packetstatus = ATAPI_STATUS_ERROR; - idecallback[ide_board]=50*IDE_TIME; - break; - } -#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_EVENT_STATUS_NOTIFICATION: /*0x4a*/ - temp_command = idebufferb[0]; - alloc_length = (idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; - - { - struct __attribute__((__packed__)) - { - 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 __attribute__((__packed__)) - { - 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); - } - len = used_len; - 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_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, 0, 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: - 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; - ide->atastat = BUSY_STAT; - 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) @@ -2778,19 +1260,69 @@ void ide_sec_disable() io_removehandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); } -void ide_init() +static 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); + timer_add(&ide_timer[0], ide_callback_pri, NULL, 0); + timer_add(&ide_timer[1], ide_callback_sec, NULL, 0); + + return (void *)-1; } -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)) +static void ide_close(void *p) { - ide_bus_master_read_sector = read_sector; - ide_bus_master_write_sector = write_sector; - ide_bus_master_set_irq = set_irq; + int c; + + for (c = 0; c < 4; c++) + { + ide_drives[c].type = IDE_NONE; + hdd_close(&ide_drives[c].hdd_file); + } } + +void ide_set_bus_master(int (*read_data)(int channel, uint8_t *data, int size, void *p), int (*write_data)(int channel, uint8_t *data, int size, void *p), void (*set_irq)(int channel, void *p), void *p) +{ + ide_bus_master_read_data = read_data; + ide_bus_master_write_data = write_data; + ide_bus_master_set_irq = set_irq; + ide_bus_master_p = p; +} + +void ide_reset_devices() +{ + if (ide_drives[0].type != IDE_NONE || ide_drives[1].type != IDE_NONE) + { + timer_set_delay_u64(&ide_timer[0], 500*IDE_TIME); + ide_drives[0].reset = ide_drives[1].reset = 1; + ide_drives[0].atastat = ide_drives[1].atastat = BUSY_STAT; + if (ide_drives[0].type != IDE_NONE) + cur_ide[0] = 0; + else + cur_ide[0] = 1; + } + if (ide_drives[2].type != IDE_NONE || ide_drives[3].type != IDE_NONE) + { + timer_set_delay_u64(&ide_timer[1], 500*IDE_TIME); + ide_drives[2].reset = ide_drives[3].reset = 1; + ide_drives[2].atastat = ide_drives[3].atastat = BUSY_STAT; + if (ide_drives[2].type != IDE_NONE) + cur_ide[1] = 2; + else + cur_ide[1] = 3; + } +} + +device_t ide_device = +{ + "Standard IDE", + DEVICE_AT, + ide_init, + ide_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/ide.h b/src/ide.h index ae1ab63..2ce681a 100644 --- a/src/ide.h +++ b/src/ide.h @@ -1,6 +1,9 @@ #ifndef __IDE__ #define __IDE__ +#include "device.h" +#include "timer.h" + struct IDE; extern void writeide(int ide_board, uint16_t addr, uint8_t val); @@ -9,53 +12,54 @@ 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_pri_enable(); extern void ide_sec_enable(); extern void ide_pri_disable(); extern void ide_sec_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)); +extern void ide_set_bus_master(int (*read_data)(int channel, uint8_t *data, int size, void *p), int (*write_data)(int channel, uint8_t *data, int size, void *p), void (*set_irq)(int channel, void *p), void *p); +void ide_irq_raise(struct IDE *ide); +void ide_reset_devices(); -/*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); - int (*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 int (*ide_bus_master_read_data)(int channel, uint8_t *data, int size, void *p); +extern int (*ide_bus_master_write_data)(int channel, uint8_t *data, int size, void *p); +extern void (*ide_bus_master_set_irq)(int channel, void *p); +extern void *ide_bus_master_p; -extern ATAPI *atapi; - -void atapi_discchanged(); -void atapi_insert_cdrom(); +#include "ide_atapi.h" extern int ideboard; -extern int idecallback[2]; +extern pc_timer_t ide_timer[2]; -extern char ide_fn[4][512]; +extern char ide_fn[7][512]; -extern int cdrom_channel; +extern int cdrom_channel, zip_channel; uint32_t atapi_get_cd_channel(int channel); uint32_t atapi_get_cd_volume(int channel); -#define CDROM_ISO 200 +#define CDROM_IMAGE 200 +extern device_t ide_device; + +/* 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 */ + +#define FEATURE_SET_TRANSFER_MODE 0x03 +#define FEATURE_ENABLE_IRQ_OVERLAPPED 0x5d +#define FEATURE_ENABLE_IRQ_SERVICE 0x5e +#define FEATURE_DISABLE_REVERT 0x66 +#define FEATURE_ENABLE_REVERT 0xcc +#define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd +#define FEATURE_DISABLE_IRQ_SERVICE 0xde + #endif //__IDE__ diff --git a/src/ide_atapi.c b/src/ide_atapi.c new file mode 100644 index 0000000..45586e7 --- /dev/null +++ b/src/ide_atapi.c @@ -0,0 +1,578 @@ +#include "ibm.h" +#include "ide.h" +#include "ide_atapi.h" +#include "scsi.h" +#include "timer.h" + +#define IDE_TIME (100 * TIMER_USEC) + +#define ATAPI_STATE_IDLE 0 +#define ATAPI_STATE_COMMAND 1 +#define ATAPI_STATE_GOT_COMMAND 2 +#define ATAPI_STATE_NEXT_PHASE 3 +#define ATAPI_STATE_READ_STATUS 4 +#define ATAPI_STATE_READ_MESSAGE 5 +#define ATAPI_STATE_END_PHASE 6 +#define ATAPI_STATE_READ_DATA 7 +#define ATAPI_STATE_READ_DATA_WAIT 8 +#define ATAPI_STATE_WRITE_DATA 9 +#define ATAPI_STATE_WRITE_DATA_WAIT 10 +#define ATAPI_STATE_RETRY_READ_DMA 11 +#define ATAPI_STATE_RETRY_WRITE_DMA 12 + +#define FEATURES_DMA 0x01 +#define FEATURES_OVERLAP 0x02 + +ATAPI *atapi; + +void atapi_data_write(atapi_device_t *atapi_dev, uint16_t val) +{ + switch (atapi_dev->state) + { + case ATAPI_STATE_COMMAND: + atapi_dev->command[atapi_dev->command_pos++] = val & 0xff; + atapi_dev->command[atapi_dev->command_pos++] = val >> 8; + if (atapi_dev->command_pos >= 12) + { + atapi_dev->state = ATAPI_STATE_GOT_COMMAND; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + *atapi_dev->atastat = BUSY_STAT | (*atapi_dev->atastat & ERR_STAT); + } + break; + + case ATAPI_STATE_WRITE_DATA_WAIT: + atapi_dev->data[atapi_dev->data_write_pos++] = val & 0xff; + atapi_dev->data[atapi_dev->data_write_pos++] = val >> 8; +// pclog("Write ATAPI data %i %i %i\n", atapi_dev->data_write_pos, atapi_dev->data_read_pos, idecallback[atapi_dev->board]); + if (atapi_dev->data_write_pos >= atapi_dev->data_read_pos) + { + atapi_dev->bus_state = 0; + atapi_dev->state = ATAPI_STATE_WRITE_DATA; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + *atapi_dev->atastat = BUSY_STAT | (*atapi_dev->atastat & ERR_STAT); + } + break; + } +} + +uint16_t atapi_data_read(atapi_device_t *atapi_dev) +{ + uint16_t temp = 0xffff; + + switch (atapi_dev->state) + { + case ATAPI_STATE_READ_DATA_WAIT: + if (atapi_dev->data_read_pos >= atapi_dev->data_write_pos) + { +// pclog("ATAPI_STATE_READ_DATA_WAIT - out of data!\n"); + break; + } + + temp = atapi_dev->data[atapi_dev->data_read_pos++]; + if (atapi_dev->data_read_pos < atapi_dev->data_write_pos) + temp |= (atapi_dev->data[atapi_dev->data_read_pos++] << 8); +// pclog("Read data %04x\n", temp); + if (atapi_dev->data_read_pos >= atapi_dev->data_write_pos) + { + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6*IDE_TIME); + *atapi_dev->atastat = BUSY_STAT | (*atapi_dev->atastat & ERR_STAT); + } + break; + } + + return temp; +} + +static int wait_for_bus(scsi_bus_t *bus, int state, int req_needed) +{ + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(bus); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) == state && (bus_state & BUS_BSY)) + { + if (!req_needed || (bus_state & BUS_REQ)) + return 1; + } + } + + return 0; +} + +void atapi_command_start(atapi_device_t *atapi, uint8_t features) +{ + scsi_bus_t *bus = &atapi->bus; + + atapi->use_dma = features & 1; + + scsi_bus_update(bus, BUS_SEL | BUS_SETDATA(1 << 0)); + if (!(scsi_bus_read(bus) & BUS_BSY)) + fatal("STATE_SCSI_SELECT failed to select target\n"); + + scsi_bus_update(bus, 0); + if (!(scsi_bus_read(bus) & BUS_BSY)) + fatal("STATE_SCSI_SELECT failed to select target 2\n"); + + /*Device should now be selected*/ + if (!wait_for_bus(bus, BUS_CD, 1)) + fatal("Device failed to request command\n"); + + atapi->state = ATAPI_STATE_COMMAND; + atapi->command_pos = 0; +} + +uint8_t atapi_read_iir(atapi_device_t *atapi_dev) +{ + uint8_t val = 0; + int bus_status = atapi_dev->bus_state;//scsi_bus_read(&atapi_dev->bus); + + if (bus_status & BUS_CD) + val |= 1; + if (bus_status & BUS_IO) + val |= 2; + +// pclog("Read IIR %02X %02x\n", val, bus_status); + + return val; +} + +uint8_t atapi_read_drq(atapi_device_t *atapi_dev) +{ + return atapi_dev->bus_state & BUS_REQ; +} + +void atapi_set_transfer_granularity(atapi_device_t *atapi_dev, int size) +{ + if (atapi_dev->max_transfer_len > size) + atapi_dev->max_transfer_len -= (atapi_dev->max_transfer_len % size); +} + +void atapi_process_packet(atapi_device_t *atapi_dev) +{ +// pclog("atapi_process_packet: state=%i\n", atapi_dev->state); + switch (atapi_dev->state) + { + case ATAPI_STATE_COMMAND: + *atapi_dev->atastat = READY_STAT | (*atapi_dev->atastat & ERR_STAT); + atapi_dev->max_transfer_len = (*atapi_dev->cylinder) & ~1; + if (!atapi_dev->max_transfer_len) + atapi_dev->max_transfer_len = 0xfffe; + atapi_dev->bus_state = BUS_CD | BUS_REQ; + break; + + case ATAPI_STATE_GOT_COMMAND: + { + int pos = 0; + int bus_state; + int c; + + for (c = 0; c < 20; c++) + { + bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + fatal("SEND_COMMAND - bus phase incorrect\n"); + if (bus_state & BUS_REQ) + break; + } + if (c == 20) + fatal("SEND_COMMAND timed out\n"); + + while (1) + { + int bus_out; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + break; + if (bus_state & BUS_REQ) + break; + } + if (c == 20) + { +// pclog("SEND_COMMAND timed out %x\n", scsi_bus_read(&atapi_dev->bus)); + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + break; + } + + bus_state = scsi_bus_read(&atapi_dev->bus); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG | BUS_REQ)) != (BUS_CD | BUS_REQ)) + { +// pclog("SEND_COMMAND - bus state changed %x\n", bus_state); + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + break; + } + + if (pos >= atapi_dev->command_pos) + bus_out = BUS_SETDATA(0); /*Pad out with zeroes*/ + else + bus_out = BUS_SETDATA(atapi_dev->command[pos++]); + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + +// if (pos >= atapi_dev->command_pos) +// fatal("Out of data!\n"); + } + } + break; + + case ATAPI_STATE_NEXT_PHASE: + { + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + +// if (!c) +// pclog("NEXT_PHASE - %x\n", bus_state); + if (!(bus_state & BUS_BSY)) + fatal("NEXT_PHASE - dropped BSY waiting\n"); + + if (bus_state & BUS_REQ) + { + scsi_device_t *scsi_dev = atapi_dev->bus.devices[0]; + void *scsi_data = atapi_dev->bus.device_data[0]; + + switch (bus_state & (BUS_IO | BUS_CD | BUS_MSG)) + { + case 0: + atapi_dev->data_read_pos = scsi_dev->get_bytes_required(scsi_data); + + atapi_dev->data_write_pos = 0; + + if (atapi_dev->use_dma) + { + if (ide_bus_master_write_data) + { + if (ide_bus_master_write_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_read_pos, ide_bus_master_p)) + { + atapi_dev->state = ATAPI_STATE_RETRY_WRITE_DMA; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 1*IDE_TIME); + } + else + { + atapi_dev->data_write_pos = atapi_dev->data_read_pos; + atapi_dev->bus_state = 0; + atapi_dev->state = ATAPI_STATE_WRITE_DATA; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + } + } + else + { + atapi_dev->state = ATAPI_STATE_RETRY_WRITE_DMA; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 1*IDE_TIME); + } + } + else + { + if (atapi_dev->data_read_pos > atapi_dev->max_transfer_len) + atapi_dev->data_read_pos = atapi_dev->max_transfer_len; + + atapi_dev->state = ATAPI_STATE_WRITE_DATA_WAIT; + + *atapi_dev->cylinder = atapi_dev->data_read_pos; + +// pclog("WRITE_DATA: bytes=%i\n", *atapi_dev->cylinder); + *atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT); + atapi_dev->bus_state = BUS_REQ; + ide_irq_raise(atapi_dev->ide); + } + break; + + case BUS_IO: + atapi_dev->state = ATAPI_STATE_READ_DATA; + atapi_dev->data_read_pos = atapi_dev->data_write_pos = 0; + break; + + case (BUS_IO | BUS_CD): + atapi_dev->state = ATAPI_STATE_READ_STATUS; + break; + + case (BUS_CD | BUS_IO | BUS_MSG): + atapi_dev->state = ATAPI_STATE_READ_MESSAGE; + break; + + default: + fatal("NEXT_PHASE - bus state changed %x\n", bus_state); + } + break; + } + } + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + } + break; + + case ATAPI_STATE_READ_STATUS: + { + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_STATUS - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO)) + fatal("READ_STATUS - changed phase\n"); + + if (bus_state & BUS_REQ) + { +// uint8_t status = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read status %02x\n", status); + + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + break; + } + } + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + } + break; + + case ATAPI_STATE_READ_MESSAGE: + { + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_MESSAGE - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO | BUS_MSG)) + { +// pclog("READ_MESSAGE - changed phase\n"); + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t msg = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read message %02x\n", msg); + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + + switch (msg) + { + case MSG_COMMAND_COMPLETE: + atapi_dev->state = ATAPI_STATE_END_PHASE; + break; + + default: + fatal("READ_MESSAGE - unknown message %02x\n", msg); + } + break; + } + } + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + } + break; + + case ATAPI_STATE_READ_DATA: + { + while (atapi_dev->data_write_pos < atapi_dev->max_transfer_len) + { + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_DATA - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO) + { +// pclog("READ_DATA - changed phase\n"); + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data = BUS_GETDATA(bus_state); + int bus_out = 0; + + atapi_dev->data[atapi_dev->data_write_pos++] = data; + +// pclog("Read data %02x %i\n", data, atapi_dev->data_write_pos); + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + break; + } + } + if ((scsi_bus_read(&atapi_dev->bus) & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO) + break; + } + if (atapi_dev->use_dma) + { + if (ide_bus_master_read_data) + { + if (ide_bus_master_read_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_write_pos, ide_bus_master_p)) + { + atapi_dev->state = ATAPI_STATE_RETRY_READ_DMA; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 1*IDE_TIME); + } + else + { + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 1*IDE_TIME); + } + } + else + { + atapi_dev->state = ATAPI_STATE_RETRY_READ_DMA; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 1*IDE_TIME); + } + } + else + { + atapi_dev->state = ATAPI_STATE_READ_DATA_WAIT; + *atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT); + *atapi_dev->cylinder = atapi_dev->data_write_pos; +// pclog("READ_DATA: bytes=%i\n", *atapi_dev->cylinder); + atapi_dev->bus_state = BUS_IO | BUS_REQ; + ide_irq_raise(atapi_dev->ide); + } + } + break; + + case ATAPI_STATE_WRITE_DATA: + { + atapi_dev->data_read_pos = 0; +// pclog("ATAPI_STATE_WRITE_DATA - %i\n", atapi_dev->data_write_pos); + while (atapi_dev->data_read_pos < atapi_dev->data_write_pos) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + fatal("WRITE_DATA - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != 0) + { +// pclog("WRITE_DATA - changed phase\n"); + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data = atapi_dev->data[atapi_dev->data_read_pos++]; + int bus_out; + +// pclog("Write data %02x %i\n", data, atapi_dev->data_read_pos-1); + bus_out = BUS_SETDATA(data); + scsi_bus_update(&atapi_dev->bus, bus_out | BUS_ACK); + scsi_bus_update(&atapi_dev->bus, bus_out & ~BUS_ACK); + } + } + + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 1 * IDE_TIME); + } + break; + + case ATAPI_STATE_END_PHASE: + { + int c; + /*Wait for SCSI command to move to next phase*/ + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&atapi_dev->bus); + + if (!(bus_state & BUS_BSY)) + { +// pclog("END_PHASE - dropped BSY waiting\n"); + atapi_dev->state = ATAPI_STATE_IDLE; + break; + } + + if (bus_state & BUS_REQ) + fatal("END_PHASE - unexpected REQ\n"); + } + if (atapi_dev->state == ATAPI_STATE_IDLE) + { + scsi_device_t *scsi_dev = atapi_dev->bus.devices[0]; + void *scsi_data = atapi_dev->bus.device_data[0]; + + *atapi_dev->atastat = READY_STAT; + atapi_dev->bus_state = BUS_IO | BUS_CD; + if (scsi_dev->get_status(scsi_data) != STATUS_GOOD) + { + *atapi_dev->error = (scsi_dev->get_sense_key(scsi_data) << 4) | ABRT_ERR; + if (scsi_dev->get_sense_key(scsi_data) == KEY_UNIT_ATTENTION) + *atapi_dev->error |= MCR_ERR; + *atapi_dev->atastat |= ERR_STAT; + } + ide_irq_raise(atapi_dev->ide); + } + else + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + } + break; + + case ATAPI_STATE_RETRY_READ_DMA: + { + if (ide_bus_master_read_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_write_pos, ide_bus_master_p)) + { + timer_set_delay_u64(&ide_timer[atapi_dev->board], 1*IDE_TIME); + } + else + { + atapi_dev->state = ATAPI_STATE_NEXT_PHASE; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6*IDE_TIME); + } + } + break; + + case ATAPI_STATE_RETRY_WRITE_DMA: + { + if (ide_bus_master_write_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_read_pos, ide_bus_master_p)) + { + timer_set_delay_u64(&ide_timer[atapi_dev->board], 1*IDE_TIME); + } + else + { + atapi_dev->bus_state = 0; + atapi_dev->state = ATAPI_STATE_WRITE_DATA; + timer_set_delay_u64(&ide_timer[atapi_dev->board], 6 * IDE_TIME); + } + } + break; + } +} + +void atapi_reset(atapi_device_t *atapi_dev) +{ + pclog("atapi_reset\n"); + atapi_dev->state = ATAPI_STATE_IDLE; + atapi_dev->command_pos = 0; + atapi_dev->data_read_pos = 0; + atapi_dev->data_write_pos = 0; + scsi_bus_reset(&atapi_dev->bus); +} diff --git a/src/ide_atapi.h b/src/ide_atapi.h new file mode 100644 index 0000000..ab2174c --- /dev/null +++ b/src/ide_atapi.h @@ -0,0 +1,69 @@ +#ifndef __IDE_ATAPI__ +#define __IDE_ATAPI__ + +#include "scsi.h" + +/*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); + int (*readsector)(uint8_t *b, int sector, int count); + 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(); + +typedef struct atapi_device_t +{ + scsi_bus_t bus; + + uint8_t command[12]; + int command_pos; + + int state; + + int max_transfer_len; + + uint8_t data[65536]; + int data_read_pos, data_write_pos; + + int bus_state; + + struct IDE *ide; + + int board; + uint8_t *atastat; + uint8_t *error; + int *cylinder; + + int use_dma; +} atapi_device_t; + +void atapi_data_write(atapi_device_t *atapi_dev, uint16_t val); +uint16_t atapi_data_read(atapi_device_t *atapi_dev); +void atapi_command_start(atapi_device_t *atapi, uint8_t features); +uint8_t atapi_read_iir(atapi_device_t *atapi_dev); +uint8_t atapi_read_drq(atapi_device_t *atapi_dev); +void atapi_process_packet(atapi_device_t *atapi_dev); +void atapi_set_transfer_granularity(atapi_device_t *atapi_dev, int size); +void atapi_reset(atapi_device_t *atapi_dev); + +#endif diff --git a/src/ide_sff8038i.c b/src/ide_sff8038i.c new file mode 100644 index 0000000..79eda27 --- /dev/null +++ b/src/ide_sff8038i.c @@ -0,0 +1,208 @@ +/*Emulation of SFF-8038i IDE bus mastering interface. + Used by PIIX and VT82C586B IDE controllers*/ +#include "ibm.h" +#include "ide.h" +#include "ide_sff8038i.h" +#include "mem.h" + +static void sff_bus_master_next_addr(sff_busmaster_t *busmaster, int channel) +{ + busmaster[channel].addr = (*(uint32_t *)(&ram[busmaster[channel].ptr_cur])) & ~1; + busmaster[channel].count = (*(uint32_t *)(&ram[busmaster[channel].ptr_cur + 4])) & 0xfffe; + if (!busmaster[channel].count) + busmaster[channel].count = 0x10000; + busmaster[channel].eot = (*(uint32_t *)(&ram[busmaster[channel].ptr_cur + 4])) >> 31; + 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 sff_bus_master_write(uint16_t port, uint8_t val, void *p) +{ + sff_busmaster_t *busmaster = (sff_busmaster_t *)p; + 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) && !(busmaster[channel].command & 1)) /*Start*/ + { + busmaster[channel].ptr_cur = busmaster[channel].ptr; + sff_bus_master_next_addr(busmaster, channel); + busmaster[channel].status |= 1; + } + if (!(val & 1) && (busmaster[channel].command & 1)) /*Stop*/ + busmaster[channel].status &= ~1; + + busmaster[channel].command = val; + break; + case 2: + busmaster[channel].status = (val & 0x60) | ((busmaster[channel].status & ~val) & 6) | (busmaster[channel].status & 1); + break; + case 4: + busmaster[channel].ptr = (busmaster[channel].ptr & 0xffffff00) | val; + break; + case 5: + busmaster[channel].ptr = (busmaster[channel].ptr & 0xffff00ff) | (val << 8); + break; + case 6: + busmaster[channel].ptr = (busmaster[channel].ptr & 0xff00ffff) | (val << 16); + break; + case 7: + busmaster[channel].ptr = (busmaster[channel].ptr & 0x00ffffff) | (val << 24); + break; + } +} + +uint8_t sff_bus_master_read(uint16_t port, void *p) +{ + sff_busmaster_t *busmaster = (sff_busmaster_t *)p; + int channel = (port & 8) ? 1 : 0; +// pclog("PIIX Bus Master read %04X %04x:%08x\n", port, CS, pc); + switch (port & 7) + { + case 0: + return busmaster[channel].command; + case 2: + return busmaster[channel].status; + case 4: + return busmaster[channel].ptr; + case 5: + return busmaster[channel].ptr >> 8; + case 6: + return busmaster[channel].ptr >> 16; + case 7: + return busmaster[channel].ptr >> 24; + } + return 0xff; +} + +static int sff_bus_master_data_read(int channel, uint8_t *data, int size, void *p) +{ + sff_busmaster_t *busmaster = (sff_busmaster_t *)p; + int transferred = 0; + + if (!(busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + while (transferred < size) + { + if (busmaster[channel].count < (size - transferred) && busmaster[channel].eot) + fatal("DMA on channel %i - Read count less than size! Addr %08X Count %04X EOT %i size %i\n", channel, busmaster[channel].addr, busmaster[channel].count, busmaster[channel].eot, size); + + mem_invalidate_range(busmaster[channel].addr, busmaster[channel].addr+(size-1)); + + if (busmaster[channel].count < (size - transferred)) + { +// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); + if (busmaster[channel].addr < (mem_size * 1024)) + { + int count = busmaster[channel].count; + if ((busmaster[channel].addr + count) > (mem_size * 1024)) + count = (mem_size * 1024) - busmaster[channel].addr; + memcpy(&ram[busmaster[channel].addr], data + transferred, count); + } + transferred += busmaster[channel].count; + busmaster[channel].addr += busmaster[channel].count; + busmaster[channel].count = 0; + } + else + { +// pclog("Transferring larger - %i bytes\n", size - transferred); + if (busmaster[channel].addr < (mem_size * 1024)) + { + int count = size - transferred; + if ((busmaster[channel].addr + count) > (mem_size * 1024)) + count = (mem_size * 1024) - busmaster[channel].addr; + memcpy(&ram[busmaster[channel].addr], data + transferred, count); + } + busmaster[channel].addr += (size - transferred); + busmaster[channel].count -= (size - transferred); + transferred += (size - 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 (!busmaster[channel].count) + { +// pclog("DMA on channel %i - block over\n", channel); + if (busmaster[channel].eot) /*End of transfer?*/ + { +// pclog("DMA on channel %i - transfer over\n", channel); + busmaster[channel].status &= ~1; + } + else + sff_bus_master_next_addr(busmaster, channel); + } + } + return 0; +} +static int sff_bus_master_data_write(int channel, uint8_t *data, int size, void *p) +{ + sff_busmaster_t *busmaster = (sff_busmaster_t *)p; + int transferred = 0; + + if (!(busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + while (transferred < size) + { + if (busmaster[channel].count < (size - transferred) && busmaster[channel].eot) + fatal("DMA on channel %i - Write count less than size! Addr %08X Count %04X EOT %i size %i\n", channel, busmaster[channel].addr, busmaster[channel].count, busmaster[channel].eot, size); + + if (busmaster[channel].count < (size - transferred)) + { +// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); + if (busmaster[channel].addr < (mem_size * 1024)) + { + int count = busmaster[channel].count; + if ((busmaster[channel].addr + count) > (mem_size * 1024)) + count = (mem_size * 1024) - busmaster[channel].addr; + memcpy(data + transferred, &ram[busmaster[channel].addr], count); + } + transferred += busmaster[channel].count; + busmaster[channel].addr += busmaster[channel].count; + busmaster[channel].count = 0; + } + else + { +// pclog("Transferring larger - %i bytes\n", size - transferred); + if (busmaster[channel].addr < (mem_size * 1024)) + { + int count = size - transferred; + if ((busmaster[channel].addr + count) > (mem_size * 1024)) + count = (mem_size * 1024) - busmaster[channel].addr; + memcpy(data + transferred, &ram[busmaster[channel].addr], count); + } + busmaster[channel].addr += (size - transferred); + busmaster[channel].count -= (size - transferred); + transferred += (size - 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 (!busmaster[channel].count) + { +// pclog("DMA on channel %i - block over\n", channel); + if (busmaster[channel].eot) /*End of transfer?*/ + { +// pclog("DMA on channel %i - transfer over\n", channel); + busmaster[channel].status &= ~1; + } + else + sff_bus_master_next_addr(busmaster, channel); + } + } + return 0; +} + +static void sff_bus_master_set_irq(int channel, void *p) +{ + sff_busmaster_t *busmaster = (sff_busmaster_t *)p; + + busmaster[channel].status |= 4; +} + +void sff_bus_master_init(sff_busmaster_t *busmaster) +{ + ide_set_bus_master(sff_bus_master_data_read, sff_bus_master_data_write, sff_bus_master_set_irq, busmaster); +} diff --git a/src/ide_sff8038i.h b/src/ide_sff8038i.h new file mode 100644 index 0000000..9ade5ad --- /dev/null +++ b/src/ide_sff8038i.h @@ -0,0 +1,13 @@ +typedef struct sff_busmaster_t +{ + uint8_t command; + uint8_t status; + uint32_t ptr, ptr_cur; + int count; + uint32_t addr; + int eot; +} sff_busmaster_t; + +uint8_t sff_bus_master_read(uint16_t port, void *p); +void sff_bus_master_write(uint16_t port, uint8_t val, void *p); +void sff_bus_master_init(sff_busmaster_t *busmaster); diff --git a/src/intel.c b/src/intel.c index 67d06f4..3d66644 100644 --- a/src/intel.c +++ b/src/intel.c @@ -2,11 +2,15 @@ #include "cpu.h" #include "io.h" #include "mem.h" +#include "model.h" #include "pit.h" #include "timer.h" +#include "x86.h" #include "intel.h" +static uint8_t batman_port_92; + uint8_t batman_brdconfig(uint16_t port, void *p) { // pclog("batman_brdconfig read port=%04x\n", port); @@ -16,15 +20,36 @@ uint8_t batman_brdconfig(uint16_t port, void *p) return 0xff; case 0x75: return 0xdf; + case 0x92: + return batman_port_92; } return 0; } +void batman_brdconfig_write(uint16_t port, uint8_t val, void *p) +{ + switch (port) + { + case 0x92: + if ((mem_a20_alt ^ val) & 2) + { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~batman_port_92 & val) & 1) + { + softresetx86(); + cpu_set_edx(); + } + batman_port_92 = val; + } +} + static uint16_t batman_timer_latch; -static int batman_timer = 0; +static pc_timer_t batman_timer; + static void batman_timer_over(void *p) { - batman_timer = 0; } static void batman_timer_write(uint16_t addr, uint8_t val, void *p) @@ -33,21 +58,16 @@ static void batman_timer_write(uint16_t addr, uint8_t val, void *p) 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; + timer_set_delay_u64(&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; + cycles -= (int)(PITCONST >> 32); - timer_clock(); - - if (batman_timer < 0) - return 0; - - batman_timer_latch = batman_timer / TIMER_USEC; + batman_timer_latch = timer_get_remaining_us(&batman_timer); if (addr & 1) return batman_timer_latch >> 8; @@ -60,17 +80,54 @@ void intel_batman_init() 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); + io_sethandler(0x0092, 0x0001, batman_brdconfig, NULL, NULL, batman_brdconfig_write, NULL, NULL, NULL); + batman_port_92 = 0; + timer_add(&batman_timer, batman_timer_over, NULL, 0); } uint8_t endeavor_brdconfig(uint16_t port, void *p) { + uint8_t temp; + CPU *cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu]; // pclog("endeavor_brdconfig read port=%04x\n", port); switch (port) { case 0x79: - return 0xff; + // Bit # | Description | Bit = 1 | Bit = 0 + // 0 | Internal CPU Clock Freq. (Switch 6) | 3/2x | 2x (Manual has these swapped in one place?) + // 1 | Soft Off capable power supply | No | Yes + // 2 | On-board Audio present | Yes | No + // 3 | External CPU clock (Switch 7) | | + // 4 | External CPU clock (Switch 8) | | + // 5 | Setup Disable (Switch 5) | Enable access | Disable access + // 6 | Clear CMOS (Switch 4) | Keep values | Clear values + // 7 | Password Clear (Switch 3) | Keep password | Clear password + + // Bus Speed | Switch 7 | Switch 8 + // 50 MHz | Off | Off + // 60 Mhz | On | Off + // 66 MHz | Off | On + + // Multiplier for each supported processor- + // -The 3/2 setting is used for 75 MHz, 90 MHz, and 100 MHz processors + // -The 2 times setting is used for 120 MHz processors. + + if (cpu_s->rspeed == 75000000 && cpu_s->pci_speed == 25000000) + temp = 0x01; + else if (cpu_s->rspeed == 90000000 && cpu_s->pci_speed == 30000000) + temp = 0x01 | 0x08; + else if (cpu_s->rspeed == 100000000 && cpu_s->pci_speed == 25000000) + temp = 0x00; + else if (cpu_s->rspeed == 100000000 && cpu_s->pci_speed == 33333333) + temp = 0x01 | 0x10; + else if (cpu_s->rspeed == 120000000 && cpu_s->pci_speed == 30000000) + temp = 0x08; + else if (cpu_s->rspeed == 133333333 && cpu_s->pci_speed == 33333333) + temp = 0x10; + else + temp = 0x10; // TODO: how are the overdrive processors configured? + return 0xe0 | temp; } return 0; } @@ -79,3 +136,54 @@ void intel_endeavor_init() { io_sethandler(0x0079, 0x0001, endeavor_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); } + +static uint8_t zappa_brdconfig(uint16_t port, void *p) +{ + uint8_t temp; + CPU *cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu]; +// pclog("zappa_brdconfig read port=%04x\n", port); + switch (port) + { + case 0x79: + // Bit # | Description | Bit = 1 | Bit = 0 + // 0 | Internal CPU Clock Freq. (Switch 6) | 3/2x | 2x (Manual has these swapped in one place?) + // 1 | No Connect | | + // 2 | No Connect | | + // 3 | External CPU clock (Switch 7) | | + // 4 | External CPU clock (Switch 8) | | + // 5 | Setup Disable (Switch 5) | Enable access | Disable access + // 6 | Clear CMOS (Switch 4) | Keep values | Clear values + // 7 | Password Clear (Switch 3) | Keep password | Clear password + + // Bus Speed | Switch 7 | Switch 8 + // 50 MHz | Off | Off + // 60 Mhz | On | Off + // 66 MHz | Off | On + + // Multiplier for each supported processor- + // -The 3/2 setting is used for 75 MHz, 90 MHz, and 100 MHz processors + // -The 2 times setting is used for 120 MHz processors. + + if (cpu_s->rspeed == 75000000 && cpu_s->pci_speed == 25000000) + temp = 0x01; + else if (cpu_s->rspeed == 90000000 && cpu_s->pci_speed == 30000000) + temp = 0x01 | 0x08; + else if (cpu_s->rspeed == 100000000 && cpu_s->pci_speed == 25000000) + temp = 0x00; + else if (cpu_s->rspeed == 100000000 && cpu_s->pci_speed == 33333333) + temp = 0x01 | 0x10; + else if (cpu_s->rspeed == 120000000 && cpu_s->pci_speed == 30000000) + temp = 0x08; + else if (cpu_s->rspeed == 133333333 && cpu_s->pci_speed == 33333333) + temp = 0x10; + else + temp = 0x10; // TODO: how are the overdrive processors configured? + return 0xe0 | temp; + } + return 0; +} + +void intel_zappa_init() +{ + io_sethandler(0x0079, 0x0001, zappa_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); +} diff --git a/src/intel.h b/src/intel.h index eccd668..4e14ddc 100644 --- a/src/intel.h +++ b/src/intel.h @@ -1,2 +1,3 @@ void intel_batman_init(); void intel_endeavor_init(); +void intel_zappa_init(); diff --git a/src/intel_flash.c b/src/intel_flash.c index 304e873..91ea964 100644 --- a/src/intel_flash.c +++ b/src/intel_flash.c @@ -3,6 +3,7 @@ #include "device.h" #include "mem.h" +#define FLASH_2MBIT 4 #define FLASH_IS_BXB 2 #define FLASH_INVERT 1 @@ -10,6 +11,7 @@ #define BLOCK_DATA1 1 #define BLOCK_DATA2 2 #define BLOCK_BOOT 3 +#define BLOCK_MAIN2 4 /*2Mbit devices only*/ enum { @@ -26,11 +28,13 @@ enum typedef struct flash_t { uint8_t command, status; - uint8_t flash_id; + uint16_t flash_id; + uint8_t type; int invert_high_pin; - mem_mapping_t mapping[8], mapping_h[8]; - uint32_t block_start[4], block_end[4], block_len[4]; - uint8_t array[131072]; + mem_mapping_t mapping[8], mapping_h[10]; + uint32_t block_start[5], block_end[5], block_len[5]; + uint8_t array[256*1024]; + uint32_t addr_mask; } flash_t; static char flash_path[1024]; @@ -39,13 +43,9 @@ static uint8_t flash_read(uint32_t addr, void *p) { flash_t *flash = (flash_t *)p; if (flash->invert_high_pin) - { - // pclog("flash_read : addr=%08x/%08x val=%02x command=%02x %04x:%08x\n", addr, addr ^ 0x10000, flash->array[(addr ^ 0x10000) & 0x1ffff], flash->command, CS, cpu_state.pc); addr ^= 0x10000; - if (addr & 0xfff00000) return flash->array[addr & 0x1ffff]; - } // pclog("flash_read : addr=%08x command=%02x %04x:%08x\n", addr, flash->command, CS, cpu_state.pc); - addr &= 0x1ffff; + addr &= flash->addr_mask; switch (flash->command) { case CMD_READ_ARRAY: @@ -65,15 +65,26 @@ static uint8_t flash_read(uint32_t addr, void *p) static uint16_t flash_readw(uint32_t addr, void *p) { flash_t *flash = (flash_t *)p; - addr &= 0x1ffff; + addr &= flash->addr_mask; if (flash->invert_high_pin) addr ^= 0x10000; - return *(uint16_t *)&(flash->array[addr]); + switch (flash->command) + { + case CMD_READ_ARRAY: + default: + return *(uint16_t *)&(flash->array[addr]); + + case CMD_IID: + return 0x89 | (flash->flash_id << 8); + + case CMD_READ_STATUS: + return flash->status; + } } static uint32_t flash_readl(uint32_t addr, void *p) { flash_t *flash = (flash_t *)p; - addr &= 0x1ffff; + addr &= flash->addr_mask; if (flash->invert_high_pin) addr ^= 0x10000; return *(uint32_t *)&(flash->array[addr]); } @@ -82,14 +93,11 @@ 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, cpu_state.pc); +// pclog("flash_write : addr=%08x val=%02x command=%02x %04x:%08x\n", addr, val, flash->command, CS, cpu_state.pc); if (flash->invert_high_pin) - { addr ^= 0x10000; - if (addr & 0xfff00000) return; - } - addr &= 0x1ffff; + addr &= flash->addr_mask; switch (flash->command) { @@ -111,7 +119,7 @@ static void flash_write(uint32_t addr, uint8_t val, void *p) case CMD_PROGRAM_SETUP: // pclog("flash_write: program %05x %02x\n", addr, val); - if ((addr & 0x1e000) != (flash->block_start[3] & 0x1e000)) + if ((addr & 0x3e000) != (flash->block_start[3] & 0x3e000)) flash->array[addr] = val; flash->command = CMD_READ_STATUS; flash->status = 0x80; @@ -134,9 +142,23 @@ static void intel_flash_add_mappings(flash_t *flash) for (i = 0; i <= 7; i++) { - mem_mapping_add(&(flash->mapping[i]), 0xe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + ((i << 14) & 0x1ffff), MEM_MAPPING_EXTERNAL, (void *)flash); - mem_mapping_add(&(flash->mapping_h[i]), 0xfffe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + ((i << 14) & 0x1ffff), 0, (void *)flash); + mem_mapping_add(&(flash->mapping[i]), 0xe0000 + (i << 14), 0x04000, + flash_read, flash_readw, flash_readl, + flash_write, mem_write_nullw, mem_write_nulll, + flash->array + (((i << 14) + 0x20000) & flash->addr_mask), MEM_MAPPING_EXTERNAL, (void *)flash); + mem_mapping_add(&(flash->mapping_h[i]), 0xfffe0000 + (i << 14), 0x04000, + flash_read, flash_readw, flash_readl, + flash_write, mem_write_nullw, mem_write_nulll, + flash->array + (((i << 14) + 0x20000) & flash->addr_mask), 0, (void *)flash); } + + if (flash->type & FLASH_2MBIT) + { + mem_mapping_add(&flash->mapping_h[8], 0xfffc0000, 0x20000, + flash_read, flash_readw, flash_readl, + flash_write, mem_write_nullw, mem_write_nulll, + flash->array, 0, (void *)flash); + } } /* This is for boards which invert the high pin - the flash->array pointers need to pointer invertedly in order for INTERNAL writes to go to the right part of the array. */ @@ -146,66 +168,156 @@ static void intel_flash_add_mappings_inverted(flash_t *flash) for (i = 0; i <= 7; i++) { - mem_mapping_add(&(flash->mapping[i]), 0xe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + (((i << 14) ^ 0x10000) & 0x1ffff), MEM_MAPPING_EXTERNAL, (void *)flash); - mem_mapping_add(&(flash->mapping_h[i]), 0xfffe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + (((i << 14) ^ 0x10000) & 0x1ffff), 0, (void *)flash); + mem_mapping_add(&(flash->mapping[i]), 0xe0000 + (i << 14), 0x04000, + flash_read, flash_readw, flash_readl, + flash_write, mem_write_nullw, mem_write_nulll, + flash->array + ((((i << 14) ^ 0x10000) + 0x20000) & flash->addr_mask), MEM_MAPPING_EXTERNAL, (void *)flash); + mem_mapping_add(&(flash->mapping_h[i]), 0xfffe0000 + (i << 14), 0x04000, + flash_read, flash_readw, flash_readl, + flash_write, mem_write_nullw, mem_write_nulll, + flash->array + ((((i << 14) ^ 0x10000) + 0x20000) & flash->addr_mask), 0, (void *)flash); } + + if (flash->type & FLASH_2MBIT) + { + mem_mapping_add(&flash->mapping_h[8], 0xfffc0000, 0x10000, + flash_read, flash_readw, flash_readl, + flash_write, mem_write_nullw, mem_write_nulll, + flash->array + 0x10000, 0, (void *)flash); + mem_mapping_add(&flash->mapping_h[9], 0xfffd0000, 0x10000, + flash_read, flash_readw, flash_readl, + flash_write, mem_write_nullw, mem_write_nulll, + flash->array, 0, (void *)flash); + } } -void *intel_flash_init(uint8_t type) +void *intel_flash_init(uint8_t type, uint8_t flash_id) { FILE *f; flash_t *flash = malloc(sizeof(flash_t)); memset(flash, 0, sizeof(flash_t)); char fpath[1024]; int i; + + flash->type = type; switch(romset) { case ROM_REVENGE: - strcpy(flash_path, "roms/revenge/"); + strcpy(flash_path, "revenge/"); + break; + case ROM_PB520R: + strcpy(flash_path, "pb520r/"); break; case ROM_ENDEAVOR: - strcpy(flash_path, "roms/endeavor/"); + strcpy(flash_path, "endeavor/"); + break; + case ROM_PB570: + strcpy(flash_path, "pb570/"); + break; + case ROM_ZAPPA: + strcpy(flash_path, "zappa/"); + break; + case ROM_P55VA: + strcpy(flash_path, "p55va/"); + break; + case ROM_P55TVP4: + strcpy(flash_path, "p55tvp4/"); break; case ROM_430VX: - strcpy(flash_path, "roms/430vx/"); + strcpy(flash_path, "430vx/"); break; + case ROM_P55T2P4: + strcpy(flash_path, "p55t2p4/"); + break; + case ROM_ITAUTEC_INFOWAYM: + strcpy(flash_path, "infowaym/"); + break; + case ROM_VS440FX: + strcpy(flash_path, "vs440fx/"); + break; + case ROM_GA686BX: + strcpy(flash_path, "ga686bx/"); + break; + default: fatal("intel_flash_init on unsupported ROM set %i\n", romset); } // pclog("Flash init: Path is: %s\n", flash_path); - flash->flash_id = (type & FLASH_IS_BXB) ? 0x95 : 0x94; + flash->flash_id = flash_id; + + flash->addr_mask = (type & FLASH_2MBIT) ? 0x3ffff : 0x1ffff; + +// flash->flash_id = (type & FLASH_IS_BXB) ? 0x95 : 0x94; flash->invert_high_pin = (type & FLASH_INVERT); - /* The block lengths are the same both flash types. */ - flash->block_len[BLOCK_MAIN] = 0x1c000; - flash->block_len[BLOCK_DATA1] = 0x01000; - flash->block_len[BLOCK_DATA2] = 0x01000; - flash->block_len[BLOCK_BOOT] = 0x02000; + if (type & FLASH_2MBIT) + { + flash->block_len[BLOCK_MAIN] = 0x20000; + flash->block_len[BLOCK_MAIN2] = 0x18000; + flash->block_len[BLOCK_DATA1] = 0x02000; + flash->block_len[BLOCK_DATA2] = 0x02000; + flash->block_len[BLOCK_BOOT] = 0x04000; - if (type & FLASH_IS_BXB) /* 28F001BX-B */ - { - flash->block_start[BLOCK_MAIN] = 0x04000; /* MAIN BLOCK */ - flash->block_end[BLOCK_MAIN] = 0x1ffff; - flash->block_start[BLOCK_DATA1] = 0x03000; /* DATA AREA 1 BLOCK */ - flash->block_end[BLOCK_DATA1] = 0x03fff; - flash->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ - flash->block_end[BLOCK_DATA2] = 0x04fff; - flash->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ - flash->block_end[BLOCK_BOOT] = 0x01fff; - } - else /* 28F001BX-T */ - { - flash->block_start[BLOCK_MAIN] = 0x00000; /* MAIN BLOCK */ - flash->block_end[BLOCK_MAIN] = 0x1bfff; - flash->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ - flash->block_end[BLOCK_DATA1] = 0x1cfff; - flash->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ - flash->block_end[BLOCK_DATA2] = 0x1dfff; - flash->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ - flash->block_end[BLOCK_BOOT] = 0x1ffff; - } + if (type & FLASH_IS_BXB) /* 28F001BX-B */ + { + flash->block_start[BLOCK_MAIN] = 0x20000; /* MAIN BLOCK */ + flash->block_end[BLOCK_MAIN] = 0x3ffff; + flash->block_start[BLOCK_MAIN2] = 0x08000; /* MAIN BLOCK */ + flash->block_end[BLOCK_MAIN2] = 0x1ffff; + flash->block_start[BLOCK_DATA1] = 0x04000; /* DATA AREA 1 BLOCK */ + flash->block_end[BLOCK_DATA1] = 0x05fff; + flash->block_start[BLOCK_DATA2] = 0x06000; /* DATA AREA 2 BLOCK */ + flash->block_end[BLOCK_DATA2] = 0x07fff; + flash->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + flash->block_end[BLOCK_BOOT] = 0x03fff; + } + else /* 28F001BX-T */ + { + flash->block_start[BLOCK_MAIN] = 0x00000; /* MAIN BLOCK */ + flash->block_end[BLOCK_MAIN] = 0x1ffff; + flash->block_start[BLOCK_MAIN2] = 0x20000; /* MAIN BLOCK */ + flash->block_end[BLOCK_MAIN2] = 0x37fff; + flash->block_start[BLOCK_DATA1] = 0x38000; /* DATA AREA 1 BLOCK */ + flash->block_end[BLOCK_DATA1] = 0x39fff; + flash->block_start[BLOCK_DATA2] = 0x3a000; /* DATA AREA 2 BLOCK */ + flash->block_end[BLOCK_DATA2] = 0x3bfff; + flash->block_start[BLOCK_BOOT] = 0x3c000; /* BOOT BLOCK */ + flash->block_end[BLOCK_BOOT] = 0x3ffff; + } + } + else + { + /* The block lengths are the same both flash types. */ + flash->block_len[BLOCK_MAIN] = 0x1c000; + flash->block_len[BLOCK_DATA1] = 0x01000; + flash->block_len[BLOCK_DATA2] = 0x01000; + flash->block_len[BLOCK_BOOT] = 0x02000; + + if (type & FLASH_IS_BXB) /* 28F001BX-B */ + { + flash->block_start[BLOCK_MAIN] = 0x04000; /* MAIN BLOCK */ + flash->block_end[BLOCK_MAIN] = 0x1ffff; + flash->block_start[BLOCK_DATA1] = 0x03000; /* DATA AREA 1 BLOCK */ + flash->block_end[BLOCK_DATA1] = 0x03fff; + flash->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ + flash->block_end[BLOCK_DATA2] = 0x04fff; + flash->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + flash->block_end[BLOCK_BOOT] = 0x01fff; + } + else /* 28F001BX-T */ + { + flash->block_start[BLOCK_MAIN] = 0x00000; /* MAIN BLOCK */ + flash->block_end[BLOCK_MAIN] = 0x1bfff; + flash->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ + flash->block_end[BLOCK_DATA1] = 0x1cfff; + flash->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ + flash->block_end[BLOCK_DATA2] = 0x1dfff; + flash->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ + flash->block_end[BLOCK_BOOT] = 0x1ffff; + } + } for (i = 0; i < 8; i++) { @@ -217,10 +329,17 @@ void *intel_flash_init(uint8_t type) { memcpy(flash->array, rom + 65536, 65536); memcpy(flash->array + 65536, rom, 65536); + if (type & FLASH_2MBIT) + { + memcpy(flash->array + 0x20000, rom + 0x30000, 65536); + memcpy(flash->array + 0x30000, rom + 0x20000, 65536); + } } else { memcpy(flash->array, rom, 131072); + if (type & FLASH_2MBIT) + memcpy(flash->array + 0x20000, rom + 0x20000, 131072); } if (flash->invert_high_pin) @@ -241,7 +360,9 @@ void *intel_flash_init(uint8_t type) if (f) { fread(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); - fread(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); + if (type & FLASH_2MBIT) + fread(&(flash->array[flash->block_start[BLOCK_MAIN2]]), flash->block_len[BLOCK_MAIN2], 1, f); + fread(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); fread(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); fclose(f); } @@ -252,19 +373,29 @@ void *intel_flash_init(uint8_t type) /* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */ void *intel_flash_bxt_ami_init() { - return intel_flash_init(FLASH_INVERT); + return intel_flash_init(FLASH_INVERT, 0x94); } /* For Award BIOS'es - Intel 28F001BXT with high address pin not inverted. */ void *intel_flash_bxt_init() { - return intel_flash_init(0); + return intel_flash_init(0, 0x94); } /* For Acer BIOS'es - Intel 28F001BXB. */ void *intel_flash_bxb_init() { - return intel_flash_init(FLASH_IS_BXB); + return intel_flash_init(FLASH_IS_BXB, 0x95); +} + +static void *intel_flash_28fb200bxt_init(void) +{ + return intel_flash_init(FLASH_INVERT | FLASH_2MBIT, 0x74); +} + +static void *intel_flash_28f002bc_init(void) +{ + return intel_flash_init(FLASH_INVERT | FLASH_2MBIT, 0x7c); } void intel_flash_close(void *p) @@ -278,6 +409,8 @@ void intel_flash_close(void *p) strcat(fpath, "flash.bin"); f = romfopen(fpath, "wb"); fwrite(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); + if (flash->type & FLASH_2MBIT) + fwrite(&(flash->array[flash->block_start[BLOCK_MAIN2]]), flash->block_len[BLOCK_MAIN2], 1, f); fwrite(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); fwrite(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); fclose(f); @@ -323,3 +456,29 @@ device_t intel_flash_bxb_device = NULL, NULL }; + +device_t intel_flash_28fb200bxt_device = +{ + "Intel 28FB200BX-T Flash BIOS", + 0, + intel_flash_28fb200bxt_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +device_t intel_flash_28f002bc_device = +{ + "Intel 28F002BC Flash BIOS", + 0, + intel_flash_28f002bc_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/intel_flash.h b/src/intel_flash.h index 2b4cb14..2ea4db5 100644 --- a/src/intel_flash.h +++ b/src/intel_flash.h @@ -1,3 +1,5 @@ extern device_t intel_flash_bxt_ami_device; extern device_t intel_flash_bxt_device; extern device_t intel_flash_bxb_device; +extern device_t intel_flash_28fb200bxt_device; +extern device_t intel_flash_28f002bc_device; diff --git a/src/io.c b/src/io.c index 318575c..ea94c67 100644 --- a/src/io.c +++ b/src/io.c @@ -1,4 +1,5 @@ #include "ibm.h" +#include "amstrad.h" #include "ide.h" #include "io.h" #include "video.h" @@ -86,36 +87,28 @@ void io_removehandler(uint16_t base, int size, int c; for (c = 0; c < size; c++) { - if (port_priv[base + c][0] == priv) + if (port_priv[base + c][0] == priv && + 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) { - 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; + port_inb[ base + c][0] = NULL; + port_inw[ base + c][0] = NULL; + port_inl[ base + c][0] = NULL; + port_outb[ base + c][0] = NULL; + port_outw[ base + c][0] = NULL; + port_outl[ base + c][0] = NULL; port_priv[base + c][0] = NULL; } - if (port_priv[base + c][1] == priv) + if (port_priv[base + c][1] == priv && + 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) { - 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; + port_inb[ base + c][1] = NULL; + port_inw[ base + c][1] = NULL; + port_inl[ base + c][1] = NULL; + port_outb[base + c][1] = NULL; + port_outw[base + c][1] = NULL; + port_outl[base + c][1] = NULL; port_priv[base + c][1] = NULL; } } @@ -135,6 +128,13 @@ uint8_t inb(uint16_t port) if (port_inb[port][1]) temp &= port_inb[port][1](port, port_priv[port][1]); + if (port & 0x80) + amstrad_latch = AMSTRAD_NOLATCH; + else if (port & 0x4000) + amstrad_latch = AMSTRAD_SW10; + else + amstrad_latch = AMSTRAD_SW9; + /* if (!port_inb[port][0] && !port_inb[port][1]) pclog("Bad INB %04X %04X:%04X\n", port, CS, pc);*/ diff --git a/src/joystick_sw_pad.c b/src/joystick_sw_pad.c index c0d0e8b..9bc64dc 100644 --- a/src/joystick_sw_pad.c +++ b/src/joystick_sw_pad.c @@ -4,7 +4,7 @@ - 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 + - Packet preceeded by high data (currently 40us), 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 @@ -30,13 +30,13 @@ typedef struct { - int poll_time; + pc_timer_t poll_timer; int poll_left; int poll_clock; uint64_t poll_data; int poll_mode; - int trigger_time; + pc_timer_t trigger_timer; int data_mode; } sw_data; @@ -44,33 +44,22 @@ 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; + 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_clock) + { + sw->poll_data >>= (sw->poll_mode ? 3 : 1); + sw->poll_left--; } - - if (!sw->poll_left) - sw->poll_time = 0; + + if (sw->poll_left == 1 && !sw->poll_clock) + timer_advance_u64(&sw->poll_timer, TIMER_USEC * 160); + else if (sw->poll_left) + timer_set_delay_u64(&sw->poll_timer, TIMER_USEC * 5); } 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) @@ -91,8 +80,8 @@ 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); + timer_add(&sw->poll_timer, sw_timer_over, sw, 0); + timer_add(&sw->trigger_timer, sw_trigger_timer_over, sw, 0); return sw; } @@ -112,7 +101,7 @@ static uint8_t sw_read(void *p) if (!JOYSTICK_PRESENT(0)) return 0xff; - if (sw->poll_time) + if (timer_is_enabled(&sw->poll_timer)) { if (sw->poll_clock) temp |= 0x10; @@ -135,17 +124,15 @@ static uint8_t sw_read(void *p) static void sw_write(void *p) { sw_data *sw = (sw_data *)p; - int time_since_last = sw->trigger_time / TIMER_USEC; + int time_since_last = timer_get_remaining_us(&sw->trigger_timer); if (!JOYSTICK_PRESENT(0)) return; - timer_process(); - if (!sw->poll_left) { sw->poll_clock = 1; - sw->poll_time = TIMER_USEC * 50; + timer_set_delay_u64(&sw->poll_timer, TIMER_USEC * 40); if (time_since_last > 9900 && time_since_last < 9940) { @@ -213,10 +200,8 @@ static void sw_write(void *p) } } } - - sw->trigger_time = 0; - - timer_update_outstanding(); + + timer_disable(&sw->trigger_timer); } static int sw_read_axis(void *p, int axis) @@ -231,7 +216,7 @@ static void sw_a0_over(void *p) { sw_data *sw = (sw_data *)p; - sw->trigger_time = TIMER_USEC * 10000; + timer_set_delay_u64(&sw->trigger_timer, TIMER_USEC * 10000); } joystick_if_t joystick_sw_pad = diff --git a/src/keyboard.c b/src/keyboard.c index 2d3135f..f41d59f 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -6,243 +6,413 @@ int keybsendcallback = 0; typedef struct { - int scancodes_make[8]; - int scancodes_break[8]; + uint8_t scancodes_make[8]; + uint8_t scancodes_break[8]; } 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} }, + { {0}, {0} }, { {0x01, 0}, {0x81, 0} }, { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} }, + { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} }, + { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} }, + { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} }, + { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} }, + { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} }, + { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} }, + { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} }, + { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} }, + { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} }, + { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, { {0x2a, 0}, {0xaa, 0} }, { {0x2b, 0}, {0xab, 0} }, + { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} }, + { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} }, + { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} }, + { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} }, + { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} }, + { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} }, + { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} }, + { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} }, + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, + { {0x54, 0}, {0xd4, 0} }, { {0x55, 0}, {0xd5, 0} }, { {0x56, 0}, {0xd6, 0} }, { {0x57, 0}, {0xd7, 0} }, + { {0x58, 0}, {0xd8, 0} }, { {0x59, 0}, {0xd9, 0} }, { {0x5a, 0}, {0xda, 0} }, { {0x5b, 0}, {0xdb, 0} }, + { {0x5c, 0}, {0xdc, 0} }, { {0x5d, 0}, {0xdd, 0} }, { {0x5e, 0}, {0xde, 0} }, { {0x5f, 0}, {0xdf, 0} }, + { {0x60, 0}, {0xe0, 0} }, { {0x61, 0}, {0xe1, 0} }, { {0x62, 0}, {0xe2, 0} }, { {0x63, 0}, {0xe3, 0} }, + { {0x64, 0}, {0xe4, 0} }, { {0x65, 0}, {0xe5, 0} }, { {0x66, 0}, {0xe6, 0} }, { {0x67, 0}, {0xe7, 0} }, + { {0x68, 0}, {0xe8, 0} }, { {0x69, 0}, {0xe9, 0} }, { {0x6a, 0}, {0xea, 0} }, { {0x6b, 0}, {0xeb, 0} }, + { {0x6c, 0}, {0xec, 0} }, { {0x6d, 0}, {0xed, 0} }, { {0x6e, 0}, {0xee, 0} }, { {0x6f, 0}, {0xef, 0} }, + { {0x70, 0}, {0xf0, 0} }, { {0x71, 0}, {0xf1, 0} }, { {0x72, 0}, {0xf2, 0} }, { {0x73, 0}, {0xf3, 0} }, + { {0x74, 0}, {0xf4, 0} }, { {0x75, 0}, {0xf5, 0} }, { {0x76, 0}, {0xf6, 0} }, { {0x77, 0}, {0xf7, 0} }, + { {0x78, 0}, {0xf8, 0} }, { {0x79, 0}, {0xf9, 0} }, { {0x7a, 0}, {0xfa, 0} }, { {0x7b, 0}, {0xfb, 0} }, + { {0x7c, 0}, {0xfc, 0} }, { {0x7d, 0}, {0xfd, 0} }, { {0x7e, 0}, {0xfe, 0} }, { {0x7f, 0}, {0xff, 0} }, - { {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} }, { {0xe0, 0x2a, -1}, {0xe0, 0xaa, -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} }, { {0xe0, 0x36, -1}, {0xe0, 0xb6, -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, 0x47, -1}, {0xe0, 0xc7, -1} }, /*c4*/ - { {0xe0, 0x48, -1}, {0xe0, 0xc8, -1} }, { {0xe0, 0x49, -1}, {0xe0, 0xc9, -1} }, { {-1}, {-1} }, { {0xe0, 0x4b, -1}, {0xe0, 0xcb, -1} }, /*c8*/ - { {0xe0, 0x4c, -1}, {0xe0, 0xcc, -1} }, { {0xe0, 0x4d, -1}, {0xe0, 0xcd, -1} }, { {0xe0, 0x4e, -1}, {0xe0, 0xce, -1} }, { {0xe0, 0x4f, -1}, {0xe0, 0xcf, -1} }, /*cc*/ - { {0xe0, 0x50, -1}, {0xe0, 0xd0, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xd1, -1} }, { {0xe0, 0x52, -1}, {0xe0, 0xd2, -1} }, { {0xe0, 0x53, -1}, {0xe0, 0xd3, -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, 0x45, 0xe1, 0x9d, 0xc5, -1}, {-1} }, /*fc*/ - { {-1}, {-1} }, { {0xe0, 0x01, -1}, {0xe0, 0x81, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0x82, -1} }, { {-1}, {-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*/ + { {0x80, 0}, {0} }, { {0x81, 0}, {0} }, { {0x82, 0}, {0} }, { {0xe0, 0x03, 0}, {0xe0, 0x83, 0} }, /*80*/ + { {0xe0, 0x04, 0}, {0xe0, 0x84, 0} }, { {0x85, 0}, {0} }, { {0x86, 0}, {0} }, { {0x87, 0}, {0} }, /*84*/ + { {0xe0, 0x08, 0}, {0xe0, 0x88, 0} }, { {0xe0, 0x09, 0}, {0xe0, 0x89, 0} }, { {0xe0, 0x0a, 0}, {0xe0, 0x8a, 0} }, { {0xe0, 0x0b, 0}, {0xe0, 0x8b, 0} }, /*88*/ + { {0xe0, 0x0c, 0}, {0xe0, 0x8c, 0} }, { {0}, {0} }, { {0xe0, 0x0e, 0}, {0xe0, 0x8e, 0} }, { {0xe0, 0x0f, 0}, {0xe0, 0x8f, 0} }, /*8c*/ + { {0xe0, 0x10, 0}, {0xe0, 0x90, 0} }, { {0xe0, 0x11, 0}, {0xe0, 0x91, 0} }, { {0xe0, 0x12, 0}, {0xe0, 0x92, 0} }, { {0xe0, 0x13, 0}, {0xe0, 0x93, 0} }, /*90*/ + { {0xe0, 0x14, 0}, {0xe0, 0x94, 0} }, { {0xe0, 0x15, 0}, {0xe0, 0x95, 0} }, { {0xe0, 0x16, 0}, {0xe0, 0x96, 0} }, { {0xe0, 0x17, 0}, {0xe0, 0x97, 0} }, /*94*/ + { {0xe0, 0x18, 0}, {0xe0, 0x98, 0} }, { {0xe0, 0x19, 0}, {0xe0, 0x99, 0} }, { {0xe0, 0x1a, 0}, {0xe0, 0x9a, 0} }, { {0xe0, 0x1b, 0}, {0xe0, 0x9b, 0} }, /*98*/ + { {0xe0, 0x1c, 0}, {0xe0, 0x9c, 0} }, { {0xe0, 0x1d, 0}, {0xe0, 0x9d, 0} }, { {0xe0, 0x1e, 0}, {0xe0, 0x9e, 0} }, { {0xe0, 0x1f, 0}, {0xe0, 0x9f, 0} }, /*9c*/ + { {0xe0, 0x20, 0}, {0xe0, 0xa0, 0} }, { {0xe0, 0x21, 0}, {0xe0, 0xa1, 0} }, { {0xe0, 0x22, 0}, {0xe0, 0xa2, 0} }, { {0xe0, 0x23, 0}, {0xe0, 0xa3, 0} }, /*a0*/ + { {0xe0, 0x24, 0}, {0xe0, 0xa4, 0} }, { {0xe0, 0x25, 0}, {0xe0, 0xa5, 0} }, { {0xe0, 0x26, 0}, {0xe0, 0xa6, 0} }, { {0}, {0} }, /*a4*/ + { {0}, {0} }, { {0}, {0} }, { {0xe0, 0x2a, 0}, {0xe0, 0xaa, 0} }, { {0}, {0} }, /*a8*/ + { {0xe0, 0x2c, 0}, {0xe0, 0xac, 0} }, { {0xe0, 0x2d, 0}, {0xe0, 0xad, 0} }, { {0xe0, 0x2e, 0}, {0xe0, 0xae, 0} }, { {0xe0, 0x2f, 0}, {0xe0, 0xaf, 0} }, /*ac*/ + { {0xe0, 0x30, 0}, {0xe0, 0xb0, 0} }, { {0xe0, 0x31, 0}, {0xe0, 0xb1, 0} }, { {0xe0, 0x32, 0}, {0xe0, 0xb2, 0} }, { {0}, {0} }, /*b0*/ + { {0xe0, 0x34, 0}, {0xe0, 0xb4, 0} }, { {0xe0, 0x35, 0}, {0xe0, 0xb5, 0} }, { {0xe0, 0x36, 0}, {0xe0, 0xb6, 0} }, { {0xe0, 0x37, 0}, {0xe0, 0xb7, 0} }, /*b4*/ + { {0xe0, 0x38, 0}, {0xe0, 0xb8, 0} }, { {0}, {0} }, { {0xe0, 0x3a, 0}, {0xe0, 0xba, 0} }, { {0xe0, 0x3b, 0}, {0xe0, 0xbb, 0} }, /*b8*/ + { {0xe0, 0x3c, 0}, {0xe0, 0xbc, 0} }, { {0xe0, 0x3d, 0}, {0xe0, 0xbd, 0} }, { {0xe0, 0x3e, 0}, {0xe0, 0xbe, 0} }, { {0xe0, 0x3f, 0}, {0xe0, 0xbf, 0} }, /*bc*/ + { {0xe0, 0x40, 0}, {0xe0, 0xc0, 0} }, { {0xe0, 0x41, 0}, {0xe0, 0xc1, 0} }, { {0xe0, 0x42, 0}, {0xe0, 0xc2, 0} }, { {0xe0, 0x43, 0}, {0xe0, 0xc3, 0} }, /*c0*/ + { {0xe0, 0x44, 0}, {0xe0, 0xc4, 0} }, { {0}, {0} }, { {0xe0, 0x46, 0}, {0xe0, 0xc6, 0} }, { {0xe0, 0x47, 0}, {0xe0, 0xc7, 0} }, /*c4*/ + { {0xe0, 0x48, 0}, {0xe0, 0xc8, 0} }, { {0xe0, 0x49, 0}, {0xe0, 0xc9, 0} }, { {0}, {0} }, { {0xe0, 0x4b, 0}, {0xe0, 0xcb, 0} }, /*c8*/ + { {0xe0, 0x4c, 0}, {0xe0, 0xcc, 0} }, { {0xe0, 0x4d, 0}, {0xe0, 0xcd, 0} }, { {0xe0, 0x4e, 0}, {0xe0, 0xce, 0} }, { {0xe0, 0x4f, 0}, {0xe0, 0xcf, 0} }, /*cc*/ + { {0xe0, 0x50, 0}, {0xe0, 0xd0, 0} }, { {0xe0, 0x51, 0}, {0xe0, 0xd1, 0} }, { {0xe0, 0x52, 0}, {0xe0, 0xd2, 0} }, { {0xe0, 0x53, 0}, {0xe0, 0xd3, 0} }, /*d0*/ + { {0xd4, 0}, {0} }, { {0xe0, 0x55, 0}, {0xe0, 0xd5, 0} }, { {0}, {0} }, { {0xe0, 0x57, 0}, {0xe0, 0xd7, 0} }, /*d4*/ + { {0xe0, 0x58, 0}, {0xe0, 0xd8, 0} }, { {0xe0, 0x59, 0}, {0xe0, 0xd9, 0} }, { {0xe0, 0x5a, 0}, {0xe0, 0xaa, 0} }, { {0xe0, 0x5b, 0}, {0xe0, 0xdb, 0} }, /*d8*/ + { {0xe0, 0x5c, 0}, {0xe0, 0xdc, 0} }, { {0xe0, 0x5d, 0}, {0xe0, 0xdd, 0} }, { {0xe0, 0x5e, 0}, {0xe0, 0xee, 0} }, { {0xe0, 0x5f, 0}, {0xe0, 0xdf, 0} }, /*dc*/ + { {0}, {0} }, { {0xe0, 0x61, 0}, {0xe0, 0xe1, 0} }, { {0xe0, 0x62, 0}, {0xe0, 0xe2, 0} }, { {0xe0, 0x63, 0}, {0xe0, 0xe3, 0} }, /*e0*/ + { {0xe0, 0x64, 0}, {0xe0, 0xe4, 0} }, { {0xe0, 0x65, 0}, {0xe0, 0xe5, 0} }, { {0xe0, 0x66, 0}, {0xe0, 0xe6, 0} }, { {0xe0, 0x67, 0}, {0xe0, 0xe7, 0} }, /*e4*/ + { {0xe0, 0x68, 0}, {0xe0, 0xe8, 0} }, { {0xe0, 0x69, 0}, {0xe0, 0xe9, 0} }, { {0xe0, 0x6a, 0}, {0xe0, 0xea, 0} }, { {0xe0, 0x6b, 0}, {0xe0, 0xeb, 0} }, /*e8*/ + { {0xe0, 0x6c, 0}, {0xe0, 0xec, 0} }, { {0xe0, 0x6d, 0}, {0xe0, 0xed, 0} }, { {0xe0, 0x6e, 0}, {0xe0, 0xee, 0} }, { {0}, {0} }, /*ec*/ + { {0xe0, 0x70, 0}, {0xe0, 0xf0, 0} }, { {0xf1, 0}, {0} }, { {0xf2, 0}, {0} }, { {0xe0, 0x73, 0}, {0xe0, 0xf3, 0} }, /*f0*/ + { {0xe0, 0x74, 0}, {0xe0, 0xf4, 0} }, { {0xe0, 0x75, 0}, {0xe0, 0xf5, 0} }, { {0}, {0} }, { {0xe0, 0x77, 0}, {0xe0, 0xf7, 0} }, /*f4*/ + { {0xe0, 0x78, 0}, {0xe0, 0xf8, 0} }, { {0xe0, 0x79, 0}, {0xe0, 0xf9, 0} }, { {0xe0, 0x7a, 0}, {0xe0, 0xfa, 0} }, { {0xe0, 0x7b, 0}, {0xe0, 0xfb, 0} }, /*f8*/ + { {0xe0, 0x7c, 0}, {0xe0, 0xfc, 0} }, { {0xe0, 0x7d, 0}, {0xe0, 0xfd, 0} }, { {0xe0, 0x7e, 0}, {0xe0, 0xfe, 0} }, { {0xe1, 0x1d, 0x45, 0xe1, 0x9d, 0xc5, 0}, {0} }, /*fc*/ + { {0}, {0} }, { {0xe0, 0x01, 0}, {0xe0, 0x81, 0} }, { {0xe0, 0x02, 0}, {0xe0, 0x82, 0} }, { {0}, {0} }, /*100*/ + { {0}, {0} }, { {0xe0, 0x05, 0}, {0xe0, 0x85, 0} }, { {0xe0, 0x06, 0}, {0xe0, 0x86, 0} }, { {0xe0, 0x07, 0}, {0xe0, 0x87, 0} }, /*104*/ + { {0xe0, 0x71, 0}, {0xe0, 0xf1, 0} }, { {0xe0, 0x72, 0}, {0xe0, 0xf2, 0} }, { {0xe0, 0x7f, 0}, {0xe0, 0xff, 0} }, { {0xe0, 0xe1, 0}, {0} }, /*108*/ + { {0xe0, 0xee, 0}, {0} }, { {0xe0, 0xf1, 0}, {0} }, { {0xe0, 0xfe, 0}, {0} }, { {0xe0, 0xff, 0}, {0} } /*10c*/ +}; + +/*272 = 256 + 16 fake interim scancodes for disambiguation purposes.*/ +static scancode scancode_set2[272] = +{ + { {0}, {0} }, { {0x76, 0}, {0xf0, 0x76, 0} }, { {0x16, 0}, {0xf0, 0x16, 0} }, { {0x1e, 0}, {0xf0, 0x1e, 0} }, + { {0x26, 0}, {0xf0, 0x26, 0} }, { {0x25, 0}, {0xf0, 0x25, 0} }, { {0x2e, 0}, {0xf0, 0x2e, 0} }, { {0x36, 0}, {0xf0, 0x36, 0} }, + { {0x3d, 0}, {0xf0, 0x3d, 0} }, { {0x3e, 0}, {0xf0, 0x3e, 0} }, { {0x46, 0}, {0xf0, 0x46, 0} }, { {0x45, 0}, {0xf0, 0x45, 0} }, + { {0x4e, 0}, {0xf0, 0x4e, 0} }, { {0x55, 0}, {0xf0, 0x55, 0} }, { {0x66, 0}, {0xf0, 0x66, 0} }, { {0x0d, 0}, {0xf0, 0x0d, 0} }, + { {0x15, 0}, {0xf0, 0x15, 0} }, { {0x1d, 0}, {0xf0, 0x1d, 0} }, { {0x24, 0}, {0xf0, 0x24, 0} }, { {0x2d, 0}, {0xf0, 0x2d, 0} }, + { {0x2c, 0}, {0xf0, 0x2c, 0} }, { {0x35, 0}, {0xf0, 0x35, 0} }, { {0x3c, 0}, {0xf0, 0x3c, 0} }, { {0x43, 0}, {0xf0, 0x43, 0} }, + { {0x44, 0}, {0xf0, 0x44, 0} }, { {0x4d, 0}, {0xf0, 0x4d, 0} }, { {0x54, 0}, {0xf0, 0x54, 0} }, { {0x5b, 0}, {0xf0, 0x5b, 0} }, + { {0x5a, 0}, {0xf0, 0x5a, 0} }, { {0x14, 0}, {0xf0, 0x14, 0} }, { {0x1c, 0}, {0xf0, 0x1c, 0} }, { {0x1b, 0}, {0xf0, 0x1b, 0} }, + { {0x23, 0}, {0xf0, 0x23, 0} }, { {0x2b, 0}, {0xf0, 0x2b, 0} }, { {0x34, 0}, {0xf0, 0x34, 0} }, { {0x33, 0}, {0xf0, 0x33, 0} }, + { {0x3b, 0}, {0xf0, 0x3b, 0} }, { {0x42, 0}, {0xf0, 0x42, 0} }, { {0x4b, 0}, {0xf0, 0x4b, 0} }, { {0x4c, 0}, {0xf0, 0x4c, 0} }, + { {0x52, 0}, {0xf0, 0x52, 0} }, { {0x0e, 0}, {0xf0, 0x0e, 0} }, { {0x12, 0}, {0xf0, 0x12, 0} }, { {0x5d, 0}, {0xf0, 0x5d, 0} }, + { {0x1a, 0}, {0xf0, 0x1a, 0} }, { {0x22, 0}, {0xf0, 0x22, 0} }, { {0x21, 0}, {0xf0, 0x21, 0} }, { {0x2a, 0}, {0xf0, 0x2a, 0} }, + { {0x32, 0}, {0xf0, 0x32, 0} }, { {0x31, 0}, {0xf0, 0x31, 0} }, { {0x3a, 0}, {0xf0, 0x3a, 0} }, { {0x41, 0}, {0xf0, 0x41, 0} }, + { {0x49, 0}, {0xf0, 0x49, 0} }, { {0x4a, 0}, {0xf0, 0x4a, 0} }, { {0x59, 0}, {0xf0, 0x59, 0} }, { {0x7c, 0}, {0xf0, 0x7c, 0} }, + { {0x11, 0}, {0xf0, 0x11, 0} }, { {0x29, 0}, {0xf0, 0x29, 0} }, { {0x58, 0}, {0xf0, 0x58, 0} }, { {0x05, 0}, {0xf0, 0x05, 0} }, + { {0x06, 0}, {0xf0, 0x06, 0} }, { {0x04, 0}, {0xf0, 0x04, 0} }, { {0x0c, 0}, {0xf0, 0x0c, 0} }, { {0x03, 0}, {0xf0, 0x03, 0} }, + { {0x0b, 0}, {0xf0, 0x0b, 0} }, { {0x83, 0}, {0xf0, 0x83, 0} }, { {0x0a, 0}, {0xf0, 0x0a, 0} }, { {0x01, 0}, {0xf0, 0x01, 0} }, + { {0x09, 0}, {0xf0, 0x09, 0} }, { {0x77, 0}, {0xf0, 0x77, 0} }, { {0x7e, 0}, {0xf0, 0x7e, 0} }, { {0x6c, 0}, {0xf0, 0x6c, 0} }, + { {0x75, 0}, {0xf0, 0x75, 0} }, { {0x7d, 0}, {0xf0, 0x7d, 0} }, { {0x7b, 0}, {0xf0, 0x7b, 0} }, { {0x6b, 0}, {0xf0, 0x6b, 0} }, + { {0x73, 0}, {0xf0, 0x73, 0} }, { {0x74, 0}, {0xf0, 0x74, 0} }, { {0x79, 0}, {0xf0, 0x79, 0} }, { {0x69, 0}, {0xf0, 0x69, 0} }, + { {0x72, 0}, {0xf0, 0x72, 0} }, { {0x7a, 0}, {0xf0, 0x7a, 0} }, { {0x70, 0}, {0xf0, 0x70, 0} }, { {0x71, 0}, {0xf0, 0x71, 0} }, + { {0x84, 0}, {0xf0, 0x84, 0} }, { {0, 0}, {0, 0} }, { {0x61, 0}, {0xf0, 0x61, 0} }, { {0x78, 0}, {0xf0, 0x78, 0} }, + { {0x07, 0}, {0xf0, 0x07, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0xe0, 0x5a, 0}, {0xe0, 0xf0, 0x5a, 0} }, { {0xe0, 0x14, 0}, {0xe0, 0xf0, 0x14, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0xe0, 0x4a, 0}, {0xe0, 0xf0, 0x4a, 0} }, { {0, 0}, {0, 0} }, { {0xe0, 0x7c, 0}, {0xe0, 0xf0, 0x7c, 0} }, + { {0xe0, 0x11, 0}, {0xe0, 0xf0, 0x11, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0xe0, 0x6c, 0}, {0xe0, 0xf0, 0x6c, 0} }, + { {0xe0, 0x75, 0}, {0xe0, 0xf0, 0x75, 0} }, { {0xe0, 0x7d, 0}, {0xe0, 0xf0, 0x7d, 0} }, { {0, 0}, {0, 0} }, { {0xe0, 0x6b, 0}, {0xe0, 0xf0, 0x6b, 0} }, + { {0, 0}, {0, 0} }, { {0xe0, 0x74, 0}, {0xe0, 0xf0, 0x74, 0} }, { {0, 0}, {0, 0} }, { {0xe0, 0x69, 0}, {0xe0, 0xf0, 0x69, 0} }, + { {0xe0, 0x72, 0}, {0xe0, 0xf0, 0x72, 0} }, { {0xe0, 0x7a, 0}, {0xe0, 0xf0, 0x7a, 0} }, { {0xe0, 0x70, 0}, {0xe0, 0xf0, 0x70, 0} }, { {0xe0, 0x71, 0}, {0xe0, 0xf0, 0x71, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0xe0, 0x1f, 0}, {0xe0, 0xf0, 0x1f, 0} }, + { {0xe0, 0x27, 0}, {0xe0, 0xf0, 0x27, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + + { {0}, {0} }, { {0xe0, 0x01, 0}, {0xe0, 0xf0, 0x01, 0} }, { {0xe0, 0x02, 0}, {0xe0, 0xf0, 0x02, 0} }, { {0}, {0} }, /*100*/ + { {0}, {0} }, { {0xe0, 0x05, 0}, {0xe0, 0xf0, 0x15, 0} }, { {0xe0, 0x06, 0}, {0xe0, 0xf0, 0x06, 0} }, { {0xe0, 0x07, 0}, {0xe0, 0xf0, 0x07, 0} }, /*104*/ + { {0xe0, 0x71, 0}, {0xe0, 0xf0, 0x71, 0} }, { {0xe0, 0x72, 0}, {0xe0, 0xf0, 0x72, 0} }, { {0xe0, 0x7f, 0}, {0xe0, 0xf0, 0x7f, 0} }, { {0xe0, 0xe1, 0}, {0} }, /*108*/ + { {0xe0, 0xee, 0}, {0} }, { {0xe0, 0xf1, 0}, {0} }, { {0xe0, 0xfe, 0}, {0} }, { {0xe0, 0xff, 0}, {0} } /*10c*/ +}; + +/*272 = 256 + 16 fake interim scancodes for disambiguation purposes.*/ +static scancode scancode_set3[272] = +{ + { {0}, {0} }, { {0x76, 0}, {0xf0, 0x76, 0} }, { {0x16, 0}, {0xf0, 0x16, 0} }, { {0x1e, 0}, {0xf0, 0x1e, 0} }, + { {0x26, 0}, {0xf0, 0x26, 0} }, { {0x25, 0}, {0xf0, 0x25, 0} }, { {0x2e, 0}, {0xf0, 0x2e, 0} }, { {0x36, 0}, {0xf0, 0x36, 0} }, + { {0x3d, 0}, {0xf0, 0x3d, 0} }, { {0x3e, 0}, {0xf0, 0x3e, 0} }, { {0x46, 0}, {0xf0, 0x46, 0} }, { {0x45, 0}, {0xf0, 0x45, 0} }, + { {0x4e, 0}, {0xf0, 0x4e, 0} }, { {0x55, 0}, {0xf0, 0x55, 0} }, { {0x66, 0}, {0xf0, 0x66, 0} }, { {0x0d, 0}, {0xf0, 0x0d, 0} }, + { {0x15, 0}, {0xf0, 0x15, 0} }, { {0x1d, 0}, {0xf0, 0x1d, 0} }, { {0x24, 0}, {0xf0, 0x24, 0} }, { {0x2d, 0}, {0xf0, 0x2d, 0} }, + { {0x2c, 0}, {0xf0, 0x2c, 0} }, { {0x35, 0}, {0xf0, 0x35, 0} }, { {0x3c, 0}, {0xf0, 0x3c, 0} }, { {0x43, 0}, {0xf0, 0x43, 0} }, + { {0x44, 0}, {0xf0, 0x44, 0} }, { {0x4d, 0}, {0xf0, 0x4d, 0} }, { {0x54, 0}, {0xf0, 0x54, 0} }, { {0x5b, 0}, {0xf0, 0x5b, 0} }, + { {0x5a, 0}, {0xf0, 0x5a, 0} }, { {0x19, 0}, {0xf0, 0x19, 0} }, { {0x1c, 0}, {0xf0, 0x1c, 0} }, { {0x1b, 0}, {0xf0, 0x1b, 0} }, + { {0x23, 0}, {0xf0, 0x23, 0} }, { {0x2b, 0}, {0xf0, 0x2b, 0} }, { {0x34, 0}, {0xf0, 0x34, 0} }, { {0x33, 0}, {0xf0, 0x33, 0} }, + { {0x3b, 0}, {0xf0, 0x3b, 0} }, { {0x42, 0}, {0xf0, 0x42, 0} }, { {0x4b, 0}, {0xf0, 0x4b, 0} }, { {0x4c, 0}, {0xf0, 0x4c, 0} }, + { {0x52, 0}, {0xf0, 0x52, 0} }, { {0x0e, 0}, {0xf0, 0x0e, 0} }, { {0x12, 0}, {0xf0, 0x12, 0} }, { {0x5c, 0}, {0xf0, 0x5c, 0} }, + { {0x1a, 0}, {0xf0, 0x1a, 0} }, { {0x22, 0}, {0xf0, 0x22, 0} }, { {0x21, 0}, {0xf0, 0x21, 0} }, { {0x2a, 0}, {0xf0, 0x2a, 0} }, + { {0x32, 0}, {0xf0, 0x32, 0} }, { {0x31, 0}, {0xf0, 0x31, 0} }, { {0x3a, 0}, {0xf0, 0x3a, 0} }, { {0x41, 0}, {0xf0, 0x41, 0} }, + { {0x49, 0}, {0xf0, 0x49, 0} }, { {0x4a, 0}, {0xf0, 0x4a, 0} }, { {0x59, 0}, {0xf0, 0x59, 0} }, { {0x7c, 0}, {0xf0, 0x7c, 0} }, + { {0x11, 0}, {0xf0, 0x11, 0} }, { {0x29, 0}, {0xf0, 0x29, 0} }, { {0x14, 0}, {0xf0, 0x14, 0} }, { {0x05, 0}, {0xf0, 0x05, 0} }, + { {0x06, 0}, {0xf0, 0x06, 0} }, { {0x04, 0}, {0xf0, 0x04, 0} }, { {0x0c, 0}, {0xf0, 0x0c, 0} }, { {0x03, 0}, {0xf0, 0x03, 0} }, + { {0x0b, 0}, {0xf0, 0x0b, 0} }, { {0x83, 0}, {0xf0, 0x83, 0} }, { {0x0a, 0}, {0xf0, 0x0a, 0} }, { {0x01, 0}, {0xf0, 0x01, 0} }, + { {0x09, 0}, {0xf0, 0x09, 0} }, { {0x77, 0}, {0xf0, 0x77, 0} }, { {0x7e, 0}, {0xf0, 0x7e, 0} }, { {0x6c, 0}, {0xf0, 0x6c, 0} }, + { {0x75, 0}, {0xf0, 0x75, 0} }, { {0x7d, 0}, {0xf0, 0x7d, 0} }, { {0x7b, 0}, {0xf0, 0x7b, 0} }, { {0x6b, 0}, {0xf0, 0x6b, 0} }, + { {0x73, 0}, {0xf0, 0x73, 0} }, { {0x74, 0}, {0xf0, 0x74, 0} }, { {0x79, 0}, {0xf0, 0x79, 0} }, { {0x69, 0}, {0xf0, 0x69, 0} }, + { {0x72, 0}, {0xf0, 0x72, 0} }, { {0x7a, 0}, {0xf0, 0x7a, 0} }, { {0x70, 0}, {0xf0, 0x70, 0} }, { {0x71, 0}, {0xf0, 0x71, 0} }, + { {0x84, 0}, {0xf0, 0x84, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0x78, 0}, {0xf0, 0x78, 0} }, + { {0x07, 0}, {0xf0, 0x07, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0x79, 0}, {0xf0, 0x79, 0} }, { {0x58, 0}, {0xf0, 0x58, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0x77, 0}, {0xf0, 0x77, 0} }, { {0, 0}, {0, 0} }, { {0x57, 0}, {0xf0, 0x57, 0} }, + { {0x39, 0}, {0xf0, 0x39, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0x6e, 0}, {0xf0, 0x6e, 0} }, + { {0x63, 0}, {0xf0, 0x63, 0} }, { {0x6f, 0}, {0xf0, 0x6f, 0} }, { {0, 0}, {0, 0} }, { {0x61, 0}, {0xf0, 0x61, 0} }, + { {0, 0}, {0, 0} }, { {0x6a, 0}, {0xf0, 0x6a, 0} }, { {0, 0}, {0, 0} }, { {0x65, 0}, {0xf0, 0x65, 0} }, + { {0x60, 0}, {0xf0, 0x60, 0} }, { {0x6d, 0}, {0xf0, 0x6d, 0} }, { {0x67, 0}, {0xf0, 0x67, 0} }, { {0x64, 0}, {0xf0, 0x64, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0x8b, 0}, {0xf0, 0x8b, 0} }, + { {0x8c, 0}, {0xf0, 0x8c, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, + { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, { {0, 0}, {0, 0} }, }; /*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*/ + { {0}, {0} }, { {0x01, 0}, {0x81, 0} }, { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} }, + { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} }, + { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} }, + { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} }, + { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} }, + { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} }, + { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} }, + { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} }, + { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} }, + { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} }, + { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, { {0x2a, 0}, {0xaa, 0} }, { {0x2b, 0}, {0xab, 0} }, + { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} }, + { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} }, + { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} }, + { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} }, + { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} }, + { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} }, + { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} }, + { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} }, + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*54*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*58*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*5c*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*60*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*64*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*68*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*6c*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*70*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*74*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*78*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*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} }, { {0x2a, -1}, {0xaa, -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} }, { {0x36, -1}, {0xb6, -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*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*80*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*84*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*88*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*8c*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*90*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*94*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*98*/ + { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0}, {0} }, { {0}, {0} }, /*9c*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*a0*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*a4*/ + { {0}, {0} }, { {0}, {0} }, { {0x2a, 0}, {0xaa, 0} }, { {0}, {0} }, /*a8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*ac*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*b0*/ + { {0}, {0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} }, /*b4*/ + { {0x38, 0}, {0xb8, 0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*b8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*bc*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*c0*/ + { {0}, {0} }, { {0}, {0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, /*c4*/ + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0}, {0} }, { {0x4b, 0}, {0xcb, 0} }, /*c8*/ + { {0}, {0} }, { {0x4d, 0}, {0xcd, 0} }, { {0}, {0} }, { {0x4f, 0}, {0xcf, 0} }, /*cc*/ + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, /*d0*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*d4*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*d8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*dc*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*e0*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*e4*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*e8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*ec*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*f0*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*f4*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*f8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*fc*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*100*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*104*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*108*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*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*/ + { {0}, {0} }, { {0x01, 0}, {0x81, 0} }, { {0x02, 0}, {0x82, 0} }, { {0x03, 0}, {0x83, 0} }, + { {0x04, 0}, {0x84, 0} }, { {0x05, 0}, {0x85, 0} }, { {0x06, 0}, {0x86, 0} }, { {0x07, 0}, {0x87, 0} }, + { {0x08, 0}, {0x88, 0} }, { {0x09, 0}, {0x89, 0} }, { {0x0a, 0}, {0x8a, 0} }, { {0x0b, 0}, {0x8b, 0} }, + { {0x0c, 0}, {0x8c, 0} }, { {0x0d, 0}, {0x8d, 0} }, { {0x0e, 0}, {0x8e, 0} }, { {0x0f, 0}, {0x8f, 0} }, + { {0x10, 0}, {0x90, 0} }, { {0x11, 0}, {0x91, 0} }, { {0x12, 0}, {0x92, 0} }, { {0x13, 0}, {0x93, 0} }, + { {0x14, 0}, {0x94, 0} }, { {0x15, 0}, {0x95, 0} }, { {0x16, 0}, {0x96, 0} }, { {0x17, 0}, {0x97, 0} }, + { {0x18, 0}, {0x98, 0} }, { {0x19, 0}, {0x99, 0} }, { {0x1a, 0}, {0x9a, 0} }, { {0x1b, 0}, {0x9b, 0} }, + { {0x1c, 0}, {0x9c, 0} }, { {0x1d, 0}, {0x9d, 0} }, { {0x1e, 0}, {0x9e, 0} }, { {0x1f, 0}, {0x9f, 0} }, + { {0x20, 0}, {0xa0, 0} }, { {0x21, 0}, {0xa1, 0} }, { {0x22, 0}, {0xa2, 0} }, { {0x23, 0}, {0xa3, 0} }, + { {0x24, 0}, {0xa4, 0} }, { {0x25, 0}, {0xa5, 0} }, { {0x26, 0}, {0xa6, 0} }, { {0x27, 0}, {0xa7, 0} }, + { {0x28, 0}, {0xa8, 0} }, { {0x29, 0}, {0xa9, 0} }, { {0x2a, 0}, {0xaa, 0} }, { {0x47, 0}, {0xc7, 0} }, + { {0x2c, 0}, {0xac, 0} }, { {0x2d, 0}, {0xad, 0} }, { {0x2e, 0}, {0xae, 0} }, { {0x2f, 0}, {0xaf, 0} }, + { {0x30, 0}, {0xb0, 0} }, { {0x31, 0}, {0xb1, 0} }, { {0x32, 0}, {0xb2, 0} }, { {0x33, 0}, {0xb3, 0} }, + { {0x34, 0}, {0xb4, 0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} }, + { {0x38, 0}, {0xb8, 0} }, { {0x39, 0}, {0xb9, 0} }, { {0x3a, 0}, {0xba, 0} }, { {0x3b, 0}, {0xbb, 0} }, + { {0x3c, 0}, {0xbc, 0} }, { {0x3d, 0}, {0xbd, 0} }, { {0x3e, 0}, {0xbe, 0} }, { {0x3f, 0}, {0xbf, 0} }, + { {0x40, 0}, {0xc0, 0} }, { {0x41, 0}, {0xc1, 0} }, { {0x42, 0}, {0xc2, 0} }, { {0x43, 0}, {0xc3, 0} }, + { {0x44, 0}, {0xc4, 0} }, { {0x45, 0}, {0xc5, 0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, + { {0x48, 0}, {0xc8, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0x4a, 0}, {0xca, 0} }, { {0x4b, 0}, {0xcb, 0} }, + { {0x4c, 0}, {0xcc, 0} }, { {0x4d, 0}, {0xcd, 0} }, { {0x4e, 0}, {0xce, 0} }, { {0x4f, 0}, {0xcf, 0} }, + { {0x50, 0}, {0xd0, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x56, 0}, {0xd6, 0} }, + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*54*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*58*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*5c*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*60*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*64*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*68*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*6c*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*70*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*74*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*78*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*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} }, { {0x2a, -1}, {0xaa, -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} }, { {0x36, -1}, {0xb6, -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*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*80*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*84*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*88*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*8c*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*90*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*94*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*98*/ + { {0x57, 0}, {0xd7, 0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*9c*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*a0*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*a4*/ + { {0}, {0} }, { {0}, {0} }, { {0x2a, 0}, {0xaa, 0} }, { {0}, {0} }, /*a8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*ac*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*b0*/ + { {0}, {0} }, { {0x35, 0}, {0xb5, 0} }, { {0x36, 0}, {0xb6, 0} }, { {0x37, 0}, {0xb7, 0} }, /*b4*/ + { {0x38, 0}, {0xb8, 0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*b8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*bc*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*c0*/ + { {0}, {0} }, { {0}, {0} }, { {0x46, 0}, {0xc6, 0} }, { {0x47, 0}, {0xc7, 0} }, /*c4*/ + { {0x29, 0}, {0xa9, 0} }, { {0x49, 0}, {0xc9, 0} }, { {0}, {0} }, { {0x2b, 0}, {0xab, 0} }, /*c8*/ + { {0}, {0} }, { {0x4e, 0}, {0xce, 0} }, { {0}, {0} }, { {0x4f, 0}, {0xcf, 0} }, /*cc*/ + { {0x4a, 0}, {0xca, 0} }, { {0x51, 0}, {0xd1, 0} }, { {0x52, 0}, {0xd2, 0} }, { {0x53, 0}, {0xd3, 0} }, /*d0*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*d4*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*d8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*dc*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*e0*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*e4*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*e8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*ec*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*f0*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*f4*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*f8*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*fc*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*100*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*104*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*108*/ + { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, { {0}, {0} }, /*10c*/ }; -static int oldkey[272]; -static int keydelay[272]; +static uint8_t oldkey[272]; +static uint8_t keydelay[272]; void (*keyboard_send)(uint8_t val); void (*keyboard_poll)(); int keyboard_scan = 1; +static scancode *at_scancodes; + +void keyboard_set_scancode_set(int set) +{ + switch (set) + { + case SCANCODE_SET_1: + at_scancodes = scancode_set1; + break; + case SCANCODE_SET_2: + at_scancodes = scancode_set2; + break; + case SCANCODE_SET_3: + at_scancodes = scancode_set3; + break; + default: + pclog("Invalid scancode set: %i\n", set); + } +} + void keyboard_process() { int c; int d; - scancode *scancodes = (AT) ? scancode_set1 : scancode_xt; + scancode *scancodes = (AT || romset == ROM_XI8088) ? at_scancodes : scancode_xt; if (!keyboard_scan) return; if (TANDY) scancodes = scancode_tandy; @@ -259,20 +429,20 @@ void keyboard_process() if (pcem_key[c] != oldkey[c]) { oldkey[c] = pcem_key[c]; - if ( pcem_key[c] && scancodes[c].scancodes_make[0] == -1) + if ( pcem_key[c] && scancodes[c].scancodes_make[0] == 0) continue; - if (!pcem_key[c] && scancodes[c].scancodes_break[0] == -1) + if (!pcem_key[c] && scancodes[c].scancodes_break[0] == 0) continue; // pclog("Key %02X start\n", c); d = 0; if (pcem_key[c]) { - while (scancodes[c].scancodes_make[d] != -1) + while (scancodes[c].scancodes_make[d] != 0) keyboard_send(scancodes[c].scancodes_make[d++]); } else { - while (scancodes[c].scancodes_break[d] != -1) + while (scancodes[c].scancodes_break[d] != 0) keyboard_send(scancodes[c].scancodes_break[d++]); } } @@ -283,13 +453,32 @@ void keyboard_process() if (keydelay[c] >= 30) { keydelay[c] -= 10; - if (scancode_set1[c].scancodes_make[0] == -1) + if (scancodes[c].scancodes_make[0] == 0) continue; d = 0; - while (scancode_set1[c].scancodes_make[d] != -1) - keyboard_send(scancode_set1[c].scancodes_make[d++]); + while (scancodes[c].scancodes_make[d] != 0) + keyboard_send(scancodes[c].scancodes_make[d++]); } } } + +void keyboard_send_scancode(int code, int is_break) +{ + scancode *scancodes = (AT || romset == ROM_XI8088) ? at_scancodes : scancode_xt; + int d = 0; + + if (!keyboard_scan) return; + + if (!is_break) + { + while (scancodes[code].scancodes_make[d] != 0) + keyboard_send(scancodes[code].scancodes_make[d++]); + } + else + { + while (scancodes[code].scancodes_break[d] != 0) + keyboard_send(scancodes[code].scancodes_break[d++]); + } +} diff --git a/src/keyboard.h b/src/keyboard.h index 5d5283c..c4a63e0 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -3,4 +3,14 @@ extern void (*keyboard_poll)(); void keyboard_process(); extern int keyboard_scan; -extern int pcem_key[272]; +extern uint8_t pcem_key[272]; + +enum +{ + SCANCODE_SET_1, + SCANCODE_SET_2, + SCANCODE_SET_3 +}; + +void keyboard_set_scancode_set(int set); +void keyboard_send_scancode(int code, int is_break); diff --git a/src/keyboard_amstrad.c b/src/keyboard_amstrad.c index e7647f4..31b0eb4 100644 --- a/src/keyboard_amstrad.c +++ b/src/keyboard_amstrad.c @@ -26,6 +26,8 @@ struct uint8_t key_waiting; uint8_t pa; uint8_t pb; + + pc_timer_t send_delay_timer; } keyboard_amstrad; static uint8_t key_queue[16]; @@ -35,7 +37,7 @@ static uint8_t amstrad_systemstat_1, amstrad_systemstat_2; void keyboard_amstrad_poll() { - keybsenddelay += (1000 * TIMER_USEC); + timer_advance_u64(&keyboard_amstrad.send_delay_timer, (1000 * TIMER_USEC)); if (keyboard_amstrad.wantirq) { keyboard_amstrad.wantirq = 0; @@ -77,7 +79,6 @@ void keyboard_amstrad_write(uint16_t port, uint8_t val, void *priv) ppi.pb = val; timer_process(); - timer_update_outstanding(); speaker_update(); speaker_gated = val & 1; @@ -174,5 +175,5 @@ void keyboard_amstrad_init() keyboard_send = keyboard_amstrad_adddata; keyboard_poll = keyboard_amstrad_poll; - timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&keyboard_amstrad.send_delay_timer, keyboard_amstrad_poll, NULL, 1); } diff --git a/src/keyboard_at.c b/src/keyboard_at.c index c4a3c72..312326a 100644 --- a/src/keyboard_at.c +++ b/src/keyboard_at.c @@ -5,8 +5,11 @@ #include "pit.h" #include "sound.h" #include "sound_speaker.h" +#include "t3100e.h" #include "timer.h" +#include "video.h" #include "x86.h" +#include "xi8088.h" #include "keyboard.h" #include "keyboard_at.h" @@ -23,6 +26,8 @@ #define PS2_REFRESH_TIME (16 * TIMER_USEC) +#define RESET_DELAY_TIME (100 * 10) /*600ms*/ + struct { int initialised; @@ -32,7 +37,11 @@ struct uint8_t status; uint8_t mem[0x20]; uint8_t out; - int out_new; + int out_new, out_delayed; + + int scancode_set; + int translate; + int next_is_release; uint8_t input_port; uint8_t output_port; @@ -45,45 +54,79 @@ struct void (*mouse_write)(uint8_t val, void *p); void *mouse_p; - int refresh_time; + pc_timer_t refresh_timer; int refresh; int is_ps2; + + pc_timer_t send_delay_timer; + + int reset_delay; } keyboard_at; +/*Translation table taken from https://www.win.tue.nl/~aeb/linux/kbd/scancodes-10.html#ss10.3*/ +static uint8_t at_translation[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 +}; 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]; +uint8_t mouse_queue[16]; int mouse_queue_start = 0, mouse_queue_end = 0; +void keyboard_at_adddata_keyboard(uint8_t val); + void keyboard_at_poll() { - keybsenddelay += (1000 * TIMER_USEC); + timer_advance_u64(&keyboard_at.send_delay_timer, (100 * 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; + if (mouse_scan) + { +// pclog("keyboard_at : take IRQ12\n"); + 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; + keyboard_at.last_irq = 0x1000; + } + else + { +// pclog("keyboard_at: suppressing IRQ12\n"); + keyboard_at.out_new = -1; + } } else { if (keyboard_at.mem[0] & 0x01) picint(2); - keyboard_at.out = keyboard_at.out_new; + keyboard_at.out = keyboard_at.out_new & 0xff; keyboard_at.out_new = -1; keyboard_at.status |= STAT_OFULL; keyboard_at.status &= ~STAT_IFULL; @@ -96,48 +139,102 @@ void keyboard_at_poll() 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]; + keyboard_at.out_new = key_ctrl_queue[key_ctrl_queue_start] | 0x200; key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; } + else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && + keyboard_at.out_delayed != -1) + { + keyboard_at.out_new = keyboard_at.out_delayed; + keyboard_at.out_delayed = -1; + } + else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && + !(keyboard_at.mem[0] & 0x10) && keyboard_at.out_delayed != -1) + { + keyboard_at.out_new = keyboard_at.out_delayed; + keyboard_at.out_delayed = -1; + } else 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; - } + } + + if (keyboard_at.reset_delay) + { + keyboard_at.reset_delay--; + if (!keyboard_at.reset_delay) + keyboard_at_adddata_keyboard(0xaa); + } } 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; + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; + + if (!(keyboard_at.out_new & 0x300)) + { + keyboard_at.out_delayed = keyboard_at.out_new; + keyboard_at.out_new = -1; } - 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);*/ } void keyboard_at_adddata_keyboard(uint8_t val) { + if (keyboard_at.reset_delay) + return; /* if (val == 0x1c) { key_1c++; if (key_1c == 4) output = 3; }*/ + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if (romset == ROM_T3100E && (pcem_key[0xb8] || pcem_key[0x9d])) + { + switch (val) + { + case 0x4f: t3100e_notify_set(0x01); break; /* End */ + case 0x50: t3100e_notify_set(0x02); break; /* Down */ + case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ + case 0x52: t3100e_notify_set(0x04); break; /* Ins */ + case 0x53: t3100e_notify_set(0x05); break; /* Del */ + case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ + case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ + case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ + case 0x47: t3100e_notify_set(0x09); break; /* Home */ + case 0x48: t3100e_notify_set(0x0A); break; /* Up */ + case 0x49: t3100e_notify_set(0x0B); break; /* PgUp */ + case 0x4A: t3100e_notify_set(0x0C); break; /* Keypad -*/ + case 0x4B: t3100e_notify_set(0x0D); break; /* Left */ + case 0x4C: t3100e_notify_set(0x0E); break; /* KP 5 */ + case 0x4D: t3100e_notify_set(0x0F); break; /* Right */ + } + } + if (keyboard_at.translate) + { + if (val == 0xf0) + { + keyboard_at.next_is_release = 1; + return; + } + else + { + val = at_translation[val]; + if (keyboard_at.next_is_release) + val |= 0x80; + keyboard_at.next_is_release = 0; + } + } key_queue[key_queue_end] = val; key_queue_end = (key_queue_end + 1) & 0xf; // pclog("keyboard_at : %02X added to key queue\n", val); @@ -155,6 +252,8 @@ void keyboard_at_adddata_mouse(uint8_t val) 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 (romset == ROM_XI8088 && port == 0x63) + port = 0x61; /* if (ram[8] == 0xc3) { output = 3; @@ -184,9 +283,15 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) if (!(val & 1) && keyboard_at.wantirq) keyboard_at.wantirq = 0; mouse_scan = !(val & 0x20); + keyboard_at.translate = val & 0x40; } break; + case 0xb6: /* T3100e - set colour/mono switch */ + if (romset == ROM_T3100E) + t3100e_mono_set(val); + break; + case 0xcb: /*AMI - set keyboard mode*/ break; @@ -205,13 +310,22 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) keyboard_at.output_port = val; break; + case 0xd2: /*Write to keyboard output buffer*/ + keyboard_at_adddata(val); + break; + case 0xd3: /*Write to mouse output buffer*/ keyboard_at_adddata_mouse(val); break; case 0xd4: /*Write to mouse*/ if (keyboard_at.mouse_write) + { keyboard_at.mouse_write(val, keyboard_at.mouse_p); + /*Implicitly enable mouse*/ + mouse_scan = 1; + keyboard_at.mem[0] &= ~0x20; + } break; default: @@ -232,6 +346,45 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) case 0xed: /*Set/reset LEDs*/ keyboard_at_adddata_keyboard(0xfa); break; + + case 0xf0: /*Set scancode set*/ + switch (val) + { + case 0: /*Read current set*/ + keyboard_at_adddata_keyboard(0xfa); + switch (keyboard_at.scancode_set) + { + case SCANCODE_SET_1: + keyboard_at_adddata_keyboard(0x01); + break; + case SCANCODE_SET_2: + keyboard_at_adddata_keyboard(0x02); + break; + case SCANCODE_SET_3: + keyboard_at_adddata_keyboard(0x03); + break; + } + break; + case 1: + keyboard_at.scancode_set = SCANCODE_SET_1; + keyboard_set_scancode_set(SCANCODE_SET_1); + keyboard_at_adddata_keyboard(0xfa); + break; + case 2: + keyboard_at.scancode_set = SCANCODE_SET_2; + keyboard_set_scancode_set(SCANCODE_SET_2); + keyboard_at_adddata_keyboard(0xfa); + break; + case 3: + keyboard_at.scancode_set = SCANCODE_SET_3; + keyboard_set_scancode_set(SCANCODE_SET_3); + keyboard_at_adddata_keyboard(0xfa); + break; + default: + keyboard_at_adddata_keyboard(0xfe); + break; + } + break; case 0xf3: /*Set typematic rate/delay*/ keyboard_at_adddata_keyboard(0xfa); @@ -257,10 +410,19 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) keyboard_at_adddata_keyboard(0xfa); break; + case 0xee: /*Diagnostic echo*/ + keyboard_at_adddata_keyboard(0xee); + break; + + case 0xf0: /*Set scancode set*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + case 0xf2: /*Read ID*/ keyboard_at_adddata_keyboard(0xfa); keyboard_at_adddata_keyboard(0xab); - keyboard_at_adddata_keyboard(0x41); + keyboard_at_adddata_keyboard(0x83); break; case 0xf3: /*Set typematic rate/delay*/ @@ -280,7 +442,7 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) case 0xff: /*Reset*/ key_queue_start = key_queue_end = 0; /*Clear key queue*/ keyboard_at_adddata_keyboard(0xfa); - keyboard_at_adddata_keyboard(0xaa); + keyboard_at.reset_delay = RESET_DELAY_TIME; break; default: @@ -296,15 +458,20 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) 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(&pit, 2, val & 1); + + if (romset == ROM_XI8088) + { + if (val & 0x04) + xi8088_turbo_set(1); + else + xi8088_turbo_set(0); + } break; case 0x64: @@ -340,10 +507,12 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) case 0xa7: /*Disable mouse port*/ mouse_scan = 0; + keyboard_at.mem[0] |= 0x20; break; case 0xa8: /*Enable mouse port*/ mouse_scan = 1; + keyboard_at.mem[0] &= ~0x20; break; case 0xa9: /*Test mouse port*/ @@ -357,6 +526,9 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) key_ctrl_queue_start = key_ctrl_queue_end = 0; keyboard_at.status &= ~STAT_OFULL; } + /* T3100e and Samsung SPC-6000A expects STAT_IFULL to be set immediately + * after sending 0xAA */ + if(romset == ROM_T3100E || romset == ROM_SPC6000A) keyboard_at.status |= STAT_IFULL; keyboard_at.status |= STAT_SYSFLAG; keyboard_at.mem[0] |= 0x04; keyboard_at_adddata(0x55); @@ -382,9 +554,82 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) case 0xae: /*Enable keyboard*/ keyboard_at.mem[0] &= ~0x10; break; + + case 0xb0: /* T3100e: Turbo on */ + if (romset == ROM_T3100E) + t3100e_turbo_set(1); + break; + + case 0xb1: /* T3100e: Turbo off */ + if (romset == ROM_T3100E) + t3100e_turbo_set(0); + break; + + case 0xb2: /* T3100e: Select external display */ + if (romset == ROM_T3100E) + t3100e_display_set(0x00); + break; + + case 0xb3: /* T3100e: Select internal display */ + if (romset == ROM_T3100E) + t3100e_display_set(0x01); + break; + + case 0xb4: /* T3100e: Get configuration / status */ + if (romset == ROM_T3100E) + keyboard_at_adddata(t3100e_config_get()); + break; + + case 0xb5: /* T3100e: Get colour / mono byte */ + if (romset == ROM_T3100E) + keyboard_at_adddata(t3100e_mono_get()); + break; + + case 0xb6: /* T3100e: Set colour / mono byte */ + if (romset == ROM_T3100E) + keyboard_at.want60 = 1; + break; + + case 0xba: + if (romset == ROM_ENDEAVOR || romset == ROM_ZAPPA || romset == ROM_ITAUTEC_INFOWAYM) + keyboard_at_adddata(0); + break; + + /* T3100e commands not implemented: + * 0xB7: Emulate PS/2 keyboard + * 0xB8: Emulate AT keyboard */ + + case 0xbb: /* T3100e: Read 'Fn' key. + Return it for right Ctrl and right + Alt; on the real T3100e, these keystrokes + could only be generated using 'Fn'. */ + if (romset == ROM_T3100E) + { + if (pcem_key[0xb8] || /* Right Alt */ + pcem_key[0x9d]) /* Right Ctrl */ + { + keyboard_at_adddata(0x04); + } + else keyboard_at_adddata(0x00); + } + break; + + case 0xbc: /* T3100e: Reset Fn+Key notification */ + if (romset == ROM_T3100E) + t3100e_notify_set(0x00); + break; case 0xc0: /*Read input port*/ - keyboard_at_adddata(keyboard_at.input_port | 4); + /* The T3100e returns all bits set except bit 6 which + * is set by t3100e_mono_set() */ + if (romset == ROM_T3100E) + keyboard_at.input_port = (t3100e_mono_get() & 1) ? 0xFF : 0xBF; + + if (romset == ROM_ENDEAVOR || romset == ROM_ZAPPA || romset == ROM_ITAUTEC_INFOWAYM) + keyboard_at_adddata(keyboard_at.input_port | 4 | 0x40); + else + keyboard_at_adddata(keyboard_at.input_port | 4); + keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc); break; @@ -392,7 +637,10 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) break; case 0xca: /*AMI - read keyboard mode*/ - keyboard_at_adddata(0x00); /*ISA mode*/ + if (romset == ROM_GA686BX) /*TODO*/ + keyboard_at_adddata(0x01); /*PS2 mode*/ + else + keyboard_at_adddata(0x00); /*ISA mode*/ break; case 0xcb: /*AMI - set keyboard mode*/ @@ -411,6 +659,10 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) keyboard_at.want60 = 1; break; + case 0xd2: /*Write keyboard output buffer*/ + keyboard_at.want60 = 1; + break; + case 0xd3: /*Write mouse output buffer*/ keyboard_at.want60 = 1; break; @@ -422,11 +674,21 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) case 0xe0: /*Read test inputs*/ keyboard_at_adddata(0x00); break; + + // AWARD BIOS: called after turbo ON/OFF in the + // Hyundai Super-286TR and probably other AWARD 286 + // bioses. Related to the Turbo LEDs. Exact function + // can't be confirmed because the system in question + // has no such leds. + //case 0xe8: /* Turbo ON, always followed by 0xba */ + //case 0xe9: /* Turbo OFF */ + //break; case 0xef: /*??? - sent by AMI486*/ break; - case 0xfe: /*Pulse output port - pin 0 selected - x86 reset*/ + case 0xf0: case 0xf2: case 0xf4: case 0xf6: + case 0xf8: case 0xfa: case 0xfc: case 0xfe: /*Pulse output port - pin 0 selected - x86 reset*/ softresetx86(); /*Pulse reset!*/ cpu_set_edx(); break; @@ -445,7 +707,12 @@ void keyboard_at_write(uint16_t port, uint8_t val, void *priv) uint8_t keyboard_at_read(uint16_t port, void *priv) { uint8_t temp = 0xff; + + if (romset != ROM_IBMAT && romset != ROM_IBMXT286) + cycles -= ISA_CYCLES(8); // if (port != 0x61) pclog("keyboard_at : read %04X ", port); + if (romset == ROM_XI8088 && port == 0x63) + port = 0x61; switch (port) { case 0x60: @@ -466,6 +733,13 @@ uint8_t keyboard_at_read(uint16_t port, void *priv) else temp &= ~0x10; } + if (romset == ROM_XI8088) + { + if (xi8088_turbo_get()) + temp |= 0x04; + else + temp &= ~0x04; + } break; case 0x64: @@ -486,8 +760,12 @@ void keyboard_at_reset() keyboard_at.mem[0] = 0x11; keyboard_at.wantirq = 0; keyboard_at.output_port = 0xcf; - keyboard_at.input_port = (MDA) ? 0xf0 : 0xb0; + if (romset == ROM_XI8088) + keyboard_at.input_port = (video_is_mda()) ? 0xb0 : 0xf0; + else + keyboard_at.input_port = (video_is_mda()) ? 0xf0 : 0xb0; keyboard_at.out_new = -1; + keyboard_at.out_delayed = -1; keyboard_at.last_irq = 0; keyboard_at.key_wantdata = 0; @@ -498,12 +776,13 @@ void keyboard_at_reset() static void at_refresh(void *p) { keyboard_at.refresh = !keyboard_at.refresh; - keyboard_at.refresh_time += PS2_REFRESH_TIME; + timer_advance_u64(&keyboard_at.refresh_timer, PS2_REFRESH_TIME); } void keyboard_at_init() { //return; + memset(&keyboard_at, 0, sizeof(keyboard_at)); io_sethandler(0x0060, 0x0005, keyboard_at_read, NULL, NULL, keyboard_at_write, NULL, NULL, NULL); keyboard_at_reset(); keyboard_send = keyboard_at_adddata_keyboard; @@ -511,8 +790,10 @@ void keyboard_at_init() keyboard_at.mouse_write = NULL; keyboard_at.mouse_p = NULL; keyboard_at.is_ps2 = 0; + keyboard_set_scancode_set(SCANCODE_SET_2); + keyboard_at.scancode_set = SCANCODE_SET_2; - timer_add(keyboard_at_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&keyboard_at.send_delay_timer, keyboard_at_poll, NULL, 1); } void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p) @@ -523,6 +804,6 @@ void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p) void keyboard_at_init_ps2() { - timer_add(at_refresh, &keyboard_at.refresh_time, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&keyboard_at.refresh_timer, at_refresh, NULL, 1); keyboard_at.is_ps2 = 1; } diff --git a/src/keyboard_at.h b/src/keyboard_at.h index 6271e75..5dc00fa 100644 --- a/src/keyboard_at.h +++ b/src/keyboard_at.h @@ -5,5 +5,6 @@ void keyboard_at_poll(); void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val, void *p), void *p); void keyboard_at_adddata_mouse(uint8_t val); +extern uint8_t mouse_queue[16]; extern int mouse_queue_start, mouse_queue_end; extern int mouse_scan; diff --git a/src/keyboard_olim24.c b/src/keyboard_olim24.c index e86241d..a34d830 100644 --- a/src/keyboard_olim24.c +++ b/src/keyboard_olim24.c @@ -34,6 +34,8 @@ struct uint8_t params[16]; int mouse_mode; + + pc_timer_t send_delay_timer; } keyboard_olim24; static uint8_t key_queue[16]; @@ -43,7 +45,7 @@ static uint8_t mouse_scancodes[7]; void keyboard_olim24_poll() { - keybsenddelay += (1000 * TIMER_USEC); + timer_advance_u64(&keyboard_olim24.send_delay_timer, (1000 * TIMER_USEC)); //pclog("poll %i\n", keyboard_olim24.wantirq); if (keyboard_olim24.wantirq) { @@ -147,7 +149,6 @@ void keyboard_olim24_write(uint16_t port, uint8_t val, void *priv) ppi.pb = val; timer_process(); - timer_update_outstanding(); speaker_update(); speaker_gated = val & 1; @@ -345,5 +346,5 @@ void keyboard_olim24_init() keyboard_send = keyboard_olim24_adddata; keyboard_poll = keyboard_olim24_poll; - timer_add(keyboard_olim24_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&keyboard_olim24.send_delay_timer, keyboard_olim24_poll, NULL, 1); } diff --git a/src/keyboard_pcjr.c b/src/keyboard_pcjr.c index 13f443b..6519897 100644 --- a/src/keyboard_pcjr.c +++ b/src/keyboard_pcjr.c @@ -1,5 +1,7 @@ #include "ibm.h" #include "device.h" +#include "cassette.h" +#include "fdd.h" #include "io.h" #include "mem.h" #include "nmi.h" @@ -32,6 +34,8 @@ struct uint8_t pa; uint8_t pb; + + pc_timer_t send_delay_timer; } keyboard_pcjr; static uint8_t key_queue[16]; @@ -39,8 +43,7 @@ static int key_queue_start = 0, key_queue_end = 0; void keyboard_pcjr_poll() { - keybsenddelay += (220 * TIMER_USEC); - + timer_advance_u64(&keyboard_pcjr.send_delay_timer, (220 * TIMER_USEC)); if (key_queue_start != key_queue_end && !keyboard_pcjr.serial_pos && !keyboard_pcjr.latched) { @@ -127,7 +130,8 @@ void keyboard_pcjr_write(uint16_t port, uint8_t val, void *priv) keyboard_pcjr.pb = val; timer_process(); - timer_update_outstanding(); + + cassette_set_motor((val & 8) ? 0 : 1); speaker_update(); speaker_gated = val & 1; @@ -171,7 +175,12 @@ uint8_t keyboard_pcjr_read(uint16_t port, void *priv) case 0x62: temp = (keyboard_pcjr.latched ? 1 : 0); temp |= 0x02; /*Modem card not installed*/ - temp |= (ppispeakon ? 0x10 : 0); + if (fdd_get_type(0) == 0) + temp |= 0x04; /*Disc card not installed*/ + if (!(keyboard_pcjr.pb & 8)) + temp |= (cassette_input()) ? 0x10 : 0; + else + temp |= (ppispeakon ? 0x10 : 0); temp |= (ppispeakon ? 0x20 : 0); temp |= (keyboard_pcjr.data ? 0x40: 0); // temp |= 0x04; @@ -205,5 +214,5 @@ void keyboard_pcjr_init() keyboard_send = keyboard_pcjr_adddata; keyboard_poll = keyboard_pcjr_poll; - timer_add(keyboard_pcjr_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&keyboard_pcjr.send_delay_timer, keyboard_pcjr_poll, NULL, 1); } diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c index d7e69bd..7f5c794 100644 --- a/src/keyboard_xt.c +++ b/src/keyboard_xt.c @@ -1,5 +1,7 @@ #include "ibm.h" #include "device.h" +#include "cassette.h" +#include "fdd.h" #include "io.h" #include "mem.h" #include "pic.h" @@ -8,6 +10,8 @@ #include "sound_speaker.h" #include "tandy_eeprom.h" #include "timer.h" +#include "t1000.h" +#include "video.h" #include "keyboard.h" #include "keyboard_xt.h" @@ -29,7 +33,12 @@ struct uint8_t pa; uint8_t pb; + int shift_full; + int tandy; + int pb2_turbo; + + pc_timer_t send_delay_timer; } keyboard_xt; static uint8_t key_queue[16]; @@ -37,15 +46,18 @@ static int key_queue_start = 0, key_queue_end = 0; void keyboard_xt_poll() { - keybsenddelay += (1000 * TIMER_USEC); + timer_advance_u64(&keyboard_xt.send_delay_timer, (1000 * TIMER_USEC)); + if (!(keyboard_xt.pb & 0x40) && romset != ROM_TANDY) + return; if (keyboard_xt.wantirq) { keyboard_xt.wantirq = 0; keyboard_xt.pa = keyboard_xt.key_waiting; + keyboard_xt.shift_full = 1; picint(2); pclog("keyboard_xt : take IRQ\n"); } - if (key_queue_start != key_queue_end && !keyboard_xt.pa) + if (key_queue_start != key_queue_end && !keyboard_xt.shift_full) { keyboard_xt.key_waiting = key_queue[key_queue_start]; pclog("Reading %02X from the key queue at %i\n", keyboard_xt.key_waiting, key_queue_start); @@ -56,6 +68,36 @@ void keyboard_xt_poll() void keyboard_xt_adddata(uint8_t val) { + /* Test for T1000 'Fn' key (Right Alt / Right Ctrl) */ + if (romset == ROM_T1000 || romset == ROM_T1200) + { + if (pcem_key[0xb8] || pcem_key[0x9D]) /* 'Fn' pressed */ + { + t1000_syskey(0x00, 0x04, 0x00); /* Set 'Fn' indicator */ + switch (val) + { + case 0x45: /* Num Lock => toggle numpad */ + t1000_syskey(0x00, 0x00, 0x10); break; + case 0x47: /* Home => internal display */ + t1000_syskey(0x40, 0x00, 0x00); break; + case 0x49: /* PgDn => turbo on */ + t1000_syskey(0x80, 0x00, 0x00); break; + case 0x4D: /* Right => toggle LCD font */ + t1000_syskey(0x00, 0x00, 0x20); break; + case 0x4F: /* End => external display */ + t1000_syskey(0x00, 0x40, 0x00); break; + case 0x51: /* PgDn => turbo off */ + t1000_syskey(0x00, 0x80, 0x00); break; + case 0x54: /* SysRQ => toggle window */ + t1000_syskey(0x00, 0x00, 0x08); break; + } + } + else + { + t1000_syskey(0x04, 0x00, 0x00); /* Reset 'Fn' indicator */ + } + } + 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; @@ -76,13 +118,20 @@ void keyboard_xt_write(uint16_t port, uint8_t val, void *priv) if (!(keyboard_xt.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/ { pclog("keyboard_xt : reset keyboard\n"); + key_queue_start = key_queue_end = 0; + keyboard_xt.wantirq = 0; + keyboard_xt.shift_full = 0; keyboard_xt_adddata(0xaa); } keyboard_xt.pb = val; ppi.pb = val; timer_process(); - timer_update_outstanding(); + + if (romset == ROM_IBMPC) + cassette_set_motor((val & 8) ? 0 : 1); + else if (keyboard_xt.pb2_turbo) + cpu_set_turbo((val & 4) ? 0 : 1); speaker_update(); speaker_gated = val & 1; @@ -94,6 +143,7 @@ void keyboard_xt_write(uint16_t port, uint8_t val, void *priv) if (val & 0x80) { keyboard_xt.pa = 0; + keyboard_xt.shift_full = 0; picintc(2); } break; @@ -107,28 +157,24 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv) switch (port) { case 0x60: - if ((romset == ROM_IBMPC) && (keyboard_xt.pb & 0x80)) + if ((romset == ROM_IBMPC || romset == ROM_LEDGE_MODELM) && (keyboard_xt.pb & 0x80)) { - if (VGA || gfxcard == GFX_EGA) + if (video_is_ega_vga()) temp = 0x4D; - else if (MDA) + else if (video_is_mda()) temp = 0x7D; else temp = 0x6D; + if (hasfpu) + temp |= 0x02; + } + else if ((romset == ROM_ATARIPC3) && (keyboard_xt.pb & 0x80)) + { + temp = 0x7f; } else { temp = keyboard_xt.pa; - if (key_queue_start == key_queue_end) - { - keyboard_xt.wantirq = 0; - } - else - { - keyboard_xt.key_waiting = key_queue[key_queue_start]; - key_queue_start = (key_queue_start + 1) & 0xf; - keyboard_xt.wantirq = 1; - } } break; @@ -143,20 +189,34 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv) temp = ((mem_size-64) / 32) & 0xf; else temp = ((mem_size-64) / 32) >> 4; + + temp |= (cassette_input()) ? 0x10 : 0; + } + else if (romset == ROM_LEDGE_MODELM) + { + /*High bit of memory size is read from port 0xa0*/ + temp = ((mem_size-64) / 32) & 0xf; + } + else if (romset == ROM_ATARIPC3) + { + if (keyboard_xt.pb & 0x04) + temp = 0xf; + else + temp = 4; } else { if (keyboard_xt.pb & 0x08) { - if (VGA || gfxcard == GFX_EGA) + if (video_is_ega_vga()) temp = 4; - else if (MDA) + else if (video_is_mda()) temp = 7; else temp = 6; } else - temp = 0xD; + temp = hasfpu ? 0xf : 0xd; } temp |= (ppispeakon ? 0x20 : 0); if (keyboard_xt.tandy) @@ -172,6 +232,16 @@ uint8_t keyboard_xt_read(uint16_t port, void *priv) return temp; } +static uint8_t ledge_modelm_read(uint16_t port, void *p) +{ + uint8_t temp = 0; + + if (((mem_size-64) / 32) >> 4) + temp |= 0x40; + + return temp; +} + void keyboard_xt_reset() { keyboard_xt.wantirq = 0; @@ -183,12 +253,15 @@ void keyboard_xt_init() { //return; io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL, NULL); + if (romset == ROM_LEDGE_MODELM) + io_sethandler(0x00a0, 0x0001, ledge_modelm_read, NULL, NULL, NULL, NULL, NULL, NULL); keyboard_xt_reset(); keyboard_send = keyboard_xt_adddata; keyboard_poll = keyboard_xt_poll; keyboard_xt.tandy = 0; + keyboard_xt.pb2_turbo = (romset == ROM_GENXT || romset == ROM_DTKXT || romset == ROM_AMIXT || romset == ROM_PXXT) ? 1 : 0; - timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&keyboard_xt.send_delay_timer, keyboard_xt_poll, NULL, 1); } void keyboard_tandy_init() @@ -200,5 +273,5 @@ void keyboard_tandy_init() keyboard_poll = keyboard_xt_poll; keyboard_xt.tandy = (romset != ROM_TANDY) ? 1 : 0; - timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&keyboard_xt.send_delay_timer, keyboard_xt_poll, NULL, 1); } diff --git a/src/laserxt.c b/src/laserxt.c new file mode 100644 index 0000000..5d15034 --- /dev/null +++ b/src/laserxt.c @@ -0,0 +1,129 @@ +/*This is the chipset used in the LaserXT series model*/ +#include "ibm.h" +#include "cpu.h" +#include "io.h" +#include "mem.h" + +static int laserxt_emspage[4]; +static int laserxt_emscontrol[4]; +static mem_mapping_t laserxt_ems_mapping[4]; +static int laserxt_ems_baseaddr_index = 0; +static uint8_t laserxt_turbo = 0x80; + +static uint32_t get_laserxt_ems_addr(uint32_t addr) +{ + if (laserxt_emspage[(addr >> 14) & 3] & 0x80) + { + addr = (romset == ROM_LTXT ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)) + ((laserxt_emspage[(addr >> 14) & 3] & 0x0F) << 14) + ((laserxt_emspage[(addr >> 14) & 3] & 0x40) << 12) + (addr & 0x3FFF); + } + + return addr; +} + +static void laserxt_write(uint16_t port, uint8_t val, void *priv) +{ + int i; + uint32_t paddr, vaddr; + + switch (port) + { + case 0x01F0: + laserxt_turbo = val; + cpu_set_turbo((val & 0x80) >> 7); + //pclog("Turbo %s at %04X:%04X\n", (val & 0x80) ? "Enabled" : "Disabled", CS, cpu_state.oldpc); + break; + case 0x0208: case 0x4208: case 0x8208: case 0xC208: + laserxt_emspage[port >> 14] = val; + paddr = 0xC0000 + (port & 0xC000) + (((laserxt_ems_baseaddr_index + (4 - (port >> 14))) & 0x0C) << 14); + + if (val & 0x80) + { + mem_mapping_enable(&laserxt_ems_mapping[port >> 14]); + vaddr = get_laserxt_ems_addr(paddr); + mem_mapping_set_exec(&laserxt_ems_mapping[port >> 14], ram + vaddr); + } + else + { + mem_mapping_disable(&laserxt_ems_mapping[port >> 14]); + } + + flushmmucache(); + break; + + case 0x0209: case 0x4209: case 0x8209: case 0xC209: + laserxt_emscontrol[port >> 14] = val; + laserxt_ems_baseaddr_index = 0; + + for (i = 0; i < 4; i++) + laserxt_ems_baseaddr_index |= (laserxt_emscontrol[i] & 0x80) >> (7 - i); + + mem_mapping_set_addr(&laserxt_ems_mapping[0], 0xC0000 + (((laserxt_ems_baseaddr_index + 4) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[1], 0xC4000 + (((laserxt_ems_baseaddr_index + 3) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[2], 0xC8000 + (((laserxt_ems_baseaddr_index + 2) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[3], 0xCC000 + (((laserxt_ems_baseaddr_index + 1) & 0x0C) << 14), 0x4000); + + flushmmucache(); + break; + } +} + +static uint8_t laserxt_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x01F0: + return laserxt_turbo; + + case 0x0208: case 0x4208: case 0x8208: case 0xC208: + return laserxt_emspage[port >> 14]; + + case 0x0209: case 0x4209: case 0x8209: case 0xC209: + return laserxt_emscontrol[port >> 14]; + } + return 0xff; +} + +static void mem_write_laserxtems(uint32_t addr, uint8_t val, void *priv) +{ + addr = get_laserxt_ems_addr(addr); + if (addr < (mem_size << 10)) + ram[addr] = val; +} + +static uint8_t mem_read_laserxtems(uint32_t addr, void *priv) +{ + uint8_t val = 0xFF; + + addr = get_laserxt_ems_addr(addr); + if (addr < (mem_size << 10)) + val = ram[addr]; + + return val; +} + +void laserxt_init() +{ + int i; + + io_sethandler(0x01F0, 0x0001, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + laserxt_turbo = 0x80; + cpu_set_turbo(1); + + if (mem_size > 640) + { + io_sethandler(0x0208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0x4208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0x8208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0xc208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + mem_mapping_set_addr(&ram_low_mapping, 0, romset == ROM_LTXT ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)); + } + + for (i = 0; i < 4; i++) + { + laserxt_emspage[i] = 0x7F; + laserxt_emscontrol[i] = (i == 3) ? 0x00 : 0x80; + mem_mapping_add(&laserxt_ems_mapping[i], 0xE0000 + (i << 14), 0x4000, mem_read_laserxtems, NULL, NULL, mem_write_laserxtems, NULL, NULL, ram + 0xA0000 + (i << 14), 0, NULL); + mem_mapping_disable(&laserxt_ems_mapping[i]); + } + mem_set_mem_state(0x0a0000, 0x60000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} diff --git a/src/laserxt.h b/src/laserxt.h new file mode 100644 index 0000000..abf7df1 --- /dev/null +++ b/src/laserxt.h @@ -0,0 +1 @@ +void laserxt_init(); diff --git a/src/lpt.c b/src/lpt.c index 5550a98..0f7cf42 100644 --- a/src/lpt.c +++ b/src/lpt.c @@ -1,8 +1,65 @@ #include "ibm.h" -#include "dac.h" #include "io.h" #include "lpt.h" +#include "lpt_dac.h" +#include "lpt_dss.h" + +char lpt1_device_name[16]; + +static struct +{ + char name[64]; + char internal_name[16]; + lpt_device_t *device; +} lpt_devices[] = +{ + {"None", "none", NULL}, + {"Disney Sound Source", "dss", &dss_device}, + {"LPT DAC / Covox Speech Thing", "lpt_dac", &lpt_dac_device}, + {"Stereo LPT DAC", "lpt_dac_stereo", &lpt_dac_stereo_device}, + {"", "", NULL} +}; + +char *lpt_device_get_name(int id) +{ + if (strlen(lpt_devices[id].name) == 0) + return NULL; + return lpt_devices[id].name; +} +char *lpt_device_get_internal_name(int id) +{ + if (strlen(lpt_devices[id].internal_name) == 0) + return NULL; + return lpt_devices[id].internal_name; +} + +static lpt_device_t *lpt1_device; +static void *lpt1_device_p; + +void lpt1_device_init() +{ + int c = 0; + + while (strcmp(lpt_devices[c].internal_name, lpt1_device_name) && strlen(lpt_devices[c].internal_name) != 0) + c++; + + if (strlen(lpt_devices[c].internal_name) == 0) + lpt1_device = NULL; + else + { + lpt1_device = lpt_devices[c].device; + if (lpt1_device) + lpt1_device_p = lpt1_device->init(); + } +} + +void lpt1_device_close() +{ + if (lpt1_device) + lpt1_device->close(lpt1_device_p); + lpt1_device = NULL; +} static uint8_t lpt1_dat, lpt2_dat; static uint8_t lpt1_ctrl, lpt2_ctrl; @@ -12,11 +69,13 @@ void lpt1_write(uint16_t port, uint8_t val, void *priv) switch (port & 3) { case 0: - writedac(0,val); + if (lpt1_device) + lpt1_device->write_data(val, lpt1_device_p); lpt1_dat = val; break; case 2: - writedacctrl(0,val); + if (lpt1_device) + lpt1_device->write_ctrl(val, lpt1_device_p); lpt1_ctrl = val; break; } @@ -28,7 +87,9 @@ uint8_t lpt1_read(uint16_t port, void *priv) case 0: return lpt1_dat; case 1: - return readdacfifo(); + if (lpt1_device) + return lpt1_device->read_status(lpt1_device_p); + return 0; case 2: return lpt1_ctrl; } @@ -40,11 +101,9 @@ void lpt2_write(uint16_t port, uint8_t val, void *priv) switch (port & 3) { case 0: - writedac(0,val); lpt2_dat = val; break; case 2: - writedacctrl(0,val); lpt2_ctrl = val; break; } @@ -56,7 +115,7 @@ uint8_t lpt2_read(uint16_t port, void *priv) case 0: return lpt2_dat; case 1: - return readdacfifo(); + return 0; case 2: return lpt2_ctrl; } @@ -65,13 +124,14 @@ uint8_t lpt2_read(uint16_t port, void *priv) void lpt_init() { - io_sethandler(0x0278, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); - io_sethandler(0x0378, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + 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); + if (port) + io_sethandler(port, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); } void lpt1_remove() { @@ -81,7 +141,8 @@ void lpt1_remove() } void lpt2_init(uint16_t port) { - io_sethandler(port, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + if (port) + io_sethandler(port, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); } void lpt2_remove() { diff --git a/src/lpt.h b/src/lpt.h index 0ff2e7b..117524a 100644 --- a/src/lpt.h +++ b/src/lpt.h @@ -4,3 +4,24 @@ extern void lpt1_remove(); extern void lpt2_init(uint16_t port); extern void lpt2_remove(); extern void lpt2_remove_ams(); + +void lpt1_write(uint16_t port, uint8_t val, void *priv); +uint8_t lpt1_read(uint16_t port, void *priv); + +void lpt1_device_init(); +void lpt1_device_close(); + +char *lpt_device_get_name(int id); +char *lpt_device_get_internal_name(int id); + +extern char lpt1_device_name[16]; + +typedef struct +{ + char name[80]; + void *(*init)(); + void (*close)(void *p); + void (*write_data)(uint8_t val, void *p); + void (*write_ctrl)(uint8_t val, void *p); + uint8_t (*read_status)(void *p); +} lpt_device_t; diff --git a/src/lpt_dac.c b/src/lpt_dac.c new file mode 100644 index 0000000..7a6fe82 --- /dev/null +++ b/src/lpt_dac.c @@ -0,0 +1,115 @@ +#include +#include "ibm.h" +#include "filters.h" +#include "lpt.h" +#include "lpt_dac.h" +#include "sound.h" + +typedef struct lpt_dac_t +{ + uint8_t dac_val_l, dac_val_r; + + int is_stereo; + int channel; + + int16_t buffer[2][MAXSOUNDBUFLEN]; + int pos; +} lpt_dac_t; + +static void dac_update(lpt_dac_t *lpt_dac) +{ + for (; lpt_dac->pos < sound_pos_global; lpt_dac->pos++) + { + lpt_dac->buffer[0][lpt_dac->pos] = (int8_t)(lpt_dac->dac_val_l ^ 0x80) * 0x40; + lpt_dac->buffer[1][lpt_dac->pos] = (int8_t)(lpt_dac->dac_val_r ^ 0x80) * 0x40; + } +} + + +static void dac_write_data(uint8_t val, void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + + if (lpt_dac->is_stereo) + { + if (lpt_dac->channel) + lpt_dac->dac_val_r = val; + else + lpt_dac->dac_val_l = val; + } + else + lpt_dac->dac_val_l = lpt_dac->dac_val_r = val; + dac_update(lpt_dac); +} + +static void dac_write_ctrl(uint8_t val, void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + + if (lpt_dac->is_stereo) + lpt_dac->channel = val & 0x01; +} + +static uint8_t dac_read_status(void *p) +{ + return 0; +} + + +static void dac_get_buffer(int32_t *buffer, int len, void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + int c; + + dac_update(lpt_dac); + + for (c = 0; c < len; c++) + { + buffer[c*2] += dac_iir(0, lpt_dac->buffer[0][c]); + buffer[c*2 + 1] += dac_iir(1, lpt_dac->buffer[1][c]); + } + lpt_dac->pos = 0; +} + +static void *dac_init() +{ + lpt_dac_t *lpt_dac = malloc(sizeof(lpt_dac_t)); + memset(lpt_dac, 0, sizeof(lpt_dac_t)); + + sound_add_handler(dac_get_buffer, lpt_dac); + + return lpt_dac; +} +static void *dac_stereo_init() +{ + lpt_dac_t *lpt_dac = dac_init(); + + lpt_dac->is_stereo = 1; + + return lpt_dac; +} +static void dac_close(void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + + free(lpt_dac); +} + +lpt_device_t lpt_dac_device = +{ + "LPT DAC / Covox Speech Thing", + dac_init, + dac_close, + dac_write_data, + dac_write_ctrl, + dac_read_status +}; +lpt_device_t lpt_dac_stereo_device = +{ + "Stereo LPT DAC", + dac_stereo_init, + dac_close, + dac_write_data, + dac_write_ctrl, + dac_read_status +}; diff --git a/src/lpt_dac.h b/src/lpt_dac.h new file mode 100644 index 0000000..b5f9815 --- /dev/null +++ b/src/lpt_dac.h @@ -0,0 +1,2 @@ +extern lpt_device_t lpt_dac_device; +extern lpt_device_t lpt_dac_stereo_device; diff --git a/src/lpt_dss.c b/src/lpt_dss.c new file mode 100644 index 0000000..767658a --- /dev/null +++ b/src/lpt_dss.c @@ -0,0 +1,111 @@ +#include +#include "ibm.h" +#include "filters.h" +#include "lpt.h" +#include "lpt_dac.h" +#include "sound.h" + +typedef struct dss_t +{ + uint8_t fifo[16]; + int read_idx, write_idx; + + uint8_t dac_val; + + pc_timer_t timer; + + int16_t buffer[MAXSOUNDBUFLEN]; + int pos; +} dss_t; + +static void dss_update(dss_t *dss) +{ + for (; dss->pos < sound_pos_global; dss->pos++) + dss->buffer[dss->pos] = (int8_t)(dss->dac_val ^ 0x80) * 0x40; +} + + +static void dss_write_data(uint8_t val, void *p) +{ + dss_t *dss = (dss_t *)p; + + if ((dss->write_idx - dss->read_idx) < 16) + { + dss->fifo[dss->write_idx & 15] = val; + dss->write_idx++; + } +} + +static void dss_write_ctrl(uint8_t val, void *p) +{ +} + +static uint8_t dss_read_status(void *p) +{ + dss_t *dss = (dss_t *)p; + + if ((dss->write_idx - dss->read_idx) >= 16) + return 0x40; + return 0; +} + + +static void dss_get_buffer(int32_t *buffer, int len, void *p) +{ + dss_t *dss = (dss_t *)p; + int c; + + dss_update(dss); + + for (c = 0; c < len*2; c += 2) + { + int16_t val = (int16_t)dss_iir((float)dss->buffer[c >> 1]); + + buffer[c] += val; + buffer[c+1] += val; + } + + dss->pos = 0; +} + +static void dss_callback(void *p) +{ + dss_t *dss = (dss_t *)p; + + dss_update(dss); + + if ((dss->write_idx - dss->read_idx) > 0) + { + dss->dac_val = dss->fifo[dss->read_idx & 15]; + dss->read_idx++; + } + + timer_advance_u64(&dss->timer, (TIMER_USEC * (1000000.0 / 7000.0))); +} + +static void *dss_init() +{ + dss_t *dss = malloc(sizeof(dss_t)); + memset(dss, 0, sizeof(dss_t)); + + sound_add_handler(dss_get_buffer, dss); + timer_add(&dss->timer, dss_callback, dss, 1); + + return dss; +} +static void dss_close(void *p) +{ + dss_t *dss = (dss_t *)p; + + free(dss); +} + +lpt_device_t dss_device = +{ + "Disney Sound Source", + dss_init, + dss_close, + dss_write_data, + dss_write_ctrl, + dss_read_status +}; diff --git a/src/lpt_dss.h b/src/lpt_dss.h new file mode 100644 index 0000000..6f85c1a --- /dev/null +++ b/src/lpt_dss.h @@ -0,0 +1 @@ +extern lpt_device_t dss_device; diff --git a/src/mca.c b/src/mca.c index ebd8ccb..11f8268 100644 --- a/src/mca.c +++ b/src/mca.c @@ -6,6 +6,7 @@ void (*mca_card_write[8])(int addr, uint8_t val, void *priv); uint8_t (*mca_card_read[8])(int addr, void *priv); +void (*mca_card_reset[8])(void *priv); void *mca_priv[8]; static int mca_index; static int mca_nr_cards; @@ -14,10 +15,13 @@ void mca_init(int nr_cards) { int c; + MCA = 1; + for (c = 0; c < 8; c++) { mca_card_read[c] = NULL; mca_card_write[c] = NULL; + mca_card_reset[c] = NULL; mca_priv[c] = NULL; } @@ -47,7 +51,18 @@ void mca_write(uint16_t port, uint8_t val) mca_card_write[mca_index](port, val, mca_priv[mca_index]); } -void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv) +void mca_reset(void) +{ + int c; + + for (c = 0; c < 8; c++) + { + if (mca_card_reset[c]) + mca_card_reset[c](mca_priv[c]); + } +} + +void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void (*reset)(void *priv), void *priv) { int c; @@ -57,6 +72,7 @@ void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint { mca_card_read[c] = read; mca_card_write[c] = write; + mca_card_reset[c] = reset; mca_priv[c] = priv; return; } diff --git a/src/mca.h b/src/mca.h index cf9361f..a298d24 100644 --- a/src/mca.h +++ b/src/mca.h @@ -1,5 +1,6 @@ void mca_init(int nr_cards); -void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv); +void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void (*reset)(void *priv), void *priv); void mca_set_index(int index); uint8_t mca_read(uint16_t port); void mca_write(uint16_t port, uint8_t val); +void mca_reset(void); diff --git a/src/mcr.c b/src/mcr.c index 83d7530..6c7d746 100644 --- a/src/mcr.c +++ b/src/mcr.c @@ -2,6 +2,7 @@ This chip was used as part of many 386 chipsets It controls memory addressing and shadowing*/ #include "ibm.h" +#include "x86.h" int nextreg6; uint8_t mcr22; @@ -10,7 +11,6 @@ void resetmcr() { mcrlock=0; mcrfirst=1; - shadowbios=0; } void writemcr(uint16_t addr, uint8_t val) @@ -29,7 +29,7 @@ void writemcr(uint16_t addr, uint8_t val) // exit(-1); break; case 0x23: - if (nextreg6) shadowbios=!val; +// if (nextreg6) shadowbios=!val; break; } mcr22=val; diff --git a/src/mem.c b/src/mem.c index ecfc949..15dc5ee 100644 --- a/src/mem.c +++ b/src/mem.c @@ -17,36 +17,25 @@ #include "rom.h" #include "x86_ops.h" #include "codegen.h" +#include "xi8088.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 *read_mapping[0x40000]; +static mem_mapping_t *write_mapping[0x40000]; +static uint8_t *_mem_exec[0x40000]; +static uint8_t _mem_state[0x40000]; static mem_mapping_t base_mapping; mem_mapping_t ram_low_mapping; mem_mapping_t ram_high_mapping; -static mem_mapping_t ram_mid_mapping; -static mem_mapping_t ram_remapped_mapping; +mem_mapping_t ram_mid_mapping; +mem_mapping_t ram_remapped_mapping; mem_mapping_t bios_mapping[8]; -mem_mapping_t bios_high_mapping[8]; +mem_mapping_t bios_high_mapping[9]; static mem_mapping_t romext_mapping; -int shadowbios,shadowbios_write; - -unsigned char isram[0x10000]; - static uint8_t ff_array[0x1000]; int mem_size; @@ -57,592 +46,23 @@ int cachesize=256; uint8_t *ram, *rom = NULL; uint8_t romext[32768]; -static void mem_load_atide115_bios() +uint64_t *byte_dirty_mask; +uint64_t *byte_code_present_mask; + +uint32_t mem_logical_addr; + +void (*smram_enable)(void); +void (*smram_disable)(void); + +int mmuflush=0; +int mmu_perm=4; + +int mem_addr_is_ram(uint32_t addr) { - FILE *f; - f=romfopen("roms/ide_at_1_1_5.bin","rb"); - -// is486=0; - if (f) - { - fread(romext,16384,1,f); - fclose(f); - } + mem_mapping_t *mapping = read_mapping[addr >> 14]; + + return (mapping == &ram_low_mapping) || (mapping == &ram_high_mapping) || (mapping == &ram_mid_mapping) || (mapping == &ram_remapped_mapping); } - -int loadbios() -{ - FILE *f=NULL,*ff=NULL; - int c; - - loadfont("roms/mda.rom", 0); - loadfont("roms/wy700.rom", 3); - loadfont("roms/8x12.bin", 4); - - biosmask = 0xffff; - - if (!rom) - rom = malloc(0x20000); - memset(romext,0x63,0x4000); - memset(rom, 0xff, 0x20000); - - pclog("Starting with romset %i\n", romset); - - 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); - 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); - 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); - 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); - return 1; - case ROM_TANDY1000HX: - f = romfopen("roms/tandy1000hx/v020000.u12", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - 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); - 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); - return 1; - } - else - { - fread(rom,65536,1,f); - fclose(f); - 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); - 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); - 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); - 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); - 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); - 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); - 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; - 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_AMI386SX: -// 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_AMI386DX_OPTI495: /*This uses the OPTi 82C495 chipset*/ - f=romfopen("roms/ami386dx/opt495sx.ami","rb"); - if (!f) break; - fread(rom,65536,1,f); - fclose(f); - return 1; - case ROM_MR386DX_OPTI495: /*This uses the OPTi 82C495 chipset*/ - f=romfopen("roms/mr386dx/opt495sx.mr","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); - 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; - 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); - return 1; - - case ROM_LTXT: - f = romfopen("roms/ltxt/27c64.bin", "rb"); - if (!f) break; - fread(rom + 0xE000, 8192, 1, f); - fclose(f); - return 1; - - case ROM_LXT3: - f = romfopen("roms/lxt3/27c64d.bin", "rb"); - if (!f) break; - fread(rom + 0xE000, 8192, 1, f); - fclose(f); - 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); - 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); - return 1; - - case ROM_PXXT: - f = romfopen("roms/pxxt/000p001.bin", "rb"); - if (!f) break; - fread(rom + 0xE000, 8192, 1, f); - fclose(f); - return 1; - - case ROM_JUKOPC: - f = romfopen("roms/jukopc/000o001.bin", "rb"); - if (!f) break; - fread(rom + 0xE000, 8192, 1, f); - fclose(f); - return 1; - - case ROM_IBMPS2_M30_286: - f = romfopen("roms/ibmps2_m30_286/33f5381a.bin", "rb"); - if (!f) break; - fread(rom, 0x20000, 1, f); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_IBMPS2_M50: - f=romfopen("roms/i8550021/90x7423.zm14","rb"); - ff=romfopen("roms/i8550021/90x7426.zm16","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); - f=romfopen("roms/i8550021/90x7420.zm13","rb"); - ff=romfopen("roms/i8550021/90x7429.zm18","rb"); - if (!f || !ff) break; - for (c = 0x10000; c < 0x20000; c += 2) - { - rom[c] = getc(f); - rom[c+1] = getc(ff); - } - fclose(ff); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_IBMPS2_M55SX: - f=romfopen("roms/i8555081/33f8146.zm41","rb"); - ff=romfopen("roms/i8555081/33f8145.zm40","rb"); - if (!f || !ff) break; - for (c = 0x0000; c < 0x20000; c += 2) - { - rom[c] = getc(f); - rom[c+1] = getc(ff); - } - fclose(ff); - fclose(f); - biosmask = 0x1ffff; - return 1; - - case ROM_IBMPS2_M80: - f=romfopen("roms/i8580111/15f6637.bin","rb"); - ff=romfopen("roms/i8580111/15f6639.bin","rb"); - if (!f || !ff) break; - for (c = 0x0000; c < 0x20000; c += 2) - { - rom[c] = getc(f); - rom[c+1] = getc(ff); - } - fclose(ff); - 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() { @@ -660,9 +80,6 @@ void resetreadlookup() } -int mmuflush=0; -int mmu_perm=4; - void flushmmucache() { int c; @@ -794,14 +211,18 @@ void mem_flush_write_page(uint32_t addr, uint32_t virt) } } -extern int output; - #define mmutranslate_read(addr) mmutranslatereal(addr,0) #define mmutranslate_write(addr) mmutranslatereal(addr,1) -int pctrans=0; +static inline uint32_t mmu_readl(uint32_t addr) +{ + return *(uint32_t *)&_mem_exec[addr >> 14][addr & 0x3fff]; +} -extern uint32_t testr[9]; +static inline void mmu_writel(uint32_t addr, uint32_t val) +{ + *(uint32_t *)&_mem_exec[addr >> 14][addr & 0x3fff] = val; +} uint32_t mmutranslatereal(uint32_t addr, int rw) { @@ -818,7 +239,7 @@ uint32_t mmutranslatereal(uint32_t addr, int rw) 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]; + temp = temp2 = mmu_readl(addr2); // 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))) { @@ -837,13 +258,38 @@ uint32_t mmutranslatereal(uint32_t addr, int rw) }*/ return -1; } - temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; + + if ((temp & 0x80) && (cr4 & CR4_PSE)) + { + /*4MB page*/ + if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3 && !cpl_override) || 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,pc,SS,ESP,ins,CPL,rw); + + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + + return -1; + } + + mmu_perm = temp & 4; + ((uint32_t *)ram)[addr2>>2] |= 0x20; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = mmu_readl((temp & ~0xfff) + ((addr >> 10) & 0xffc)); 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 (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && ((CPL == 3 && !cpl_override) || 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,pc,SS,ESP,ins,CPL,rw); - // dumpregs(); // exit(-1); // if (addr == 0x815F6E90) output = 3; @@ -864,8 +310,8 @@ uint32_t mmutranslatereal(uint32_t addr, int rw) return -1; } mmu_perm=temp&4; - ((uint32_t *)ram)[addr2>>2]|=0x20; - ((uint32_t *)ram)[((temp2&~0xFFF)+((addr>>10)&0xFFC))>>2]|=(rw?0x60:0x20); + mmu_writel(addr2, temp2 | 0x20); + mmu_writel((temp2 & ~0xfff) + ((addr >> 10) & 0xffc), temp | (rw ? 0x60 : 0x20)); // /*if (output) */pclog("Translate %08X %08X %08X %08X:%08X %08X\n",addr,(temp&~0xFFF)+(addr&0xFFF),temp,cs,pc,EDI); return (temp&~0xFFF)+(addr&0xFFF); @@ -880,12 +326,21 @@ uint32_t mmutranslate_noabrt(uint32_t addr, int rw) return -1; addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); - temp=temp2=((uint32_t *)ram)[addr2>>2]; + temp = temp2 = mmu_readl(addr2); if (!(temp&1)) return -1; - temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; + if ((temp & 0x80) && (cr4 & CR4_PSE)) + { + /*4MB page*/ + if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (CPL == 3 || cr0 & WP_FLAG))) + return -1; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = mmu_readl((temp & ~0xfff) + ((addr >> 10) & 0xffc)); temp3=temp&temp2; if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) @@ -971,41 +426,36 @@ void addwritelookup(uint32_t virt, uint32_t phys) 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]) { + if (read_mapping[a >> 14]->flags & MEM_MAPPING_ROM) + cpu_prefetch_cycles = cpu_rom_prefetch_cycles; + else + cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + 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_mapping_t *map; + mem_logical_addr = addr; if (cr0 >> 31) { @@ -1014,13 +464,17 @@ uint8_t readmembl(uint32_t addr) } addr &= rammask; - if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + map = read_mapping[addr >> 14]; + if (map && map->read_b) + return map->read_b(addr, map->p); // pclog("Bad readmembl %08X %04X:%08X\n", addr, CS, pc); return 0xFF; } void writemembl(uint32_t addr, uint8_t val) { + mem_mapping_t *map; + mem_logical_addr = addr; if (page_lookup[addr>>12]) @@ -1035,377 +489,399 @@ void writemembl(uint32_t addr, uint8_t val) } addr &= rammask; - if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + map = write_mapping[addr >> 14]; + if (map && map->write_b) + return map->write_b(addr, val, map->p); // else pclog("Bad writemembl %08X %02X %04X:%08X\n", addr, val, CS, pc); } -uint8_t readmemb386l(uint32_t seg, uint32_t addr) +uint16_t readmemwl(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; - } + mem_mapping_t *map; - addr &= rammask; + mem_logical_addr = addr; - 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) + if (addr & 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 (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xFFF) > 0xFFE) { - if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; - if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; + if (cr0 >> 31) + { + if (mmutranslate_read(addr) == 0xffffffff) return 0xffff; + if (mmutranslate_read(addr+1) == 0xffffffff) return 0xffff; + } + return readmembl(addr)|(readmembl(addr+1)<<8); } - 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; + else if (readlookup2[addr >> 12] != -1) + return *(uint16_t *)(readlookup2[addr >> 12] + addr); } if (cr0>>31) { - addr2 = mmutranslate_read(addr2); - if (addr2==0xFFFFFFFF) return 0xFFFF; + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) return 0xFFFF; } - addr2 &= rammask; + addr &= 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]) + map = read_mapping[addr >> 14]; + if (map) { - 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); + if (map->read_w) + return map->read_w(addr, map->p); + + if (map->read_b) + return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8); } -// pclog("Bad readmemwl %08X\n", addr2); + +// pclog("Bad readmemwl %08X\n", addr); return 0xffff; } -void writememwl(uint32_t seg, uint32_t addr, uint16_t val) +void writememwl(uint32_t addr, uint16_t val) { - uint32_t addr2 = mem_logical_addr = seg + addr; - if ((addr2&0xFFF)>0xFFE) + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 1) { - if (cr0>>31) + if (!cpu_cyrix_alignment || (addr & 7) == 7) + cycles -= timing_misaligned; + if ((addr & 0xFFF) > 0xFFE) { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+1) == 0xffffffff) return; + if (cr0 >> 31) + { + if (mmutranslate_write(addr) == 0xffffffff) return; + if (mmutranslate_write(addr+1) == 0xffffffff) return; + } + writemembl(addr,val); + writemembl(addr+1,val>>8); + return; } - if (is386) + else if (writelookup2[addr >> 12] != -1) { - writememb386l(seg,addr,val); - writememb386l(seg,addr+1,val>>8); + *(uint16_t *)(writelookup2[addr >> 12] + addr) = val; + return; } - else - { - writemembl(seg+addr,val); - writemembl(seg+addr+1,val>>8); - } - return; } - if (seg==-1) + if (page_lookup[addr>>12]) { - 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]); + page_lookup[addr>>12]->write_w(addr, val, page_lookup[addr>>12]); return; } if (cr0>>31) { - addr2 = mmutranslate_write(addr2); - if (addr2==0xFFFFFFFF) return; + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) return; } - addr2 &= rammask; + addr &= rammask; -/* if (addr2 >= 0xa0000 && addr2 < 0xc0000) - pclog("writememwl %08X %02X\n", addr2, val);*/ - - if (_mem_write_w[addr2 >> 14]) + map = write_mapping[addr >> 14]; + if (map) { - _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - return; + if (map->write_w) + map->write_w(addr, val, map->p); + else if (map->write_b) + { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + } } - 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); +// pclog("Bad writememwl %08X %04X\n", addr, val); } -uint32_t readmemll(uint32_t seg, uint32_t addr) +uint32_t readmemll(uint32_t addr) { - uint32_t addr2 = mem_logical_addr = seg + addr; - if ((addr2&0xFFF)>0xFFC) + mem_mapping_t *map; + + mem_logical_addr = addr; + + if (addr & 3) { - if (cr0>>31) + if (!cpu_cyrix_alignment || (addr & 7) > 4) + cycles -= timing_misaligned; + if ((addr&0xFFF)>0xFFC) { - if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; - if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; + if (cr0>>31) + { + if (mmutranslate_read(addr) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr+3) == 0xffffffff) return 0xffffffff; + } + return readmemwl(addr)|(readmemwl(addr+2)<<16); } - return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); + else if (readlookup2[addr >> 12] != -1) + return *(uint32_t *)(readlookup2[addr >> 12] + addr); } - 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; + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) return 0xFFFFFFFF; } - addr2&=rammask; + addr&=rammask; - if (_mem_read_l[addr2 >> 14]) return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + map = read_mapping[addr >> 14]; + if (map) + { + if (map->read_l) + return map->read_l(addr, map->p); - 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); + if (map->read_w) + return map->read_w(addr, map->p) | (map->read_w(addr + 2, map->p) << 16); -// pclog("Bad readmemll %08X\n", addr2); + if (map->read_b) + return map->read_b(addr, map->p) | (map->read_b(addr + 1, map->p) << 8) | + (map->read_b(addr + 2, map->p) << 16) | (map->read_b(addr + 3, map->p) << 24); + } + +// pclog("Bad readmemll %08X\n", addr); return 0xffffffff; } -void writememll(uint32_t seg, uint32_t addr, uint32_t val) +void writememll(uint32_t addr, uint32_t val) { - uint32_t addr2 = mem_logical_addr = seg + addr; + mem_mapping_t *map; - if ((addr2&0xFFF)>0xFFC) + mem_logical_addr = addr; + + if (addr & 3) { - if (cr0>>31) + if (!cpu_cyrix_alignment || (addr & 7) > 4) + cycles -= timing_misaligned; + if ((addr & 0xFFF) > 0xFFC) { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+3) == 0xffffffff) return; + if (cr0>>31) + { + if (mmutranslate_write(addr) == 0xffffffff) return; + if (mmutranslate_write(addr+3) == 0xffffffff) return; + } + writememwl(addr,val); + writememwl(addr+2,val>>16); + return; + } + else if (writelookup2[addr >> 12] != -1) + { + *(uint32_t *)(writelookup2[addr >> 12] + addr) = val; + return; } - writememwl(seg,addr,val); - writememwl(seg,addr+2,val>>16); - return; } - if (seg==-1) + if (page_lookup[addr>>12]) { - 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[addr>>12]->write_l(addr, val, page_lookup[addr>>12]); return; } if (cr0>>31) { - addr2 = mmutranslate_write(addr2); - if (addr2==0xFFFFFFFF) return; + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) return; } - addr2&=rammask; + addr&=rammask; -/* if (addr >= 0xa0000 && addr < 0xc0000) - pclog("writememll %08X %08X\n", addr, val);*/ - - if (_mem_write_l[addr2 >> 14]) + map = write_mapping[addr >> 14]; + if (map) { - _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); - return; + if (map->write_l) + map->write_l(addr, val, map->p); + else if (map->write_w) + { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + } + else if (map->write_b) + { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + } } - 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); +// pclog("Bad writememll %08X %08X\n", addr, val); } -uint64_t readmemql(uint32_t seg, uint32_t addr) +uint64_t readmemql(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); - } + mem_mapping_t *map; - if (seg==-1) + mem_logical_addr = addr; + + if (addr & 7) { - x86gpf("NULL segment", 0); - printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); - return -1; + cycles -= timing_misaligned; + if ((addr & 0xFFF) > 0xFF8) + { + if (cr0>>31) + { + if (mmutranslate_read(addr) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr+7) == 0xffffffff) return 0xffffffff; + } + return readmemll(addr)|((uint64_t)readmemll(addr+4)<<32); + } + else if (readlookup2[addr >> 12] != -1) + return *(uint64_t *)(readlookup2[addr >> 12] + addr); } if (cr0>>31) { - addr2 = mmutranslate_read(addr2); - if (addr2==0xFFFFFFFF) return 0xFFFFFFFF; + addr = mmutranslate_read(addr); + if (addr==0xFFFFFFFF) return 0xFFFFFFFF; } - addr2&=rammask; + addr&=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); + map = read_mapping[addr >> 14]; + if (map && map->read_l) + return map->read_l(addr, map->p) | ((uint64_t)map->read_l(addr + 4, map->p) << 32); - return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); + return readmemll(addr) | ((uint64_t)readmemll(addr+4)<<32); } -void writememql(uint32_t seg, uint32_t addr, uint64_t val) +void writememql(uint32_t addr, uint64_t val) { - uint32_t addr2 = mem_logical_addr = seg + addr; + mem_mapping_t *map; - if ((addr2 & 0xFFF) > 0xFF8) + mem_logical_addr = addr; + + if (addr & 7) { - if (cr0>>31) + cycles -= timing_misaligned; + if ((addr & 0xFFF) > 0xFF8) { - if (mmutranslate_write(addr2) == 0xffffffff) return; - if (mmutranslate_write(addr2+7) == 0xffffffff) return; + if (cr0>>31) + { + if (mmutranslate_write(addr) == 0xffffffff) return; + if (mmutranslate_write(addr+7) == 0xffffffff) return; + } + writememll(addr, val); + writememll(addr+4, val >> 32); + return; + } + else if (writelookup2[addr >> 12] != -1) + { + *(uint64_t *)(writelookup2[addr >> 12] + addr) = val; + return; } - writememll(seg, addr, val); - writememll(seg, addr+4, val >> 32); - return; } - if (seg==-1) + if (page_lookup[addr>>12]) { - 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]); + page_lookup[addr>>12]->write_l(addr, val, page_lookup[addr>>12]); + page_lookup[addr>>12]->write_l(addr + 4, val >> 32, page_lookup[addr>>12]); return; } if (cr0>>31) { - addr2 = mmutranslate_write(addr2); - if (addr2==0xFFFFFFFF) return; + addr = mmutranslate_write(addr); + if (addr==0xFFFFFFFF) return; } - addr2&=rammask; + addr&=rammask; - if (_mem_write_l[addr2 >> 14]) + map = write_mapping[addr >> 14]; + if (map) { - _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 (map->write_l) + { + map->write_l(addr, val, map->p); + map->write_l(addr + 4, val >> 32, map->p); + } + else if (map->write_w) + { + map->write_w(addr, val, map->p); + map->write_w(addr + 2, val >> 16, map->p); + map->write_w(addr + 4, val >> 32, map->p); + map->write_w(addr + 6, val >> 48, map->p); + } + else if (map->write_b) + { + map->write_b(addr, val, map->p); + map->write_b(addr + 1, val >> 8, map->p); + map->write_b(addr + 2, val >> 16, map->p); + map->write_b(addr + 3, val >> 24, map->p); + map->write_b(addr + 4, val >> 32, map->p); + map->write_b(addr + 5, val >> 40, map->p); + map->write_b(addr + 6, val >> 48, map->p); + map->write_b(addr + 7, val >> 56, map->p); + } } - 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); +// pclog("Bad writememql %08X %08X\n", addr, val); } uint8_t mem_readb_phys(uint32_t addr) { + mem_mapping_t *map = read_mapping[addr >> 14]; + mem_logical_addr = 0xffffffff; - if (_mem_read_b[addr >> 14]) - return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + if (map && map->read_b) + return map->read_b(addr, map->p); return 0xff; } +uint16_t mem_readw_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> 14]; + + mem_logical_addr = 0xffffffff; + + if (map && map->read_w) + return map->read_w(addr, map->p); + + return mem_readb_phys(addr) | (mem_readb_phys(addr + 1) << 8); +} +uint32_t mem_readl_phys(uint32_t addr) +{ + mem_mapping_t *map = read_mapping[addr >> 14]; + + mem_logical_addr = 0xffffffff; + + if (map && map->read_l) + return map->read_l(addr, map->p); + + return mem_readw_phys(addr) | (mem_readw_phys(addr + 2) << 16); +} void mem_writeb_phys(uint32_t addr, uint8_t val) { + mem_mapping_t *map = write_mapping[addr >> 14]; + mem_logical_addr = 0xffffffff; + + if (map && map->write_b) + map->write_b(addr, val, map->p); +} +void mem_writew_phys(uint32_t addr, uint16_t val) +{ + mem_mapping_t *map = write_mapping[addr >> 14]; - if (_mem_write_b[addr >> 14]) - _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); + mem_logical_addr = 0xffffffff; + + if (map && map->write_w && !(addr & 1)) + map->write_w(addr, val, map->p); + else + { + mem_writeb_phys(addr, val); + mem_writeb_phys(addr+1, val >> 8); + } +} +void mem_writel_phys(uint32_t addr, uint32_t val) +{ + mem_mapping_t *map = write_mapping[addr >> 14]; + + mem_logical_addr = 0xffffffff; + + if (map && map->write_l && !(addr & 3)) + map->write_l(addr, val, map->p); + else + { + mem_writew_phys(addr, val); + mem_writew_phys(addr+2, val >> 16); + } } uint8_t mem_read_ram(uint32_t addr, void *priv) @@ -1427,14 +903,59 @@ uint32_t mem_read_raml(uint32_t addr, void *priv) return *(uint32_t *)&ram[addr]; } +uint32_t purgable_page_list_head = 0; +int purgeable_page_count = 0; + +static inline int page_index(page_t *p) +{ + return ((uintptr_t)p - (uintptr_t)pages) / sizeof(page_t); +} +void page_add_to_evict_list(page_t *p) +{ +// pclog("page_add_to_evict_list: %08x %i\n", page_index(p), purgeable_page_count); + pages[purgable_page_list_head].evict_prev = page_index(p); + p->evict_next = purgable_page_list_head; + p->evict_prev = 0; + purgable_page_list_head = pages[purgable_page_list_head].evict_prev; + purgeable_page_count++; +} +void page_remove_from_evict_list(page_t *p) +{ +// pclog("page_remove_from_evict_list: %08x %i\n", page_index(p), purgeable_page_count); + if (!page_in_evict_list(p)) + fatal("page_remove_from_evict_list: not in evict list!\n"); + if (p->evict_prev) + pages[p->evict_prev].evict_next = p->evict_next; + else + purgable_page_list_head = p->evict_next; + if (p->evict_next) + pages[p->evict_next].evict_prev = p->evict_prev; + p->evict_prev = EVICT_NOT_IN_LIST; + purgeable_page_count--; +} + 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; + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t)1 << (addr & PAGE_BYTE_MASK_MASK); + +// pclog("mem_write_ramb_page: %08x %02x %08x %llx %llx\n", addr, val, cs+cpu_state.pc, p->dirty_mask, mask); p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + { +// pclog("ramb add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask); + page_add_to_evict_list(p); + } + p->byte_dirty_mask[byte_offset] |= byte_mask; + if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p)) + { +// pclog(" ramb add %08x %016llx %016llx\n", addr, p->byte_code_present_mask[byte_offset], byte_mask); + page_add_to_evict_list(p); + } } } void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) @@ -1442,11 +963,38 @@ 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) + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t)1 << (addr & PAGE_BYTE_MASK_MASK); + + if ((addr & 0xf) == 0xf) mask |= (mask << 1); -// pclog("mem_write_ramw_page: %08x %04x %08x\n", addr, val, cs+pc); - p->dirty_mask |= mask; +// pclog("mem_write_ramw_page: %08x %04x %08x %016llx %016llx %016llx %08x %08x %p\n", addr, val, cs+cpu_state.pc, p->dirty_mask[index], p->code_present_mask[index], mask, p->evict_prev, p->evict_next, p); *(uint16_t *)&p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + { +// pclog("ramw add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask); + page_add_to_evict_list(p); + } + if ((addr & PAGE_BYTE_MASK_MASK) == PAGE_BYTE_MASK_MASK) + { + p->byte_dirty_mask[byte_offset+1] |= 1; + if ((p->byte_code_present_mask[byte_offset+1] & 1) && !page_in_evict_list(p)) + { +// pclog("ramw add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask); + page_add_to_evict_list(p); + } + } + else + byte_mask |= (byte_mask << 1); + + p->byte_dirty_mask[byte_offset] |= byte_mask; + + if ((p->byte_code_present_mask[byte_offset] & byte_mask) && !page_in_evict_list(p)) + { +// pclog("ramw add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask); + page_add_to_evict_list(p); + } } } void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) @@ -1454,11 +1002,31 @@ 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) + int byte_offset = (addr >> PAGE_BYTE_MASK_SHIFT) & PAGE_BYTE_MASK_OFFSET_MASK; + uint64_t byte_mask = (uint64_t)0xf << (addr & PAGE_BYTE_MASK_MASK); + + if ((addr & 0xf) >= 0xd) mask |= (mask << 1); -// pclog("mem_write_raml_page: %08x %08x %08x\n", addr, val, cs+pc); - p->dirty_mask |= mask; +// pclog("mem_write_raml_page: %08x %08x %08x %016llx %016llx %016llx\n", addr, val, cs+cpu_state.pc, p->dirty_mask[index], p->code_present_mask[index], mask); *(uint32_t *)&p->mem[addr & 0xfff] = val; + p->dirty_mask |= mask; + p->byte_dirty_mask[byte_offset] |= byte_mask; + if (!page_in_evict_list(p) && ((p->code_present_mask & mask) || (p->byte_code_present_mask[byte_offset] & byte_mask))) + { +// pclog("raml add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask); + page_add_to_evict_list(p); + } + if ((addr & PAGE_BYTE_MASK_MASK) > (PAGE_BYTE_MASK_MASK-3)) + { + uint32_t byte_mask_2 = 0xf >> (4 - (addr & 3)); + + p->byte_dirty_mask[byte_offset+1] |= byte_mask_2; + if ((p->byte_code_present_mask[byte_offset+1] & byte_mask_2) && !page_in_evict_list(p)) + { +// pclog("raml add %08x %016llx %016llx\n", addr, p->code_present_mask[index], mask); + page_add_to_evict_list(p); + } + } } } @@ -1478,14 +1046,52 @@ void mem_write_raml(uint32_t addr, uint32_t val, void *priv) mem_write_raml_page(addr, val, &pages[addr >> 12]); } + +static uint32_t remap_start_addr; + +uint8_t mem_read_remapped(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} +uint16_t mem_read_remappedw(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} +uint32_t mem_read_remappedl(uint32_t addr, void *priv) +{ + addr = 0xA0000 + (addr - remap_start_addr); + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} + +void mem_write_remapped(uint32_t addr, uint8_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[oldaddr >> 12]); +} +void mem_write_remappedw(uint32_t addr, uint16_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[oldaddr >> 12]); +} +void mem_write_remappedl(uint32_t addr, uint32_t val, void *priv) +{ + uint32_t oldaddr = addr; + addr = 0xA0000 + (addr - remap_start_addr); + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[oldaddr >> 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,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]; } @@ -1531,8 +1137,15 @@ void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) 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; + page_t *p = &pages[start_addr >> 12]; + +//pclog("mem_invalidate: %08x\n", start_addr); + p->dirty_mask |= mask; + if ((p->code_present_mask & mask) && !page_in_evict_list(p)) + { +// pclog("invalidate add %08x %016llx %016llx\n", start_addr, p->code_present_mask[index], mask); + page_add_to_evict_list(p); + } } } @@ -1581,16 +1194,9 @@ static void mem_mapping_recalc(uint64_t base, uint64_t size) /*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; + read_mapping[c >> 14] = NULL; + write_mapping[c >> 14] = NULL; + _mem_exec[c >> 14] = NULL; } /*Walk mapping list*/ @@ -1609,24 +1215,16 @@ static void mem_mapping_recalc(uint64_t base, uint64_t size) 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; + read_mapping[c >> 14] = mapping; 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; + write_mapping[c >> 14] = mapping; } } } @@ -1746,144 +1344,104 @@ void mem_set_mem_state(uint32_t base, uint32_t size, int state) void mem_add_bios() { - if (AT) + if (AT || (romset == ROM_XI8088 && xi8088_bios_128kb())) { - 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[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x20000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 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 + (0x24000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 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 + (0x28000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 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 + (0x2c000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 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_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x30000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 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 + (0x34000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 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 + (0x38000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 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 + (0x3c000 & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 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); + mem_mapping_add(&bios_high_mapping[0], (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x20000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[1], (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x24000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[2], (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x28000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[3], (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x2c000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[4], (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x30000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[5], (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x34000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[6], (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x38000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[7], (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x3c000 & biosmask), MEM_MAPPING_ROM, 0); + if (biosmask == 0x3ffff) + mem_mapping_add(&bios_high_mapping[8], (AT && cpu_16bitbus) ? 0xfc0000 : 0xfffc0000, 0x20000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_ROM, 0); } int mem_a20_key = 0, mem_a20_alt = 0; -static int mem_a20_state = 1; +static int mem_a20_state = 2; -void mem_init() +static void mem_remap_top(int max_size) { int c; - - ram = malloc((mem_size + 384) * 1024); -// rom = malloc(0x20000); - readlookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); - writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); - 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 * 1024) >> 12); c++) + if (mem_size > 640) { - 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; + uint32_t start = (mem_size >= 1024) ? mem_size : 1024; + int size = mem_size - 640; + if (size > max_size) + size = max_size; + + remap_start_addr = start * 1024; + + for (c = ((start * 1024) >> 12); c < (((start + size) * 1024) >> 12); c++) + { + int offset = c - ((start * 1024) >> 12); + pages[c].mem = &ram[0xA0000 + (offset << 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; + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[offset * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[offset * 64]; + } + + mem_set_mem_state(start * 1024, size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_remapped_mapping, start * 1024, size * 1024, mem_read_remapped, mem_read_remappedw, mem_read_remappedl, mem_write_remapped, mem_write_remappedw, mem_write_remappedl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); } - - 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_256k() { - int c; - - for (c = ((mem_size * 1024) >> 12); c < (((mem_size + 256) * 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 + 256) / 256); c++) - { - isram[c] = 1; - if (c >= 0xa && c <= 0xd) - isram[c] = 0; - } - - mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 256 * 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); + mem_remap_top(256); } 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); + mem_remap_top(384); } -void mem_resize() +void mem_set_704kb() +{ + mem_set_mem_state(0x000000, (mem_size > 704) ? 0xb0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_set_addr(&ram_low_mapping, 0x00000, (mem_size > 704) ? 0xb0000 : mem_size * 1024); +} + +void mem_init() +{ + readlookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); + writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); + page_lookup = malloc((1 << 20) * sizeof(page_t *)); + + memset(ff_array, 0xff, sizeof(ff_array)); + + smram_enable = NULL; + smram_disable = NULL; +} + +void mem_alloc() { int c; free(ram); - ram = malloc((mem_size + 384) * 1024); - memset(ram, 0, (mem_size + 384) * 1024); + ram = malloc(mem_size * 1024); + memset(ram, 0, mem_size * 1024); + + free(byte_dirty_mask); + byte_dirty_mask = malloc((mem_size * 1024) / 8); + memset(byte_dirty_mask, 0, (mem_size * 1024) / 8); + free(byte_code_present_mask); + byte_code_present_mask = malloc((mem_size * 1024) / 8); + memset(byte_code_present_mask, 0, (mem_size * 1024) / 8); free(pages); pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); @@ -1894,22 +1452,15 @@ void mem_resize() 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; + pages[c].evict_prev = EVICT_NOT_IN_LIST; + pages[c].byte_dirty_mask = &byte_dirty_mask[c * 64]; + pages[c].byte_code_present_mask = &byte_code_present_mask[c * 64]; } - 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(page_lookup, 0, (1 << 20) * sizeof(page_t *)); + + memset(read_mapping, 0, sizeof(read_mapping)); + memset(write_mapping, 0, sizeof(write_mapping)); memset(_mem_exec, 0, sizeof(_mem_exec)); memset(&base_mapping, 0, sizeof(base_mapping)); @@ -1917,20 +1468,50 @@ void mem_resize() 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); + if (romset == ROM_XI8088) + { + // Xi 8088 UMBs are selected by DIP Switches + mem_set_mem_state(0x0a0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x0c0000, 0x08000, model_get_config_int("umb_c0000h_c7fff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + mem_set_mem_state(0x0c8000, 0x08000, model_get_config_int("umb_c8000h_cffff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + mem_set_mem_state(0x0d0000, 0x08000, model_get_config_int("umb_d0000h_d7fff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + mem_set_mem_state(0x0d8000, 0x08000, model_get_config_int("umb_d8000h_dffff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + mem_set_mem_state(0x0e0000, 0x08000, model_get_config_int("umb_e0000h_e7fff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + mem_set_mem_state(0x0e8000, 0x08000, model_get_config_int("umb_e8000h_effff") ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + mem_set_mem_state(0x0f0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + else + { + mem_set_mem_state(0x0a0000, 0x60000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } 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); + { + if (cpu_16bitbus && mem_size > 16256) + { + mem_set_mem_state(0x100000, (16256 - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_high_mapping, 0x100000, ((16256 - 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); + } + else + { + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + 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) // 640k - 768k is graphics RAM + mem_mapping_add(&ram_mid_mapping, 0xa0000, 0x60000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0xa0000, 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); + if (romset == ROM_IBMPS1_2011) + 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_alt = 0; mem_a20_recalc(); + + purgable_page_list_head = 0; + purgeable_page_count = 0; } void mem_reset_page_blocks() @@ -1942,8 +1523,8 @@ void mem_reset_page_blocks() 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; + pages[c].block = BLOCK_INVALID; + pages[c].block_2 = BLOCK_INVALID; } } @@ -1953,12 +1534,12 @@ void mem_a20_recalc() // pclog("A20 recalc %i %i\n", state, mem_a20_state); if (state && !mem_a20_state) { - rammask = 0xffffffff; + rammask = (AT && cpu_16bitbus) ? 0xffffff : 0xffffffff; flushmmucache(); } else if (!state && mem_a20_state) { - rammask = 0xffefffff; + rammask = (AT && cpu_16bitbus) ? 0xefffff : 0xffefffff; flushmmucache(); } // pclog("rammask now %08X\n", rammask); diff --git a/src/mem.h b/src/mem.h index 370be13..bd733e7 100644 --- a/src/mem.h +++ b/src/mem.h @@ -1,6 +1,8 @@ #ifndef _MEM_H_ #define _MEM_H_ +#include "x86.h" + typedef struct mem_mapping_t { struct mem_mapping_t *prev, *next; @@ -28,12 +30,13 @@ typedef struct mem_mapping_t #define MEM_MAPPING_EXTERNAL 1 /*Only present on internal bus (RAM)*/ #define MEM_MAPPING_INTERNAL 2 +/*Executing from ROM may involve additional wait states*/ +#define MEM_MAPPING_ROM 4 extern uint8_t *ram,*rom; extern uint8_t romext[32768]; extern int readlnum,writelnum; extern int memspeed[11]; -extern int nopageerrors; extern uint32_t biosmask; void mem_mapping_add(mem_mapping_t *mapping, @@ -79,7 +82,11 @@ extern int mem_a20_key; void mem_a20_recalc(); uint8_t mem_readb_phys(uint32_t addr); +uint16_t mem_readw_phys(uint32_t addr); +uint32_t mem_readl_phys(uint32_t addr); void mem_writeb_phys(uint32_t addr, uint8_t val); +void mem_writew_phys(uint32_t addr, uint16_t val); +void mem_writel_phys(uint32_t addr, uint32_t val); uint8_t mem_read_ram(uint32_t addr, void *priv); uint16_t mem_read_ramw(uint32_t addr, void *priv); @@ -100,10 +107,19 @@ 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]; +mem_mapping_t bios_high_mapping[9]; extern mem_mapping_t ram_high_mapping; +extern mem_mapping_t ram_remapped_mapping; +extern uint64_t *byte_dirty_mask; +extern uint64_t *byte_code_present_mask; + +#define PAGE_BYTE_MASK_SHIFT 6 +#define PAGE_BYTE_MASK_OFFSET_MASK 63 +#define PAGE_BYTE_MASK_MASK 63 + +#define EVICT_NOT_IN_LIST ((uint32_t)-1) typedef struct page_t { void (*write_b)(uint32_t addr, uint8_t val, struct page_t *p); @@ -112,18 +128,33 @@ typedef struct page_t uint8_t *mem; - struct codeblock_t *block, *block_2; + uint16_t block, block_2; /*Head of codeblock tree associated with this page*/ - struct codeblock_t *head; + uint16_t head; uint64_t code_present_mask, dirty_mask; + + uint32_t evict_prev, evict_next; + + uint64_t *byte_dirty_mask; + uint64_t *byte_code_present_mask; } page_t; extern page_t *pages; extern page_t **page_lookup; +extern uint32_t purgable_page_list_head; +static inline int page_in_evict_list(page_t *p) +{ + return (p->evict_prev != EVICT_NOT_IN_LIST); +} +void page_remove_from_evict_list(page_t *p); +void page_add_to_evict_list(page_t *p); + +int mem_addr_is_ram(uint32_t addr); + 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) @@ -139,17 +170,34 @@ static inline uint32_t get_phys(uint32_t addr) return addr & rammask; } - get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; + if (readlookup2[addr >> 12] != -1) + get_phys_phys = ((uintptr_t)readlookup2[addr >> 12] + (addr & ~0xfff)) - (uintptr_t)ram; + else + { + get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; + if (!cpu_state.abrt && mem_addr_is_ram(get_phys_phys)) + addreadlookup(get_phys_virt, get_phys_phys); + } + return get_phys_phys | (addr & 0xfff); // return mmutranslatereal(addr, 0) & rammask; } static inline uint32_t get_phys_noabrt(uint32_t addr) { + uint32_t phys_addr; + if (!(cr0 >> 31)) return addr & rammask; - return mmutranslate_noabrt(addr, 0) & rammask; + if (readlookup2[addr >> 12] != -1) + return ((uintptr_t)readlookup2[addr >> 12] + addr) - (uintptr_t)ram; + + phys_addr = mmutranslate_noabrt(addr, 0) & rammask; + if (phys_addr != 0xffffffff && mem_addr_is_ram(phys_addr)) + addreadlookup(addr, phys_addr); + + return phys_addr; } void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr); @@ -163,6 +211,7 @@ 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; +extern mem_mapping_t ram_mid_mapping; void mem_remap_top_256k(); void mem_remap_top_384k(); @@ -172,7 +221,9 @@ void mem_flush_write_page(uint32_t addr, uint32_t virt); void mem_add_bios(); void mem_init(); -void mem_resize(); +void mem_alloc(); + +void mem_set_704kb(); void flushmmucache(); void flushmmucache_nopc(); @@ -184,5 +235,8 @@ void mmu_invalidate(uint32_t addr); int loadbios(); -extern unsigned char isram[0x10000]; +extern int purgeable_page_count; + +extern void (*smram_enable)(void); +extern void (*smram_disable)(void); #endif diff --git a/src/mem_bios.c b/src/mem_bios.c new file mode 100644 index 0000000..2b6b174 --- /dev/null +++ b/src/mem_bios.c @@ -0,0 +1,1192 @@ +#include +#include "ibm.h" +#include "mem.h" +#include "mem_bios.h" +#include "rom.h" +#include "video.h" +#include "xi8088.h" + +static void romfread(uint8_t *buf, size_t size, size_t count, FILE *fp) +{ + int result = fread(buf,size,count,fp); + if (result < count) + { + pclog("ROM read failed: Expected %d, read %d\n", count, result); + } +} + +static int mem_load_basic(char *path) +{ + char s[256]; + FILE *f; + + sprintf(s, "%s/ibm-basic-1.10.rom", path); + f = romfopen(s, "rb"); + if (!f) + { + sprintf(s, "%s/basicc11.f6", path); + f = romfopen(s, "rb"); + if (!f) return 1; /*I don't really care if BASIC is there or not*/ + romfread(rom + 0x6000, 8192, 1, f); + fclose(f); + sprintf(s, "%s/basicc11.f8", path); + f = romfopen(s, "rb"); + if (!f) return 0; /*But if some of it is there, then all of it must be*/ + romfread(rom + 0x8000, 8192, 1, f); + fclose(f); + sprintf(s, "%s/basicc11.fa", path); + f = romfopen(s, "rb"); + if (!f) return 0; + romfread(rom + 0xA000, 8192, 1, f); + fclose(f); + sprintf(s, "%s/basicc11.fc", path); + f = romfopen(s, "rb"); + if (!f) return 0; + romfread(rom + 0xC000, 8192, 1, f); + fclose(f); + } + else + { + romfread(rom + 0x6000, 32768, 1, f); + fclose(f); + } + + return 1; +} + +int loadbios() +{ + FILE *f=NULL,*ff=NULL; + int c; + + loadfont("mda.rom", FONT_MDA); + loadfont("wy700.rom", FONT_WY700); + loadfont("8x12.bin", FONT_MDSI); + loadfont("im1024font.bin", FONT_IM1024); + + biosmask = 0xffff; + + if (!rom) + rom = malloc(0x40000); + memset(romext,0x63,0x4000); + memset(rom, 0xff, 0x20000); + + pclog("Starting with romset %i\n", romset); + + switch (romset) + { + case ROM_PC1512: + f=romfopen("pc1512/40043.v1","rb"); + ff=romfopen("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); + loadfont("pc1512/40078.ic127", FONT_CGA); + return 1; + case ROM_PC1640: + f=romfopen("pc1640/40044.v3","rb"); + ff=romfopen("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("pc1640/40100","rb"); + if (!f) break; + fclose(f); + return 1; + case ROM_PC200: + f=romfopen("pc200/pc20v2.1","rb"); + ff=romfopen("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); + loadfont("pc200/40109.bin", FONT_PC200); + return 1; + case ROM_PPC512: + f=romfopen("ppc512/40107.v2","rb"); + ff=romfopen("ppc512/40108.v2","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); + loadfont("ppc512/40109.bin", FONT_PC200); + return 1; + case ROM_TANDY: + f=romfopen("tandy/tandy1t1.020","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + case ROM_TANDY1000HX: + f = romfopen("tandy1000hx/v020000.u12", "rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + case ROM_TANDY1000SL2: + f = romfopen("tandy1000sl2/8079047.hu1" ,"rb"); + ff = romfopen("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); + return 1; +/* case ROM_IBMPCJR: + f=fopen("pcjr/bios.rom","rb"); + romfread(rom+0xE000,8192,1,f); + fclose(f); + f=fopen("pcjr/basic.rom","rb"); + romfread(rom+0x6000,32768,1,f); + fclose(f); + break;*/ + case ROM_IBMXT: + f=romfopen("ibmxt/xt.rom","rb"); + if (!f) + { + f = romfopen("ibmxt/5000027.u19", "rb"); + ff = romfopen("ibmxt/1501512.u18","rb"); + if (!f || !ff) break; + romfread(rom, 0x8000, 1, f); + romfread(rom + 0x8000, 0x8000, 1, ff); + fclose(ff); + fclose(f); + return 1; + } + else + { + romfread(rom,65536,1,f); + fclose(f); + return 1; + } + break; + + case ROM_IBMPCJR: + f = romfopen("ibmpcjr/bios.rom","rb"); + if (!f) break; + romfread(rom, 0x10000, 1, f); + fclose(f); + return 1; + + case ROM_GENXT: + f=romfopen("genxt/pcxt.rom","rb"); + if (!f) break; + romfread(rom+0xE000,8192,1,f); + fclose(f); + if (!mem_load_basic("genxt")) + break; + return 1; + case ROM_DTKXT: + f=romfopen("dtk/dtk_erso_2.42_2764.bin","rb"); + if (!f) break; + romfread(rom+0xE000,8192,1,f); + fclose(f); + return 1; + case ROM_OLIM24: + f = romfopen("olivetti_m24/olivetti_m24_version_1.43_low.bin" ,"rb"); + ff = romfopen("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); + return 1; + + case ROM_PC2086: + f = romfopen("pc2086/40179.ic129" ,"rb"); + ff = romfopen("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("pc2086/40186.ic171", "rb"); + if (!f) break; + fclose(f); + biosmask = 0x3fff; + return 1; + + case ROM_PC3086: + f = romfopen("pc3086/fc00.bin" ,"rb"); + if (!f) break; + romfread(rom, 0x4000, 1, f); + fclose(f); + f = romfopen("pc3086/c000.bin", "rb"); + if (!f) break; + fclose(f); + biosmask = 0x3fff; + return 1; + + case ROM_PC5086: + f = romfopen("pc5086/sys_rom.bin" ,"rb"); + if (!f) break; + romfread(rom, 65536, 1, f); + fclose(f); + return 1; + + + case ROM_IBMAT: +/* f=romfopen("amic206.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1;*/ + case ROM_IBMAT386: + f = romfopen("ibmat/62x0820.u27", "rb"); + ff =romfopen("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); + return 1; + case ROM_CMDPC30: + f = romfopen("cmdpc30/commodore pc 30 iii even.bin", "rb"); + ff = romfopen("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; + return 1; + case ROM_DELL200: + f=romfopen("dells200/dell0.bin","rb"); + ff=romfopen("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("at386/at386.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1;*/ + case ROM_AMA932J: +// f=romfopen("at386/at386.bin","rb"); + f=romfopen("ama932j/ami.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + f=romfopen("ama932j/oti067.bin","rb"); + if (!f) break; + fclose(f); + return 1; + + case ROM_AMI386SX: +// f=romfopen("at386/at386.bin","rb"); + f=romfopen("ami386/ami386.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_AMI386DX_OPTI495: /*This uses the OPTi 82C495 chipset*/ + f=romfopen("ami386dx/opt495sx.ami","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + case ROM_MR386DX_OPTI495: /*This uses the OPTi 82C495 chipset*/ + f=romfopen("mr386dx/opt495sx.mr","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_ACER386: + f=romfopen("acer386/acer386.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + rom[0xB0]=0xB0-0x51; + rom[0x40d4]=0x51; /*PUSH CX*/ + f=romfopen("acer386/oti067.bin","rb"); + if (!f) break; + fclose(f); + return 1; + + case ROM_KMXC02: + f=romfopen("kmxc02/3ctm005.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_AMI286: + f=romfopen("ami286/amic206.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_TG286M: + f=romfopen("tg286m/ami.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_AWARD286: + f=romfopen("award286/award.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_GDC212M: + f=romfopen("gdc212m/gdc212m_72h.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_HYUNDAI_SUPER286TR: + f=romfopen("super286tr/award.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_GW286CT: + f=romfopen("gw286ct/2ctc001.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_SPC4200P: + f=romfopen("spc4200p/u8.01","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_SPC4216P: + f=romfopen("spc4216p/phoenix.bin","rb"); + if (!f) + { + f = romfopen("spc4216p/7101.u8", "rb"); + ff = romfopen("spc4216p/ac64.u10","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; + } + else + { + romfread(rom,65536,1,f); + + fclose(f); + return 1; + } + break; + + case ROM_SPC4620P: + f=romfopen("spc4620p/svb6120a_font.rom","rb"); + if (!f) break; + fclose(f); + f = romfopen("spc4620p/31005h.u8", "rb"); + ff = romfopen("spc4620p/31005h.u10","rb"); + if (f && ff) + { + 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; + } + break; + + case ROM_SPC6000A: + f = romfopen("spc6000a/3c80.u27", "rb"); + ff = romfopen("spc6000a/9f80.u26","rb"); + if (f && ff) + { + for (c = 0x8000; c < 0x10000; c += 2) + { + rom[c] = getc(f); + rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); + return 1; + } + break; + + case ROM_SPC6033P: + f=romfopen("spc6033p/svb6120a_font.rom","rb"); + if (!f) break; + fclose(f); + f=romfopen("spc6033p/phoenix.bin","rb"); + if (f) + { + fseek(f, 0x10000, SEEK_SET); + romfread(rom,65536,1,f); + + fclose(f); + return 1; + } + break; + + case ROM_EUROPC: +// return 0; + f=romfopen("europc/50145","rb"); + if (!f) break; + romfread(rom+0x8000,32768,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_IBMPC: + f=romfopen("ibmpc/pc102782.bin","rb"); + if (!f) break; +// f=fopen("pc081682.bin","rb"); + romfread(rom+0xE000,8192,1,f); + fclose(f); + if (!mem_load_basic("ibmpc")) + break; + return 1; + + case ROM_MEGAPC: + f = romfopen("megapc/41651-bios lo.u18", "rb"); + ff = romfopen("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("ami486/ami486.bin","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + //is486=1; + return 1; + + case ROM_WIN486: +// f=romfopen("win486/win486.bin","rb"); + f=romfopen("win486/ali1429g.amw","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + //is486=1; + return 1; + + case ROM_PCI486: + f=romfopen("hot-433/hot-433.ami","rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_SIS496: + f = romfopen("sis496/sis496-1.awa", "rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + pclog("Load SIS496 %x %x\n", rom[0x1fff0], rom[0xfff0]); + return 1; + + case ROM_P55VA: + f = romfopen("p55va/va021297.bin", "rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55TVP4: + f = romfopen("p55tvp4/tv5i0204.awd", "rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_430VX: +// f = romfopen("430vx/ga586atv.bin", "rb"); +// f = fopen("430vx/vx29.bin", "rb"); + f = romfopen("430vx/55xwuq0e.bin", "rb"); +// f=romfopen("430vx/430vx","rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_P55T2P4: + f = romfopen("p55t2p4/0207_j2.bin", "rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_REVENGE: + f = romfopen("revenge/1009af2_.bio", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("revenge/1009af2_.bi1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom, 0xc000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + case ROM_ENDEAVOR: + f = romfopen("endeavor/1006cb0_.bio", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("endeavor/1006cb0_.bi1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom, 0xd000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_IBMPS1_2011: +#if 0 + f=romfopen("ibmps1es/ibm_1057757_24-05-90.bin","rb"); + ff=romfopen("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("ibmps1es/f80000.bin", "rb"); + if (!f) break; + fseek(f, 0x60000, SEEK_SET); + romfread(rom, 0x20000, 1, f); + fclose(f); +//#endif + biosmask = 0x1ffff; + return 1; + + case ROM_IBMPS1_2121: + f = romfopen("ibmps1_2121/fc0000.bin", "rb"); + if (!f) break; + fseek(f, 0x20000, SEEK_SET); + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_DESKPRO_386: + f=romfopen("deskpro386/109592-005.u11.bin","rb"); + ff=romfopen("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; + return 1; + + case ROM_AMIXT: + f = romfopen("amixt/ami_8088_bios_31jan89.bin", "rb"); + if (!f) break; + romfread(rom + 0xE000, 8192, 1, f); + fclose(f); + return 1; + + case ROM_LTXT: + f = romfopen("ltxt/27c64.bin", "rb"); + if (!f) break; + romfread(rom + 0xE000, 8192, 1, f); + fclose(f); + if (!mem_load_basic("ltxt")) + break; + return 1; + + case ROM_LXT3: + f = romfopen("lxt3/27c64d.bin", "rb"); + if (!f) break; + romfread(rom + 0xE000, 8192, 1, f); + fclose(f); + if (!mem_load_basic("lxt3")) + break; + return 1; + + case ROM_PX386: /*Phoenix 80386 BIOS*/ + f=romfopen("px386/3iip001l.bin","rb"); + ff=romfopen("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); + return 1; + + case ROM_DTK386: /*Uses NEAT chipset*/ + f = romfopen("dtk386/3cto001.bin", "rb"); + if (!f) break; + romfread(rom, 65536, 1, f); + fclose(f); + return 1; + + case ROM_PXXT: + f = romfopen("pxxt/000p001.bin", "rb"); + if (!f) break; + romfread(rom + 0xE000, 8192, 1, f); + fclose(f); + return 1; + + case ROM_JUKOPC: + f = romfopen("jukopc/000o001.bin", "rb"); + if (!f) break; + romfread(rom + 0xE000, 8192, 1, f); + fclose(f); + return 1; + + case ROM_IBMPS2_M30_286: + f = romfopen("ibmps2_m30_286/33f5381a.bin", "rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_IBMPS2_M50: + f=romfopen("i8550021/90x7423.zm14","rb"); + ff=romfopen("i8550021/90x7426.zm16","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); + f=romfopen("i8550021/90x7420.zm13","rb"); + ff=romfopen("i8550021/90x7429.zm18","rb"); + if (!f || !ff) break; + for (c = 0x10000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_IBMPS2_M55SX: + f=romfopen("i8555081/33f8146.zm41","rb"); + ff=romfopen("i8555081/33f8145.zm40","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_IBMPS2_M80: + f=romfopen("i8580111/15f6637.bin","rb"); + ff=romfopen("i8580111/15f6639.bin","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ATARIPC3: + f=romfopen("ataripc3/AWARD_ATARI_PC_BIOS_3.08.BIN","rb"); + if (!f) break; + romfread(rom+0x8000,32768,1,f); + fclose(f); + return 1; + + case ROM_IBMXT286: + f = romfopen("ibmxt286/BIOS_5162_21APR86_U34_78X7460_27256.BIN", "rb"); + ff =romfopen("ibmxt286/BIOS_5162_21APR86_U35_78X7461_27256.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_EPSON_PCAX: + f = romfopen("epson_pcax/EVAX", "rb"); + ff = romfopen("epson_pcax/ODAX", "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; + return 1; + + case ROM_EPSON_PCAX2E: + f = romfopen("epson_pcax2e/EVAXE", "rb"); + ff = romfopen("epson_pcax2e/ODAXE", "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_EPSON_PCAX3: + f = romfopen("epson_pcax3/EVAX3", "rb"); + ff = romfopen("epson_pcax3/ODAX3", "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_T3100E: + loadfont("t3100e/t3100e_font.bin", FONT_T3100E); + f=romfopen("t3100e/t3100e.rom","rb"); + if (!f) break; + romfread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_T1000: + loadfont("t1000/t1000font.rom", FONT_CGA); + f=romfopen("t1000/t1000.rom","rb"); + if (!f) break; + romfread(rom, 0x8000,1,f); + memcpy(rom + 0x8000, rom, 0x8000); + biosmask = 0x7fff; + fclose(f); + return 1; + + case ROM_T1200: + loadfont("t1200/t1000font.rom", FONT_CGA); + f=romfopen("t1200/t1200_019e.ic15.bin","rb"); + if (!f) break; + romfread(rom, 0x8000,1,f); + memcpy(rom + 0x8000, rom, 0x8000); + biosmask = 0x7fff; + fclose(f); + return 1; + + case ROM_PB_L300SX: + f = romfopen("pb_l300sx/pb_l300sx.bin", "rb"); + if (!f) break; + romfread(rom, 65536, 1, f); + fclose(f); + return 1; + + case ROM_NCR_PC4I: + f=romfopen("ncr_pc4i/NCR_PC4i_BIOSROM_1985.BIN" ,"rb"); + if (!f) break; + romfread(rom, 0x4000, 1, f); + fclose(f); + biosmask = 0x3fff; + return 1; + + case ROM_TO16_PC: + f=romfopen("to16_pc/TO16_103.bin","rb"); + if (!f) break; + romfread(rom+0x8000,32768,1,f); + fclose(f); + return 1; + + case ROM_COMPAQ_PII: + f = romfopen("compaq_pii/109740-001.rom", "rb"); + ff = romfopen("compaq_pii/109739-001.rom", "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; + return 1; + + case ROM_ELX_PC425X: + /*PC-425X uses a single ROM chip containing both main and video BIOSes. + First 32kb is video BIOS, next 32kb is blank, last 64kb is main BIOS. + Alternatively, seperate BIOS + video BIOS dumps are supported.*/ + f = romfopen("elx_pc425x/elx_pc425x.bin", "rb"); + if (!f) + { + if (!rom_present("elx_pc425x/elx_pc425x_vbios.bin")) + break; + f = romfopen("elx_pc425x/elx_pc425x_bios.bin", "rb"); + if (!f) + break; + } + else + fseek(f, 0x10000, SEEK_SET); + romfread(rom, 65536, 1, f); + fclose(f); + return 1; + + case ROM_PB570: + if (!rom_present("pb570/gd5430.bin")) + break; + f = romfopen("pb570/1007by0r.bio", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("pb570/1007by0r.bi1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom, 0xc000, 1, f); + romfread(rom+0xc000, 0x1000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ZAPPA: + f = romfopen("zappa/1006bs0_.bio", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("zappa/1006bs0_.bi1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom, 0xd000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + // keep separate from generic Zappa because there is a BIOS logo + // in flash.bin + case ROM_ITAUTEC_INFOWAYM: +// if (!rom_present("infowaym/gd5434.bin")) +// break; + f = romfopen("infowaym/1006bs0_.bio", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("infowaym/1006bs0_.bi1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom, 0xd000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_PB520R: + if (!rom_present("pb520r/gd5434.bin")) + break; + f = romfopen("pb520r/1009bc0r.bio", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("pb520r/1009bc0r.bi1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom, 0xc000, 1, f); + romfread(rom+0xc000, 0x1000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_COMPAQ_PIP: + f=romfopen("compaq_pip/Compaq Portable Plus 100666-001 Rev C.bin","rb"); + if (!f) break; + romfread(rom + 0xE000, 8192, 1, f); + fclose(f); + return 1; + + case ROM_XI8088: + f = romfopen("xi8088/bios-xi8088.bin", "rb"); /* use the bios without xt-ide because it's configurable in pcem */ + if (!f) break; + if (xi8088_bios_128kb()) + { + /* high bit is flipped in xi8088 */ + romfread(rom + 0x10000, 0x10000, 1, f); + romfread(rom, 0x10000, 1, f); + biosmask = 0x1ffff; + } + else + { + /* smaller bios, more UMBs */ + romfread(rom, 0x10000, 1, f); + } + fclose(f); + return 1; + + case ROM_IBMPS2_M70_TYPE3: + f = romfopen("ibmps2_m70_type3/70-a_even.bin","rb"); + ff = romfopen("ibmps2_m70_type3/70-a_odd.bin","rb"); + if (!f || !ff) + break; + for (c = 0x0000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_IBMPS2_M70_TYPE4: + f = romfopen("ibmps2_m70_type4/70-b_even.bin","rb"); + ff = romfopen("ibmps2_m70_type4/70-b_odd.bin","rb"); + if (!f || !ff) + break; + for (c = 0x0000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_TULIP_TC7: + f = romfopen("tulip_tc7/tc7be.bin", "rb"); + ff = romfopen("tulip_tc7/tc7bo.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; + return 1; + + case ROM_ZD_SUPERS: /* [8088] Zenith Data Systems SupersPort */ + f=romfopen("zdsupers/z184m v3.1d.10d","rb"); + if (!f) break; + romfread(rom, 32768, 1, f); + fclose(f); + biosmask = 0x7fff; + return 1; + + case ROM_PB410A: + f = romfopen("pb410a/PB410A.080337.4ABF.U25.bin","rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_BULL_MICRAL_45: + f = romfopen("bull_micral_45/even.fil", "rb"); + ff = romfopen("bull_micral_45/odd.fil", "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_FIC_VA503P: + f = romfopen("fic_va503p/je4333.bin","rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_CBM_SL386SX25: + f = romfopen("cbm_sl386sx25/f000.rom", "rb"); + if (!f) break; + romfread(rom, 0x10000, 1, f); + fclose(f); + return 1; + + case ROM_IBMPS1_2133_451: + f = romfopen("ibmps1_2133/PS1_2133_52G2974_ROM.bin", "rb"); + if (!f) break; + romfread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ECS_386_32: + f = romfopen("ecs386_32/386_32_even.bin", "rb"); + ff = romfopen("ecs386_32/386_32_odd.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_LEDGE_MODELM: + f = romfopen("leadingedge_modelm/Leading Edge - Model M - BIOS ROM - Version 4.71.bin","rb"); + if (!f) break; + romfread(rom, 0x4000, 1, f); + fclose(f); + biosmask = 0x3fff; + return 1; + + case ROM_DESKPRO: + f = romfopen("deskpro/Compaq - BIOS - Revision J - 106265-002.bin","rb"); + if (!f) break; + romfread(rom, 0x2000, 1, f); + fclose(f); + biosmask = 0x1fff; + return 1; + + case ROM_VS440FX: + f = romfopen("vs440fx/1018CS1_.BIO", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("vs440fx/1018CS1_.BI1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x00000, 0x10000, 1, f); + fclose(f); + f = romfopen("vs440fx/1018CS1_.BI2", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x30000, 0x10000, 1, f); + fclose(f); + f = romfopen("vs440fx/1018CS1_.BI3", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x20000, 0x0a000, 1, f); + fclose(f); + + f = romfopen("vs440fx/1018CS1_.RCV", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + romfread(rom + 0x2c000, 0x04000, 1, f); + fclose(f); + + biosmask = 0x3ffff; + return 1; + + case ROM_GA686BX: + f = romfopen("ga686bx/6BX.F2a", "rb"); + if (!f) break; + romfread(rom, 0x40000, 1, f); + fclose(f); + + biosmask = 0x3ffff; + return 1; + } + printf("Failed to load ROM!\n"); + if (f) fclose(f); + if (ff) fclose(ff); + return 0; +} diff --git a/src/mem_bios.h b/src/mem_bios.h new file mode 100644 index 0000000..e3fc1f8 --- /dev/null +++ b/src/mem_bios.h @@ -0,0 +1 @@ +int loadbios(); diff --git a/src/mfm_at.c b/src/mfm_at.c index f2099a1..9293f18 100644 --- a/src/mfm_at.c +++ b/src/mfm_at.c @@ -11,6 +11,7 @@ #include "ibm.h" #include "device.h" +#include "hdd_file.h" #include "io.h" #include "pic.h" #include "timer.h" @@ -20,6 +21,14 @@ #define IDE_TIME (TIMER_USEC*10)//(5 * 100 * (1 << TIMER_SHIFT)) +/*Rough estimate - MFM drives spin at 3600 RPM, with 17 sectors per track, + meaning (3600/60)*17 = 1020 sectors per second, or 980us per sector. + + This is required for OS/2 on slow 286 systems, as the hard drive formatter + will crash with 'internal processing error' if write sector interrupts are too + close in time*/ +#define SECTOR_TIME (TIMER_USEC * 980) + #define STAT_ERR 0x01 #define STAT_INDEX 0x02 #define STAT_CORRECTED_DATA 0x04 @@ -45,16 +54,14 @@ #define CMD_DIAGNOSE 0x90 #define CMD_SET_PARAMETERS 0x91 -extern char ide_fn[4][512]; +extern char ide_fn[7][512]; typedef struct mfm_drive_t { - int spt, hpc; - int tracks; int cfg_spt; int cfg_hpc; int current_cylinder; - FILE *hdfile; + hdd_file_t hdd_file; } mfm_drive_t; typedef struct mfm_t @@ -71,7 +78,7 @@ typedef struct mfm_t uint16_t buffer[256]; int irqstat; - int callback; + pc_timer_t callback_timer; mfm_drive_t drives[2]; } mfm_t; @@ -123,12 +130,12 @@ static int mfm_get_sector(mfm_t *mfm, off64_t *addr) pclog("mfm_get_sector: past end of configured sectors\n"); return 1; } - if (mfm->head > drive->hpc) + if (mfm->head > drive->hdd_file.hpc) { pclog("mfm_get_sector: past end of heads\n"); return 1; } - if (mfm->sector >= drive->spt+1) + if (mfm->sector >= drive->hdd_file.spt+1) { pclog("mfm_get_sector: past end of sectors\n"); return 1; @@ -156,52 +163,12 @@ static void mfm_next_sector(mfm_t *mfm) { mfm->head = 0; mfm->cylinder++; - if (drive->current_cylinder < drive->tracks) + if (drive->current_cylinder < drive->hdd_file.tracks) drive->current_cylinder++; } } } -static void loadhd(mfm_t *mfm, int d, const char *fn) -{ - mfm_drive_t *drive = &mfm->drives[d]; - - if (drive->hdfile == NULL) - { - /* Try to open existing hard disk image */ - drive->hdfile = fopen64(fn, "rb+"); - if (drive->hdfile == NULL) - { - /* Failed to open existing hard disk image */ - if (errno == ENOENT) - { - /* Failed because it does not exist, - so try to create new file */ - drive->hdfile = fopen64(fn, "wb+"); - if (drive->hdfile == NULL) - { - pclog("Cannot create file '%s': %s", - fn, strerror(errno)); - return; - } - } - else - { - /* Failed for another reason */ - pclog("Cannot open file '%s': %s", - fn, strerror(errno)); - return; - } - } - } - - drive->spt = hdc[d].spt; - drive->hpc = hdc[d].hpc; - drive->tracks = hdc[d].tracks; -} - - - void mfm_write(uint16_t port, uint8_t val, void *p) { mfm_t *mfm = (mfm_t *)p; @@ -236,14 +203,14 @@ void mfm_write(uint16_t port, uint8_t val, void *p) case 0x1F6: /* Drive/Head */ mfm->head = val & 0xF; mfm->drive_sel = (val & 0x10) ? 1 : 0; - if (mfm->drives[mfm->drive_sel].hdfile == NULL) + if (mfm->drives[mfm->drive_sel].hdd_file.f == NULL) mfm->status = 0; else mfm->status = STAT_READY | STAT_DSC; return; case 0x1F7: /* Command register */ - if (mfm->drives[mfm->drive_sel].hdfile == NULL) + if (mfm->drives[mfm->drive_sel].hdd_file.f == NULL) fatal("Command on non-present drive\n"); mfm_irq_lower(mfm); @@ -256,18 +223,14 @@ void mfm_write(uint16_t port, uint8_t val, void *p) // pclog("Restore\n"); mfm->command &= ~0x0f; /*Mask off step rate*/ mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 200*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200*IDE_TIME); break; case CMD_SEEK: // pclog("Seek to cylinder %i\n", mfm->cylinder); mfm->command &= ~0x0f; /*Mask off step rate*/ mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 200*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200*IDE_TIME); break; default: @@ -280,9 +243,7 @@ void mfm_write(uint16_t port, uint8_t val, void *p) if (val & 2) fatal("Read with ECC\n"); mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 200*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200*IDE_TIME); break; case CMD_WRITE: case CMD_WRITE+1: @@ -299,9 +260,7 @@ void mfm_write(uint16_t port, uint8_t val, void *p) // pclog("Read verify %i sectors from sector %i cylinder %i head %i\n",mfm->secount,mfm->sector,mfm->cylinder,mfm->head); mfm->command &= ~1; mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 200 * IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200 * IDE_TIME); break; case CMD_FORMAT: @@ -312,24 +271,18 @@ void mfm_write(uint16_t port, uint8_t val, void *p) case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 30*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 30*IDE_TIME); break; case CMD_DIAGNOSE: /* Execute Drive Diagnostics */ mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 200*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200*IDE_TIME); break; default: pclog("Bad MFM command %02X\n", val); mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 200*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 200*IDE_TIME); break; } } @@ -338,9 +291,7 @@ void mfm_write(uint16_t port, uint8_t val, void *p) case 0x3F6: /* Device control */ if ((mfm->fdisk & 4) && !(val & 4)) { - timer_process(); - mfm->callback = 500*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, 500*IDE_TIME); mfm->reset = 1; mfm->status = STAT_BUSY; // pclog("MFM Reset\n"); @@ -348,9 +299,7 @@ void mfm_write(uint16_t port, uint8_t val, void *p) if (val & 4) { /*Drive held in reset*/ - timer_process(); - mfm->callback = 0; - timer_update_outstanding(); + timer_disable(&mfm->callback_timer); mfm->status = STAT_BUSY; } mfm->fdisk = val; @@ -372,9 +321,7 @@ void mfm_writew(uint16_t port, uint16_t val, void *p) { mfm->pos = 0; mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 6*IDE_TIME; - timer_update_outstanding(); + timer_set_delay_u64(&mfm->callback_timer, SECTOR_TIME); } } @@ -442,10 +389,8 @@ uint16_t mfm_readw(uint16_t port, void *p) if (mfm->secount) { mfm_next_sector(mfm); - mfm->status = STAT_BUSY; - timer_process(); - mfm->callback = 6*IDE_TIME; - timer_update_outstanding(); + mfm->status = STAT_BUSY | STAT_READY | STAT_DSC; + timer_set_delay_u64(&mfm->callback_timer, SECTOR_TIME); } } } @@ -458,10 +403,10 @@ static void do_seek(mfm_t *mfm) { mfm_drive_t *drive = &mfm->drives[mfm->drive_sel]; - if (mfm->cylinder < drive->tracks) + if (mfm->cylinder < drive->hdd_file.tracks) drive->current_cylinder = mfm->cylinder; else - drive->current_cylinder = drive->tracks-1; + drive->current_cylinder = drive->hdd_file.tracks-1; } void mfm_callback(void *p) @@ -469,10 +414,9 @@ void mfm_callback(void *p) mfm_t *mfm = (mfm_t *)p; mfm_drive_t *drive = &mfm->drives[mfm->drive_sel]; off64_t addr; - int c; // pclog("mfm_callback: command=%02x reset=%i\n", mfm->command, mfm->reset); - mfm->callback = 0; + if (mfm->reset) { mfm->status = STAT_READY | STAT_DSC; @@ -510,14 +454,13 @@ void mfm_callback(void *p) } // pclog("Read %i %i %i %08X\n",ide.cylinder,ide.head,ide.sector,addr); - fseeko64(drive->hdfile, addr * 512, SEEK_SET); - fread(mfm->buffer, 512, 1, drive->hdfile); + hdd_read_sectors(&drive->hdd_file, addr, 1, mfm->buffer); mfm->pos = 0; mfm->status = STAT_DRQ | STAT_READY | STAT_DSC; // 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; mfm_irq_raise(mfm); - readflash = 1; + readflash_set(READFLASH_HDC, mfm->drive_sel); break; case CMD_WRITE: @@ -529,8 +472,7 @@ void mfm_callback(void *p) mfm_irq_raise(mfm); break; } - fseeko64(drive->hdfile, addr * 512, SEEK_SET); - fwrite(mfm->buffer, 512, 1, drive->hdfile); + hdd_write_sectors(&drive->hdd_file, addr, 1, mfm->buffer); mfm_irq_raise(mfm); mfm->secount = (mfm->secount - 1) & 0xff; if (mfm->secount) @@ -541,7 +483,7 @@ void mfm_callback(void *p) } else mfm->status = STAT_READY | STAT_DSC; - readflash = 1; + readflash_set(READFLASH_HDC, mfm->drive_sel); break; case CMD_VERIFY: @@ -550,7 +492,7 @@ void mfm_callback(void *p) mfm->status = STAT_READY | STAT_DSC; // pclog("Read verify callback %i %i %i offset %08X %i left\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount); mfm_irq_raise(mfm); - readflash=1; + readflash_set(READFLASH_HDC, mfm->drive_sel); break; case CMD_FORMAT: @@ -562,15 +504,10 @@ void mfm_callback(void *p) mfm_irq_raise(mfm); break; } - fseeko64(drive->hdfile, addr * 512, SEEK_SET); - memset(mfm->buffer, 0, 512); - for (c = 0; c < mfm->secount; c++) - { - fwrite(mfm->buffer, 512, 1, drive->hdfile); - } + hdd_format_sectors(&drive->hdd_file, addr, mfm->secount); mfm->status = STAT_READY | STAT_DSC; mfm_irq_raise(mfm); - readflash = 1; + readflash_set(READFLASH_HDC, mfm->drive_sel); break; case CMD_DIAGNOSE: @@ -601,8 +538,8 @@ void *mfm_init() mfm_t *mfm = malloc(sizeof(mfm_t)); memset(mfm, 0, sizeof(mfm_t)); - loadhd(mfm, 0, ide_fn[0]); - loadhd(mfm, 1, ide_fn[1]); + hdd_load(&mfm->drives[0].hdd_file, 0, ide_fn[0]); + hdd_load(&mfm->drives[1].hdd_file, 1, ide_fn[1]); mfm->status = STAT_READY | STAT_DSC; mfm->error = 1; /*No errors*/ @@ -611,7 +548,7 @@ void *mfm_init() io_sethandler(0x01f1, 0x0007, mfm_read, NULL, NULL, mfm_write, NULL, NULL, mfm); io_sethandler(0x03f6, 0x0001, NULL, NULL, NULL, mfm_write, NULL, NULL, mfm); - timer_add(mfm_callback, &mfm->callback, &mfm->callback, mfm); + timer_add(&mfm->callback_timer, mfm_callback, mfm, 0); return mfm; } @@ -619,15 +556,9 @@ void *mfm_init() void mfm_close(void *p) { mfm_t *mfm = (mfm_t *)p; - int d; - - for (d = 0; d < 2; d++) - { - mfm_drive_t *drive = &mfm->drives[d]; - - if (drive->hdfile != NULL) - fclose(drive->hdfile); - } + + hdd_close(&mfm->drives[0].hdd_file); + hdd_close(&mfm->drives[1].hdd_file); free(mfm); } diff --git a/src/mfm_xebec.c b/src/mfm_xebec.c index 7a65a31..51cec9e 100644 --- a/src/mfm_xebec.c +++ b/src/mfm_xebec.c @@ -12,6 +12,7 @@ #include "device.h" #include "dma.h" +#include "hdd_file.h" #include "io.h" #include "mem.h" #include "pic.h" @@ -22,7 +23,7 @@ #define XEBEC_TIME (2000 * TIMER_USEC) -extern char ide_fn[4][512]; +extern char ide_fn[7][512]; enum { @@ -39,20 +40,18 @@ enum typedef struct mfm_drive_t { - int spt, hpc; - int tracks; int cfg_spt; int cfg_hpc; int cfg_cyl; int current_cylinder; - FILE *hdfile; + hdd_file_t hdd_file; } mfm_drive_t; typedef struct xebec_t { rom_t bios_rom; - int callback; + pc_timer_t callback_timer; int state; @@ -144,7 +143,7 @@ static uint8_t xebec_read(uint16_t port, void *p) // pclog("Read all data\n"); xebec->status = STAT_BSY; xebec->state = STATE_SENT_DATA; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); } break; @@ -191,7 +190,7 @@ static void xebec_write(uint16_t port, uint8_t val, void *p) { xebec->status = STAT_BSY; xebec->state = STATE_START_COMMAND; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); // pclog("Command %02x\n", xebec->command[0]); } break; @@ -208,7 +207,7 @@ static void xebec_write(uint16_t port, uint8_t val, void *p) // pclog("Got data\n"); xebec->status = STAT_BSY; xebec->state = STATE_RECEIVED_DATA; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); } break; @@ -271,7 +270,7 @@ static int xebec_get_sector(xebec_t *xebec, off64_t *addr) xebec->error = ERR_ILLEGAL_SECTOR_ADDRESS; return 1; } - if (xebec->head > drive->hpc) + if (xebec->head > drive->hdd_file.hpc) { pclog("mfm_get_sector: past end of heads\n"); xebec->error = ERR_ILLEGAL_SECTOR_ADDRESS; @@ -315,23 +314,21 @@ static void xebec_callback(void *p) xebec_t *xebec = (xebec_t *)p; mfm_drive_t *drive; - xebec->callback = 0; - xebec->drive_sel = (xebec->command[1] & 0x20) ? 1 : 0; xebec->completion_byte = xebec->drive_sel & 0x20; drive = &xebec->drives[xebec->drive_sel]; - + switch (xebec->command[0]) { case CMD_TEST_DRIVE_READY: - if (!drive->hdfile) + if (!drive->hdd_file.f) xebec_error(xebec, ERR_NOT_READY); xebec_complete(xebec); break; case CMD_RECALIBRATE: - if (!drive->hdfile) + if (!drive->hdd_file.f) xebec_error(xebec, ERR_NOT_READY); else { @@ -391,7 +388,7 @@ static void xebec_callback(void *p) xebec_complete(xebec); - readflash = 1; + readflash_set(READFLASH_HDC, xebec->drive_sel); break; default: @@ -402,7 +399,6 @@ static void xebec_callback(void *p) case CMD_FORMAT_TRACK: { off64_t addr; - int c; xebec->cylinder = xebec->command[3] | ((xebec->command[2] & 0xc0) << 2); drive->current_cylinder = (xebec->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : xebec->cylinder; @@ -417,10 +413,8 @@ static void xebec_callback(void *p) return; } - fseeko64(drive->hdfile, addr * 512, SEEK_SET); - for (c = 0; c < 17; c++) - fwrite(xebec->sector_buf, 512, 1, drive->hdfile); - + hdd_format_sectors(&drive->hdd_file, addr, 17); + xebec_complete(xebec); } break; @@ -448,12 +442,11 @@ static void xebec_callback(void *p) } // pclog("xebec Read %i,%i,%i\n", xebec->cylinder, xebec->head, xebec->sector); - fseeko64(drive->hdfile, addr * 512, SEEK_SET); - fread(xebec->sector_buf, 512, 1, drive->hdfile); - readflash = 1; + hdd_read_sectors(&drive->hdd_file, addr, 1, xebec->sector_buf); + readflash_set(READFLASH_HDC, xebec->drive_sel); } if (xebec->irq_dma_mask & DMA_ENA) - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); else { xebec->status = STAT_BSY | STAT_IO | STAT_REQ; @@ -473,12 +466,12 @@ static void xebec_callback(void *p) { pclog("CMD_READ_SECTORS out of data!\n"); xebec->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); return; } } xebec->state = STATE_SENT_DATA; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); } else fatal("Read sectors no DMA! - shouldn't get here\n"); @@ -503,15 +496,14 @@ static void xebec_callback(void *p) } // pclog("xebec Read %i,%i,%i\n", xebec->cylinder, xebec->head, xebec->sector); - - fseeko64(drive->hdfile, addr * 512, SEEK_SET); - fread(xebec->sector_buf, 512, 1, drive->hdfile); - readflash = 1; + + hdd_read_sectors(&drive->hdd_file, addr, 1, xebec->sector_buf); + readflash_set(READFLASH_HDC, xebec->drive_sel); xebec->state = STATE_SEND_DATA; if (xebec->irq_dma_mask & DMA_ENA) - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); else { xebec->status = STAT_BSY | STAT_IO | STAT_REQ; @@ -541,7 +533,7 @@ static void xebec_callback(void *p) xebec->data_pos = 0; xebec->data_len = 512; if (xebec->irq_dma_mask & DMA_ENA) - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); else xebec->status = STAT_BSY | STAT_REQ; break; @@ -558,7 +550,7 @@ static void xebec_callback(void *p) { pclog("CMD_WRITE_SECTORS out of data!\n"); xebec->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); return; } @@ -566,7 +558,7 @@ static void xebec_callback(void *p) } xebec->state = STATE_RECEIVED_DATA; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); } else fatal("Write sectors no DMA! - should never get here\n"); @@ -587,12 +579,11 @@ static void xebec_callback(void *p) } // pclog("xebec Write %i,%i,%i %i\n", xebec->cylinder, xebec->head, xebec->sector, xebec->drive_sel); - - fseeko64(drive->hdfile, addr * 512, SEEK_SET); - fwrite(xebec->sector_buf, 512, 1, drive->hdfile); + + hdd_write_sectors(&drive->hdd_file, addr, 1, xebec->sector_buf); } - readflash = 1; + readflash_set(READFLASH_HDC, xebec->drive_sel); xebec_next_sector(xebec); xebec->data_pos = 0; @@ -602,7 +593,7 @@ static void xebec_callback(void *p) { xebec->state = STATE_RECEIVE_DATA; if (xebec->irq_dma_mask & DMA_ENA) - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); else xebec->status = STAT_BSY | STAT_REQ; } @@ -616,7 +607,7 @@ static void xebec_callback(void *p) break; case CMD_SEEK: - if (!drive->hdfile) + if (!drive->hdd_file.f) xebec_error(xebec, ERR_NOT_READY); else { @@ -660,7 +651,7 @@ static void xebec_callback(void *p) xebec->data_pos = 0; xebec->data_len = 512; if (xebec->irq_dma_mask & DMA_ENA) - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); else xebec->status = STAT_BSY | STAT_REQ; break; @@ -678,7 +669,7 @@ static void xebec_callback(void *p) { pclog("CMD_WRITE_SECTOR_BUFFER out of data!\n"); xebec->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); return; } @@ -686,7 +677,7 @@ static void xebec_callback(void *p) } xebec->state = STATE_RECEIVED_DATA; - xebec->callback = XEBEC_TIME; + timer_set_delay_u64(&xebec->callback_timer, XEBEC_TIME); } else fatal("CMD_WRITE_SECTOR_BUFFER - should never get here!\n"); @@ -723,10 +714,10 @@ static void xebec_callback(void *p) xebec->data_len = 4; xebec->status = STAT_BSY | STAT_IO | STAT_REQ; memset(xebec->data, 0, 4); - xebec->data[0] = drive->tracks & 0xff; - xebec->data[1] = 17 | ((drive->tracks >> 2) & 0xc0); - xebec->data[2] = drive->hpc-1; - pclog("Get drive params %02x %02x %02x %i\n", xebec->data[0], xebec->data[1], xebec->data[2], drive->tracks); + xebec->data[0] = drive->hdd_file.tracks & 0xff; + xebec->data[1] = 17 | ((drive->hdd_file.tracks >> 2) & 0xc0); + xebec->data[2] = drive->hdd_file.hpc-1; + pclog("Get drive params %02x %02x %02x %i\n", xebec->data[0], xebec->data[1], xebec->data[2], drive->hdd_file.tracks); break; case STATE_SENT_DATA: @@ -747,9 +738,9 @@ static void xebec_callback(void *p) xebec->data_len = 16; xebec->status = STAT_BSY | STAT_IO | STAT_REQ; memset(xebec->data, 0, 16); - xebec->data[0x4] = drive->tracks & 0xff; - xebec->data[0x5] = (drive->tracks >> 8) & 0xff; - xebec->data[0xa] = drive->hpc; + xebec->data[0x4] = drive->hdd_file.tracks & 0xff; + xebec->data[0x5] = (drive->hdd_file.tracks >> 8) & 0xff; + xebec->data[0xa] = drive->hdd_file.hpc; break; case STATE_SENT_DATA: @@ -783,44 +774,6 @@ static void xebec_callback(void *p) } } -static void loadhd(xebec_t *xebec, int d, const char *fn) -{ - mfm_drive_t *drive = &xebec->drives[d]; - - if (drive->hdfile == NULL) - { - /* Try to open existing hard disk image */ - drive->hdfile = fopen64(fn, "rb+"); - if (drive->hdfile == NULL) - { - /* Failed to open existing hard disk image */ - if (errno == ENOENT) - { - /* Failed because it does not exist, - so try to create new file */ - drive->hdfile = fopen64(fn, "wb+"); - if (drive->hdfile == NULL) - { - pclog("Cannot create file '%s': %s", - fn, strerror(errno)); - return; - } - } - else - { - /* Failed for another reason */ - pclog("Cannot open file '%s': %s", - fn, strerror(errno)); - return; - } - } - } - - drive->spt = hdc[d].spt; - drive->hpc = hdc[d].hpc; - drive->tracks = hdc[d].tracks; -} - static struct { int tracks, hpc; @@ -842,14 +795,14 @@ static void xebec_set_switches(xebec_t *xebec) { mfm_drive_t *drive = &xebec->drives[d]; - if (!drive->hdfile) + if (!drive->hdd_file.f) continue; for (c = 0; c < 4; c++) { - if (drive->spt == 17 && - drive->hpc == xebec_hd_types[c].hpc && - drive->tracks == xebec_hd_types[c].tracks) + if (drive->hdd_file.spt == 17 && + drive->hdd_file.hpc == xebec_hd_types[c].hpc && + drive->hdd_file.tracks == xebec_hd_types[c].tracks) { xebec->switches |= (c << (d ? 0 : 2)); break; @@ -866,15 +819,15 @@ static void *xebec_init() xebec_t *xebec = malloc(sizeof(xebec_t)); memset(xebec, 0, sizeof(xebec_t)); - loadhd(xebec, 0, ide_fn[0]); - loadhd(xebec, 1, ide_fn[1]); + hdd_load(&xebec->drives[0].hdd_file, 0, ide_fn[0]); + hdd_load(&xebec->drives[1].hdd_file, 1, ide_fn[1]); xebec_set_switches(xebec); - rom_init(&xebec->bios_rom, "roms/ibm_xebec_62x0822_1985.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&xebec->bios_rom, "ibm_xebec_62x0822_1985.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); io_sethandler(0x0320, 0x0004, xebec_read, NULL, NULL, xebec_write, NULL, NULL, xebec); - timer_add(xebec_callback, &xebec->callback, &xebec->callback, xebec); + timer_add(&xebec->callback_timer, xebec_callback, xebec, 0); return xebec; } @@ -882,22 +835,16 @@ static void *xebec_init() static void xebec_close(void *p) { xebec_t *xebec = (xebec_t *)p; - int d; - - for (d = 0; d < 2; d++) - { - mfm_drive_t *drive = &xebec->drives[d]; - - if (drive->hdfile != NULL) - fclose(drive->hdfile); - } + hdd_close(&xebec->drives[0].hdd_file); + hdd_close(&xebec->drives[1].hdd_file); + free(xebec); } static int xebec_available() { - return rom_present("roms/ibm_xebec_62x0822_1985.bin"); + return rom_present("ibm_xebec_62x0822_1985.bin"); } device_t mfm_xebec_device = @@ -918,26 +865,26 @@ static void *dtc_5150x_init() xebec_t *xebec = malloc(sizeof(xebec_t)); memset(xebec, 0, sizeof(xebec_t)); - loadhd(xebec, 0, ide_fn[0]); - loadhd(xebec, 1, ide_fn[1]); + hdd_load(&xebec->drives[0].hdd_file, 0, ide_fn[0]); + hdd_load(&xebec->drives[1].hdd_file, 1, ide_fn[1]); xebec->switches = 0xff; - xebec->drives[0].cfg_cyl = xebec->drives[0].tracks; - xebec->drives[0].cfg_hpc = xebec->drives[0].hpc; - xebec->drives[1].cfg_cyl = xebec->drives[1].tracks; - xebec->drives[1].cfg_hpc = xebec->drives[1].hpc; + xebec->drives[0].cfg_cyl = xebec->drives[0].hdd_file.tracks; + xebec->drives[0].cfg_hpc = xebec->drives[0].hdd_file.hpc; + xebec->drives[1].cfg_cyl = xebec->drives[1].hdd_file.tracks; + xebec->drives[1].cfg_hpc = xebec->drives[1].hdd_file.hpc; - rom_init(&xebec->bios_rom, "roms/dtc_cxd21a.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&xebec->bios_rom, "dtc_cxd21a.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); io_sethandler(0x0320, 0x0004, xebec_read, NULL, NULL, xebec_write, NULL, NULL, xebec); - timer_add(xebec_callback, &xebec->callback, &xebec->callback, xebec); + timer_add(&xebec->callback_timer, xebec_callback, xebec, 0); return xebec; } static int dtc_5150x_available() { - return rom_present("roms/dtc_cxd21a.bin"); + return rom_present("dtc_cxd21a.bin"); } device_t dtc_5150x_device = diff --git a/src/midi_alsa.c b/src/midi_alsa.c new file mode 100644 index 0000000..5b8a2cc --- /dev/null +++ b/src/midi_alsa.c @@ -0,0 +1,187 @@ +#include +#include "ibm.h" +#include "config.h" +#include "plat-midi.h" + +#define MAX_MIDI_DEVICES 128 + +static struct +{ + int card; + int device; + int sub; + char name[50]; +} midi_devices[MAX_MIDI_DEVICES]; + +static int midi_device_count = 0; + +static int midi_queried = 0; + +static snd_rawmidi_t *midiout = NULL; + +static void midi_query() +{ + int status; + int card = -1; + + midi_queried = 1; + + if ((status = snd_card_next(&card)) < 0) + return; + + if (card < 0) + return; /*No cards*/ + + while (card >= 0) + { + char *shortname; + + if ((status = snd_card_get_name(card, &shortname)) >= 0) + { + snd_ctl_t *ctl; + char name[32]; + + sprintf(name, "hw:%i", card); + + if ((status = snd_ctl_open(&ctl, name, 0)) >= 0) + { + int device = -1; + + do + { + status = snd_ctl_rawmidi_next_device(ctl, &device); + if (status >= 0 && device != -1) + { + snd_rawmidi_info_t *info; + int sub_nr, sub; + + snd_rawmidi_info_alloca(&info); + snd_rawmidi_info_set_device(info, device); + snd_rawmidi_info_set_stream(info, SND_RAWMIDI_STREAM_OUTPUT); + snd_ctl_rawmidi_info(ctl, info); + sub_nr = snd_rawmidi_info_get_subdevices_count(info); + pclog("sub_nr=%i\n",sub_nr); + + for (sub = 0; sub < sub_nr; sub++) + { + snd_rawmidi_info_set_subdevice(info, sub); + + if (snd_ctl_rawmidi_info(ctl, info) == 0) + { + pclog("%s: MIDI device=%i:%i:%i\n", shortname, card, device,sub); + + midi_devices[midi_device_count].card = card; + midi_devices[midi_device_count].device = device; + midi_devices[midi_device_count].sub = sub; + snprintf(midi_devices[midi_device_count].name, 50, "%s (%i:%i:%i)", shortname, card, device, sub); + midi_device_count++; + if (midi_device_count >= MAX_MIDI_DEVICES) + return; + } + } + } + } while (device >= 0); + } + } + + if (snd_card_next(&card) < 0) + break; + } +} + +void midi_init() +{ + char portname[32]; + int midi_id; + + if (!midi_queried) + midi_query(); + + midi_id = config_get_int(CFG_MACHINE, NULL, "midi", 0); + + sprintf(portname, "hw:%i,%i,%i", midi_devices[midi_id].card, + midi_devices[midi_id].device, + midi_devices[midi_id].sub); + pclog("Opening MIDI port %s\n", portname); + + if (snd_rawmidi_open(NULL, &midiout, portname, SND_RAWMIDI_SYNC) < 0) + { + pclog("Failed to open MIDI\n"); + return; + } +} + +void midi_close() +{ + if (midiout != NULL) + { + snd_rawmidi_close(midiout); + midiout = NULL; + } +} + +static int midi_pos, midi_len; +static uint8_t midi_command[4]; +static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 1}; +static int midi_insysex; +static uint8_t midi_sysex_data[65536]; + +void midi_write(uint8_t val) +{ + //pclog("Write MIDI %02x\n", val); + + if ((val & 0x80) && !(val == 0xf7 && midi_insysex)) + { + midi_pos = 0; + midi_len = midi_lengths[(val >> 4) & 7]; + midi_command[0] = midi_command[1] = midi_command[2] = midi_command[3] = 0; + if (val == 0xf0) + midi_insysex = 1; + } + + if (midi_insysex) + { + midi_sysex_data[midi_pos++] = val; + + if (val == 0xf7 || midi_pos >= 65536) + { +/* pclog("MIDI send sysex %i: ", midi_pos); + for (int i = 0; i < midi_pos; i++) + pclog("%02x ", midi_sysex_data[i]); + pclog("\n");*/ + snd_rawmidi_write(midiout, midi_sysex_data, midi_pos); +// pclog("Sent sysex\n"); + midi_insysex = 0; + } + return; + } + + if (midi_len) + { + if (midi_pos < 3) + { + midi_command[midi_pos] = val; + + midi_pos++; + + if (midi_pos == midi_len) + { +// pclog("MIDI send %i: %02x %02x %02x %02x\n", midi_len, midi_command[0], midi_command[1], midi_command[2], midi_command[3]); + snd_rawmidi_write(midiout, midi_command, midi_len); + } + } + } +} + +int midi_get_num_devs() +{ + if (!midi_queried) + midi_query(); + + return midi_device_count; +} + +void midi_get_dev_name(int num, char *s) +{ + strcpy(s, midi_devices[num].name); +} diff --git a/src/minivhd/CREDITS.md b/src/minivhd/CREDITS.md new file mode 100644 index 0000000..c494d4e --- /dev/null +++ b/src/minivhd/CREDITS.md @@ -0,0 +1,12 @@ +# Credits +MiniVHD Copyright (c) 2019 Sherman Perry + +MiniVHD was made possible with the help of the following projects + +### libxml2 +**Project Home:** http://www.xmlsoft.org/ +**License:** MIT (see src/libxml2_encoding.c for details) + +### cwalk +**Project Home:** https://likle.github.io/cwalk/ +**Licence:** MIT (https://github.com/likle/cwalk/blob/master/LICENSE.md) diff --git a/src/minivhd/LICENSE b/src/minivhd/LICENSE new file mode 100644 index 0000000..b5392e6 --- /dev/null +++ b/src/minivhd/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2020 Sherman Perry + +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. \ No newline at end of file diff --git a/src/minivhd/cwalk.c b/src/minivhd/cwalk.c new file mode 100644 index 0000000..f0c4842 --- /dev/null +++ b/src/minivhd/cwalk.c @@ -0,0 +1,1424 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "cwalk.h" +/** + * We try to default to a different path style depending on the operating + * system. So this should detect whether we should use windows or unix paths. + */ +#if defined(WIN32) || defined(_WIN32) || \ + defined(__WIN32) && !defined(__CYGWIN__) +static enum cwk_path_style path_style = CWK_STYLE_WINDOWS; +#else +static enum cwk_path_style path_style = CWK_STYLE_UNIX; +#endif + +/** + * This is a list of separators used in different styles. Windows can read + * multiple separators, but it generally outputs just a backslash. The output + * will always use the first character for the output. + */ +static const char *separators[] = {[CWK_STYLE_WINDOWS] = "\\/", + [CWK_STYLE_UNIX] = "/"}; + +/** + * A joined path represents multiple path strings which are concatenated, but + * not (necessarily) stored in contiguous memory. The joined path allows to + * iterate over the segments as if it was one piece of path. + */ +struct cwk_segment_joined +{ + struct cwk_segment segment; + const char **paths; + size_t path_index; +}; + +static size_t cwk_path_output_sized(char *buffer, size_t buffer_size, + size_t position, const char *str, size_t length) +{ + size_t amount_written; + + // First we determine the amount which we can write to the buffer. There are + // three cases. In the first case we have enough to store the whole string in + // it. In the second one we can only store a part of it, and in the third we + // have no space left. + if (buffer_size > position + length) { + amount_written = length; + } else if (buffer_size > position) { + amount_written = buffer_size - position; + } else { + amount_written = 0; + } + + // If we actually want to write out something we will do that here. We will + // always append a '\0', this way we are guaranteed to have a valid string at + // all times. + if (amount_written > 0) { + memmove(&buffer[position], str, amount_written); + } + + // Return the theoretical length which would have been written when everything + // would have fit in the buffer. + return length; +} + +static size_t cwk_path_output_current(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a "current" directory, which is a single character. This + // character is currently not style dependant. + return cwk_path_output_sized(buffer, buffer_size, position, ".", 1); +} + +static size_t cwk_path_output_back(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a "back" directory, which ahs two characters. This + // character is currently not style dependant. + return cwk_path_output_sized(buffer, buffer_size, position, "..", 2); +} + +static size_t cwk_path_output_separator(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a separator, which is a single character. + return cwk_path_output_sized(buffer, buffer_size, position, + separators[path_style], 1); +} + +static size_t cwk_path_output_dot(char *buffer, size_t buffer_size, + size_t position) +{ + // We output a dot, which is a single character. This is used for extensions. + return cwk_path_output_sized(buffer, buffer_size, position, ".", 1); +} + +static size_t cwk_path_output(char *buffer, size_t buffer_size, size_t position, + const char *str) +{ + size_t length; + + // This just does a sized output internally, but first measuring the + // null-terminated string. + length = strlen(str); + return cwk_path_output_sized(buffer, buffer_size, position, str, length); +} + +static void cwk_path_terminate_output(char *buffer, size_t buffer_size, + size_t pos) +{ + if (buffer_size > 0) { + if (pos >= buffer_size) { + buffer[buffer_size - 1] = '\0'; + } else { + buffer[pos] = '\0'; + } + } +} + +static bool cwk_path_is_string_equal(const char *first, const char *second, + size_t n) +{ + // If the path style is UNIX, we will compare case sensitively. This can be + // done easily using strncmp. + if (path_style == CWK_STYLE_UNIX) { + return strncmp(first, second, n) == 0; + } + + // However, if this is windows we will have to compare case insensitively. + // Since there is no standard method to do that we will have to do it on our + // own. + while (*first && *second && n > 0) { + // We can consider the string to be not equal if the two lowercase + // characters are not equal. + if (tolower(*first++) != tolower(*second++)) { + return false; + } + + --n; + } + + // We can consider the string to be equal if we either reached n == 0 or both + // cursors point to a null character. + return n == 0 || (*first == '\0' && *second == '\0'); +} + +static const char *cwk_path_find_next_stop(const char *c) +{ + // We just move forward until we find a '\0' or a separator, which will be our + // next "stop". + while (*c != '\0' && !cwk_path_is_separator(c)) { + ++c; + } + + // Return the pointer of the next stop. + return c; +} + +static const char *cwk_path_find_previous_stop(const char *begin, const char *c) +{ + // We just move back until we find a separator or reach the beginning of the + // path, which will be our previous "stop". + while (c > begin && !cwk_path_is_separator(c)) { + --c; + } + + // Return the pointer to the previous stop. We have to return the first + // character after the separator, not on the separator itself. + if (cwk_path_is_separator(c)) { + return c + 1; + } else { + return c; + } +} + +static bool cwk_path_get_first_segment_without_root(const char *path, + const char *segments, struct cwk_segment *segment) +{ + // Let's remember the path. We will move the path pointer afterwards, that's + // why this has to be done first. + segment->path = path; + segment->segments = segments; + + // Now let's check whether this is an empty string. An empty string has no + // segment it could use. + if (*segments == '\0') { + return false; + } + + // If the string starts with separators, we will jump over those. If there is + // only a slash and a '\0' after it, we can't determine the first segment + // since there is none. + while (cwk_path_is_separator(segments)) { + ++segments; + if (*segments == '\0') { + return false; + } + } + + // So this is the beginning of our segment. + segment->begin = segments; + + // Now let's determine the end of the segment, which we do by moving the path + // pointer further until we find a separator. + segments = cwk_path_find_next_stop(segments); + + // And finally, calculate the size of the segment by subtracting the position + // from the end. + segment->size = segments - segment->begin; + segment->end = segments; + + // Tell the caller that we found a segment. + return true; +} + +static bool cwk_path_get_last_segment_without_root(const char *path, + struct cwk_segment *segment) +{ + // Now this is fairly similar to the normal algorithm, however, it will assume + // that there is no root in the path. So we grab the first segment at this + // position, assuming there is no root. + if (!cwk_path_get_first_segment_without_root(path, path, segment)) { + return false; + } + + // Now we find our last segment. The segment struct of the caller + // will contain the last segment, since the function we call here will not + // change the segment struct when it reaches the end. + while (cwk_path_get_next_segment(segment)) { + // We just loop until there is no other segment left. + } + + return true; +} + +static bool cwk_path_get_first_segment_joined(const char **paths, + struct cwk_segment_joined *sj) +{ + bool result; + + // Prepare the first segment. We position the joined segment on the first path + // and assign the path array to the struct. + sj->path_index = 0; + sj->paths = paths; + + // We loop through all paths until we find one which has a segment. The result + // is stored in a variable, so we can let the caller know whether we found one + // or not. + result = false; + while (paths[sj->path_index] != NULL && + (result = cwk_path_get_first_segment(paths[sj->path_index], + &sj->segment)) == false) { + ++sj->path_index; + } + + return result; +} + +static bool cwk_path_get_next_segment_joined(struct cwk_segment_joined *sj) +{ + bool result; + + if (sj->paths[sj->path_index] == NULL) { + // We reached already the end of all paths, so there is no other segment + // left. + return false; + } else if (cwk_path_get_next_segment(&sj->segment)) { + // There was another segment on the current path, so we are good to + // continue. + return true; + } + + // We try to move to the next path which has a segment available. We must at + // least move one further since the current path reached the end. + result = false; + + do { + ++sj->path_index; + + // And we obviously have to stop this loop if there are no more paths left. + if (sj->paths[sj->path_index] == NULL) { + break; + } + + // Grab the first segment of the next path and determine whether this path + // has anything useful in it. There is one more thing we have to consider + // here - for the first time we do this we want to skip the root, but + // afterwards we will consider that to be part of the segments. + result = cwk_path_get_first_segment_without_root(sj->paths[sj->path_index], + sj->paths[sj->path_index], &sj->segment); + + } while (!result); + + // Finally, report the result back to the caller. + return result; +} + +static bool cwk_path_get_previous_segment_joined(struct cwk_segment_joined *sj) +{ + bool result; + + if (*sj->paths == NULL) { + // It's possible that there is no initialized segment available in the + // struct since there are no paths. In that case we can return false, since + // there is no previous segment. + return false; + } else if (cwk_path_get_previous_segment(&sj->segment)) { + // Now we try to get the previous segment from the current path. If we can + // do that successfully, we can let the caller know that we found one. + return true; + } + + result = false; + + do { + // We are done once we reached index 0. In that case there are no more + // segments left. + if (sj->path_index == 0) { + break; + } + + // There is another path which we have to inspect. So we decrease the path + // index. + --sj->path_index; + + // If this is the first path we will have to consider that this path might + // include a root, otherwise we just treat is as a segment. + if (sj->path_index == 0) { + result = cwk_path_get_last_segment(sj->paths[sj->path_index], + &sj->segment); + } else { + result = cwk_path_get_last_segment_without_root(sj->paths[sj->path_index], + &sj->segment); + } + + } while (!result); + + return result; +} + +static bool cwk_path_segment_back_will_be_removed(struct cwk_segment_joined *sj) +{ + enum cwk_segment_type type; + int counter; + + // We are handling back segments here. We must verify how many back segments + // and how many normal segments come before this one to decide whether we keep + // or remove it. + + // The counter determines how many normal segments are our current segment, + // which will popped off before us. If the counter goes above zero it means + // that our segment will be popped as well. + counter = 0; + + // We loop over all previous segments until we either reach the beginning, + // which means our segment will not be dropped or the counter goes above zero. + while (cwk_path_get_previous_segment_joined(sj)) { + + // Now grab the type. The type determines whether we will increase or + // decrease the counter. We don't handle a CWK_CURRENT frame here since it + // has no influence. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_NORMAL) { + // This is a normal segment. The normal segment will increase the counter + // since it neutralizes one back segment. If we go above zero we can + // return immediately. + ++counter; + if (counter > 0) { + return true; + } + } else if (type == CWK_BACK) { + // A CWK_BACK segment will reduce the counter by one. We can not remove a + // back segment as long we are not above zero since we don't have the + // opposite normal segment which we would remove. + --counter; + } + } + + // We never got a count larger than zero, so we will keep this segment alive. + return false; +} + +static bool cwk_path_segment_normal_will_be_removed( + struct cwk_segment_joined *sj) +{ + enum cwk_segment_type type; + int counter; + + // The counter determines how many segments are above our current segment, + // which will popped off before us. If the counter goes below zero it means + // that our segment will be popped as well. + counter = 0; + + // We loop over all following segments until we either reach the end, which + // means our segment will not be dropped or the counter goes below zero. + while (cwk_path_get_next_segment_joined(sj)) { + + // First, grab the type. The type determines whether we will increase or + // decrease the counter. We don't handle a CWK_CURRENT frame here since it + // has no influence. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_NORMAL) { + // This is a normal segment. The normal segment will increase the counter + // since it will be removed by a "../" before us. + ++counter; + } else if (type == CWK_BACK) { + // A CWK_BACK segment will reduce the counter by one. If we are below zero + // we can return immediately. + --counter; + if (counter < 0) { + return true; + } + } + } + + // We never got a negative count, so we will keep this segment alive. + return false; +} + +static bool +cwk_path_segment_will_be_removed(const struct cwk_segment_joined *sj, + bool absolute) +{ + enum cwk_segment_type type; + struct cwk_segment_joined sjc; + + // We copy the joined path so we don't need to modify it. + sjc = *sj; + + // First we check whether this is a CWK_CURRENT or CWK_BACK segment, since + // those will always be dropped. + type = cwk_path_get_segment_type(&sj->segment); + if (type == CWK_CURRENT) { + return true; + } else if (type == CWK_BACK && absolute) { + return true; + } else if (type == CWK_BACK) { + return cwk_path_segment_back_will_be_removed(&sjc); + } else { + return cwk_path_segment_normal_will_be_removed(&sjc); + } +} + +static bool +cwk_path_segment_joined_skip_invisible(struct cwk_segment_joined *sj, + bool absolute) +{ + while (cwk_path_segment_will_be_removed(sj, absolute)) { + if (!cwk_path_get_next_segment_joined(sj)) { + return false; + } + } + + return true; +} + +static void cwk_path_get_root_windows(const char *path, size_t *length) +{ + const char *c; + bool is_device_path; + + // A device path is a path which starts with "\\." or "\\?". A device path can + // be a UNC path as well, in which case it will take up one more segment. + is_device_path = false; + + // We can not determine the root if this is an empty string. So we set the + // root to NULL and the length to zero and cancel the whole thing. + c = path; + *length = 0; + if (!*c) { + return; + } + + // Now we have to verify whether this is a windows network path (UNC), which + // we will consider our root. + if (cwk_path_is_separator(c)) { + ++c; + + // Check whether the path starts with a single back slash, which means this + // is not a network path - just a normal path starting with a backslash. + if (!cwk_path_is_separator(c)) { + // Okay, this is not a network path but we still use the backslash as a + // root. + ++(*length); + return; + } + + // Yes, this is a network or device path. Skip the previous separator. Now + // we need to determine whether this is a device path. We might advance one + // character here if the server name starts with a '?' or a '.', but that's + // fine since we will search for a separator afterwards anyway. + ++c; + is_device_path = (*c == '?' || *c == '.') && cwk_path_is_separator(++c); + if (is_device_path) { + // That's a device path, and the root must be either "\\.\" or "\\?\" + // which is 4 characters long. (at least that's how Windows + // GetFullPathName behaves.) + *length = 4; + return; + } + + // We will grab anything up to the next stop. The next top might be a '\0' + // or another separator. That will be the server name. + c = cwk_path_find_next_stop(c); + + // If this is a separator and not the end of a string we wil have to include + // it. However, if this is a '\0' we must not skip it. + while (cwk_path_is_separator(c)) { + ++c; + } + + // We are now skipping the shared folder name, which will end after the + // next stop. + c = cwk_path_find_next_stop(c); + + // Then there might be a separator at the end. We will include that as well, + // it will mark the path as absolute. + if (cwk_path_is_separator(c)) { + ++c; + } + + // Finally, calculate the size of the root. + *length = c - path; + return; + } + + // Move to the next and check whether this is a colon. + if (*++c == ':') { + *length = 2; + + // Now check whether this is a backslash (or slash). If it is not, we could + // assume that the next character is a '\0' if it is a valid path. However, + // we will not assume that - since ':' is not valid in a path it must be a + // mistake by the caller than. We will try to understand it anyway. + if (cwk_path_is_separator(++c)) { + *length = 3; + } + } +} + +static void cwk_path_get_root_unix(const char *path, size_t *length) +{ + // The slash of the unix path represents the root. There is no root if there + // is no slash. + if (cwk_path_is_separator(path)) { + *length = 1; + } else { + *length = 0; + } +} + +static bool cwk_path_is_root_absolute(const char *path, size_t length) +{ + // This is definitely not absolute if there is no root. + if (length == 0) { + return false; + } + + // If there is a separator at the end of the root, we can safely consider this + // to be an absolute path. + return cwk_path_is_separator(&path[length - 1]); +} + +static size_t cwk_path_join_and_normalize_multiple(const char **paths, + char *buffer, size_t buffer_size) +{ + size_t pos; + bool absolute, has_segment_output; + struct cwk_segment_joined sj; + + // We initialize the position after the root, which should get us started. + cwk_path_get_root(paths[0], &pos); + + // Determine whether the path is absolute or not. We need that to determine + // later on whether we can remove superfluous "../" or not. + absolute = cwk_path_is_root_absolute(paths[0], pos); + + // First copy the root to the output. We will not modify the root. + cwk_path_output_sized(buffer, buffer_size, 0, paths[0], pos); + + // So we just grab the first segment. If there is no segment we will always + // output a "/", since we currently only support absolute paths here. + if (!cwk_path_get_first_segment_joined(paths, &sj)) { + goto done; + } + + // Let's assume that we don't have any segment output for now. We will toggle + // this flag once there is some output. + has_segment_output = false; + + do { + // Check whether we have to drop this segment because of resolving a + // relative path or because it is a CWK_CURRENT segment. + if (cwk_path_segment_will_be_removed(&sj, absolute)) { + continue; + } + + // Remember that we have segment output, so we can handle the trailing slash + // later on. This is necessary since we might have segments but they are all + // removed. + has_segment_output = true; + + // Write out the segment but keep in mind that we need to follow the + // buffer size limitations. That's why we use the path output functions + // here. + pos += cwk_path_output_sized(buffer, buffer_size, pos, sj.segment.begin, + sj.segment.size); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&sj)); + + // Remove the trailing slash, but only if we have segment output. We don't + // want to remove anything from the root. + if (has_segment_output) { + --pos; + } else if (pos == 0) { + // This may happen if the path is absolute and all segments have been + // removed. We can not have an empty output - and empty output means we stay + // in the current directory. So we will output a ".". + assert(absolute == false); + pos += cwk_path_output_current(buffer, buffer_size, pos); + } + + // We must append a '\0' in any case, unless the buffer size is zero. If the + // buffer size is zero, which means we can not. +done: + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And finally let our caller know about the total size of the normalized + // path. + return pos; +} + +size_t cwk_path_get_absolute(const char *base, const char *path, char *buffer, + size_t buffer_size) +{ + size_t i; + const char *paths[4]; + + // The basename should be an absolute path if the caller is using the API + // correctly. However, he might not and in that case we will append a fake + // root at the beginning. + if (cwk_path_is_absolute(base)) { + i = 0; + } else { + paths[0] = "/"; + i = 1; + } + + if (cwk_path_is_absolute(path)) { + // If the submitted path is not relative the base path becomes irrelevant. + // We will only normalize the submitted path instead. + paths[i++] = path; + paths[i] = NULL; + } else { + // Otherwise we append the relative path to the base path and normalize it. + // The result will be a new absolute path. + paths[i++] = base; + paths[i++] = path; + paths[i] = NULL; + } + + // Finally join everything together and normalize it. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +static void cwk_path_skip_segments_until_diverge(struct cwk_segment_joined *bsj, + struct cwk_segment_joined *osj, bool absolute, bool *base_available, + bool *other_available) +{ + // Now looping over all segments until they start to diverge. A path may + // diverge if two segments are not equal or if one path reaches the end. + do { + + // Check whether there is anything available after we skip everything which + // is invisible. We do that for both paths, since we want to let the caller + // know which path has some trailing segments after they diverge. + *base_available = cwk_path_segment_joined_skip_invisible(bsj, absolute); + *other_available = cwk_path_segment_joined_skip_invisible(osj, absolute); + + // We are done if one or both of those paths reached the end. They either + // diverge or both reached the end - but in both cases we can not continue + // here. + if (!*base_available || !*other_available) { + break; + } + + // Compare the content of both segments. We are done if they are not equal, + // since they diverge. + if (!cwk_path_is_string_equal(bsj->segment.begin, osj->segment.begin, + bsj->segment.size)) { + break; + } + + // We keep going until one of those segments reached the end. The next + // segment might be invisible, but we will check for that in the beginning + // of the loop once again. + *base_available = cwk_path_get_next_segment_joined(bsj); + *other_available = cwk_path_get_next_segment_joined(osj); + } while (*base_available && *other_available); +} + +size_t cwk_path_get_relative(const char *base_directory, const char *path, + char *buffer, size_t buffer_size) +{ + size_t pos, base_root_length, path_root_length; + bool absolute, base_available, other_available, has_output; + const char *base_paths[2], *other_paths[2]; + struct cwk_segment_joined bsj, osj; + + pos = 0; + + // First we compare the roots of those two paths. If the roots are not equal + // we can't continue, since there is no way to get a relative path from + // different roots. + cwk_path_get_root(base_directory, &base_root_length); + cwk_path_get_root(path, &path_root_length); + if (!cwk_path_is_string_equal(base_directory, path, base_root_length)) { + return pos; + } + + // Verify whether this is an absolute path. We need to know that since we can + // remove all back-segments if it is. + absolute = cwk_path_is_root_absolute(base_directory, base_root_length); + + // Initialize our joined segments. This will allow us to use the internal + // functions to skip until diverge and invisible. We only have one path in + // them though. + base_paths[0] = base_directory; + base_paths[1] = NULL; + other_paths[0] = path; + other_paths[1] = NULL; + cwk_path_get_first_segment_joined(base_paths, &bsj); + cwk_path_get_first_segment_joined(other_paths, &osj); + + // Okay, now we skip until the segments diverge. We don't have anything to do + // with the segments which are equal. + cwk_path_skip_segments_until_diverge(&bsj, &osj, absolute, &base_available, + &other_available); + + // Assume there is no output until we have got some. We will need this + // information later on to remove trailing slashes or alternatively output a + // current-segment. + has_output = false; + + // So if we still have some segments left in the base path we will now output + // a back segment for all of them. + if (base_available) { + do { + // Skip any invisible segment. We don't care about those and we don't need + // to navigate back because of them. + if (!cwk_path_segment_joined_skip_invisible(&bsj, absolute)) { + break; + } + + // Toggle the flag if we have output. We need to remember that, since we + // want to remove the trailing slash. + has_output = true; + + // Output the back segment and a separator. No need to worry about the + // superfluous segment since it will be removed later on. + pos += cwk_path_output_back(buffer, buffer_size, pos); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&bsj)); + } + + // And if we have some segments available of the target path we will output + // all of those. + if (other_available) { + do { + // Again, skip any invisible segments since we don't need to navigate into + // them. + if (!cwk_path_segment_joined_skip_invisible(&osj, absolute)) { + break; + } + + // Toggle the flag if we have output. We need to remember that, since we + // want to remove the trailing slash. + has_output = true; + + // Output the current segment and a separator. No need to worry about the + // superfluous segment since it will be removed later on. + pos += cwk_path_output_sized(buffer, buffer_size, pos, osj.segment.begin, + osj.segment.size); + pos += cwk_path_output_separator(buffer, buffer_size, pos); + } while (cwk_path_get_next_segment_joined(&osj)); + } + + // If we have some output by now we will have to remove the trailing slash. We + // simply do that by moving back one character. The terminate output function + // will then place the '\0' on this position. Otherwise, if there is no + // output, we will have to output a "current directory", since the target path + // points to the base path. + if (has_output) { + --pos; + } else { + pos += cwk_path_output_current(buffer, buffer_size, pos); + } + + // Finally, we can terminate the output - which means we place a '\0' at the + // current position or at the end of the buffer. + cwk_path_terminate_output(buffer, buffer_size, pos); + + return pos; +} + +size_t cwk_path_join(const char *path_a, const char *path_b, char *buffer, + size_t buffer_size) +{ + const char *paths[3]; + + // This is simple. We will just create an array with the two paths which we + // wish to join. + paths[0] = path_a; + paths[1] = path_b; + paths[2] = NULL; + + // And then call the join and normalize function which will do the hard work + // for us. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +size_t cwk_path_join_multiple(const char **paths, char *buffer, + size_t buffer_size) +{ + // We can just call the internal join and normalize function for this one, + // since it will handle everything. + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +void cwk_path_get_root(const char *path, size_t *length) +{ + // We use a different implementation here based on the configuration of the + // library. + if (path_style == CWK_STYLE_WINDOWS) { + cwk_path_get_root_windows(path, length); + } else { + cwk_path_get_root_unix(path, length); + } +} + +size_t cwk_path_change_root(const char *path, const char *new_root, + char *buffer, size_t buffer_size) +{ + const char *tail; + size_t root_length, path_length, tail_length, new_root_length, new_path_size; + + // First we need to determine the actual size of the root which we will + // change. + cwk_path_get_root(path, &root_length); + + // Now we determine the sizes of the new root and the path. We need that to + // determine the size of the part after the root (the tail). + new_root_length = strlen(new_root); + path_length = strlen(path); + + // Okay, now we calculate the position of the tail and the length of it. + tail = path + root_length; + tail_length = path_length - root_length; + + // We first output the tail and then the new root, that's because the source + // path and the buffer may be overlapping. This way the root will not + // overwrite the tail. + cwk_path_output_sized(buffer, buffer_size, new_root_length, tail, + tail_length); + cwk_path_output_sized(buffer, buffer_size, 0, new_root, new_root_length); + + // Finally we calculate the size o the new path and terminate the output with + // a '\0'. + new_path_size = tail_length + new_root_length; + cwk_path_terminate_output(buffer, buffer_size, new_path_size); + + return new_path_size; +} + +bool cwk_path_is_absolute(const char *path) +{ + size_t length; + + // We grab the root of the path. This root does not include the first + // separator of a path. + cwk_path_get_root(path, &length); + + // Now we can determine whether the root is absolute or not. + return cwk_path_is_root_absolute(path, length); +} + +bool cwk_path_is_relative(const char *path) +{ + // The path is relative if it is not absolute. + return !cwk_path_is_absolute(path); +} + +void cwk_path_get_basename(const char *path, const char **basename, + size_t *length) +{ + struct cwk_segment segment; + + // We get the last segment of the path. The last segment will contain the + // basename if there is any. If there are no segments we will set the basename + // to NULL and the length to 0. + if (!cwk_path_get_last_segment(path, &segment)) { + *basename = NULL; + *length = 0; + return; + } + + // Now we can just output the segment contents, since that's our basename. + // There might be trailing separators after the basename, but the size does + // not include those. + *basename = segment.begin; + *length = segment.size; +} + +size_t cwk_path_change_basename(const char *path, const char *new_basename, + char *buffer, size_t buffer_size) +{ + struct cwk_segment segment; + size_t pos, root_size, new_basename_size; + + // First we try to get the last segment. We may only have a root without any + // segments, in which case we will create one. + if (!cwk_path_get_last_segment(path, &segment)) { + + // So there is no segment in this path. First we grab the root and output + // that. We are not going to modify the root in any way. + cwk_path_get_root(path, &root_size); + pos = cwk_path_output_sized(buffer, buffer_size, 0, path, root_size); + + // We have to trim the separators from the beginning of the new basename. + // This is quite easy to do. + while (cwk_path_is_separator(new_basename)) { + ++new_basename; + } + + // Now we measure the length of the new basename, this is a two step + // process. First we find the '\0' character at the end of the string. + new_basename_size = 0; + while (new_basename[new_basename_size]) { + ++new_basename_size; + } + + // And then we trim the separators at the end of the basename until we reach + // the first valid character. + while (new_basename_size > 0 && + cwk_path_is_separator(&new_basename[new_basename_size - 1])) { + --new_basename_size; + } + + // Now we will output the new basename after the root. + pos += cwk_path_output_sized(buffer, buffer_size, pos, new_basename, + new_basename_size); + + // And finally terminate the output and return the total size of the path. + cwk_path_terminate_output(buffer, buffer_size, pos); + return pos; + } + + // If there is a last segment we can just forward this call, which is fairly + // easy. + return cwk_path_change_segment(&segment, new_basename, buffer, buffer_size); +} + +void cwk_path_get_dirname(const char *path, size_t *length) +{ + struct cwk_segment segment; + + // We get the last segment of the path. The last segment will contain the + // basename if there is any. If there are no segments we will set the length + // to 0. + if (!cwk_path_get_last_segment(path, &segment)) { + *length = 0; + return; + } + + // We can now return the length from the beginning of the string up to the + // beginning of the last segment. + *length = segment.begin - path; +} + +bool cwk_path_get_extension(const char *path, const char **extension, + size_t *length) +{ + struct cwk_segment segment; + const char *c; + + // We get the last segment of the path. The last segment will contain the + // extension if there is any. + if (!cwk_path_get_last_segment(path, &segment)) { + return false; + } + + // Now we search for a dot within the segment. If there is a dot, we consider + // the rest of the segment the extension. We do this from the end towards the + // beginning, since we want to find the last dot. + for (c = segment.end; c >= segment.begin; --c) { + if (*c == '.') { + // Okay, we found an extension. We can stop looking now. + *extension = c; + *length = segment.end - c; + return true; + } + } + + // We couldn't find any extension. + return false; +} + +bool cwk_path_has_extension(const char *path) +{ + const char *extension; + size_t length; + + // We just wrap the get_extension call which will then do the work for us. + return cwk_path_get_extension(path, &extension, &length); +} + +size_t cwk_path_change_extension(const char *path, const char *new_extension, + char *buffer, size_t buffer_size) +{ + struct cwk_segment segment; + const char *c, *old_extension; + size_t pos, root_size, trail_size, new_extension_size; + + // First we try to get the last segment. We may only have a root without any + // segments, in which case we will create one. + if (!cwk_path_get_last_segment(path, &segment)) { + + // So there is no segment in this path. First we grab the root and output + // that. We are not going to modify the root in any way. If there is no + // root, this will end up with a root size 0, and nothing will be written. + cwk_path_get_root(path, &root_size); + pos = cwk_path_output_sized(buffer, buffer_size, 0, path, root_size); + + // Add a dot if the submitted value doesn't have any. + if (*new_extension != '.') { + pos += cwk_path_output_dot(buffer, buffer_size, pos); + } + + // And finally terminate the output and return the total size of the path. + pos += cwk_path_output(buffer, buffer_size, pos, new_extension); + cwk_path_terminate_output(buffer, buffer_size, pos); + return pos; + } + + // Now we seek the old extension in the last segment, which we will replace + // with the new one. If there is no old extension, it will point to the end of + // the segment. + old_extension = segment.end; + for (c = segment.begin; c < segment.end; ++c) { + if (*c == '.') { + old_extension = c; + } + } + + pos = cwk_path_output_sized(buffer, buffer_size, 0, segment.path, + old_extension - segment.path); + + // If the new extension starts with a dot, we will skip that dot. We always + // output exactly one dot before the extension. If the extension contains + // multiple dots, we will output those as part of the extension. + if (*new_extension == '.') { + ++new_extension; + } + + // We calculate the size of the new extension, including the dot, in order to + // output the trail - which is any part of the path coming after the + // extension. We must output this first, since the buffer may overlap with the + // submitted path - and it would be overridden by longer extensions. + new_extension_size = strlen(new_extension) + 1; + trail_size = cwk_path_output(buffer, buffer_size, pos + new_extension_size, + segment.end); + + // Finally we output the dot and the new extension. The new extension itself + // doesn't contain the dot anymore, so we must output that first. + pos += cwk_path_output_dot(buffer, buffer_size, pos); + pos += cwk_path_output(buffer, buffer_size, pos, new_extension); + + // Now we terminate the output with a null-terminating character, but before + // we do that we must add the size of the trail to the position which we + // output before. + pos += trail_size; + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And the position is our output size now. + return pos; +} + +size_t cwk_path_normalize(const char *path, char *buffer, size_t buffer_size) +{ + const char *paths[2]; + + // Now we initialize the paths which we will normalize. Since this function + // only supports submitting a single path, we will only add that one. + paths[0] = path; + paths[1] = NULL; + + return cwk_path_join_and_normalize_multiple(paths, buffer, buffer_size); +} + +size_t cwk_path_get_intersection(const char *path_base, const char *path_other) +{ + bool absolute; + size_t base_root_length, other_root_length; + const char *end; + const char *paths_base[2], *paths_other[2]; + struct cwk_segment_joined base, other; + + // We first compare the two roots. We just return zero if they are not equal. + // This will also happen to return zero if the paths are mixed relative and + // absolute. + cwk_path_get_root(path_base, &base_root_length); + cwk_path_get_root(path_other, &other_root_length); + if (!cwk_path_is_string_equal(path_base, path_other, base_root_length)) { + return 0; + } + + // Configure our paths. We just have a single path in here for now. + paths_base[0] = path_base; + paths_base[1] = NULL; + paths_other[0] = path_other; + paths_other[1] = NULL; + + // So we get the first segment of both paths. If one of those paths don't have + // any segment, we will return 0. + if (!cwk_path_get_first_segment_joined(paths_base, &base) || + !cwk_path_get_first_segment_joined(paths_other, &other)) { + return base_root_length; + } + + // We now determine whether the path is absolute or not. This is required + // because if will ignore removed segments, and this behaves differently if + // the path is absolute. However, we only need to check the base path because + // we are guaranteed that both paths are either relative or absolute. + absolute = cwk_path_is_root_absolute(path_base, base_root_length); + + // We must keep track of the end of the previous segment. Initially, this is + // set to the beginning of the path. This means that 0 is returned if the + // first segment is not equal. + end = path_base + base_root_length; + + // Now we loop over both segments until one of them reaches the end or their + // contents are not equal. + do { + // We skip all segments which will be removed in each path, since we want to + // know about the true path. + if (!cwk_path_segment_joined_skip_invisible(&base, absolute) || + !cwk_path_segment_joined_skip_invisible(&other, absolute)) { + break; + } + + if (!cwk_path_is_string_equal(base.segment.begin, other.segment.begin, + base.segment.size)) { + // So the content of those two segments are not equal. We will return the + // size up to the beginning. + return end - path_base; + } + + // Remember the end of the previous segment before we go to the next one. + end = base.segment.end; + } while (cwk_path_get_next_segment_joined(&base) && + cwk_path_get_next_segment_joined(&other)); + + // Now we calculate the length up to the last point where our paths pointed to + // the same place. + return end - path_base; +} + +bool cwk_path_get_first_segment(const char *path, struct cwk_segment *segment) +{ + size_t length; + const char *segments; + + // We skip the root since that's not part of the first segment. The root is + // treated as a separate entity. + cwk_path_get_root(path, &length); + segments = path + length; + + // Now, after we skipped the root we can continue and find the actual segment + // content. + return cwk_path_get_first_segment_without_root(path, segments, segment); +} + +bool cwk_path_get_last_segment(const char *path, struct cwk_segment *segment) +{ + // We first grab the first segment. This might be our last segment as well, + // but we don't know yet. There is no last segment if there is no first + // segment, so we return false in that case. + if (!cwk_path_get_first_segment(path, segment)) { + return false; + } + + // Now we find our last segment. The segment struct of the caller + // will contain the last segment, since the function we call here will not + // change the segment struct when it reaches the end. + while (cwk_path_get_next_segment(segment)) { + // We just loop until there is no other segment left. + } + + return true; +} + +bool cwk_path_get_next_segment(struct cwk_segment *segment) +{ + const char *c; + + // First we jump to the end of the previous segment. The first character must + // be either a '\0' or a separator. + c = segment->begin + segment->size; + if (*c == '\0') { + return false; + } + + // Now we skip all separator until we reach something else. We are not yet + // guaranteed to have a segment, since the string could just end afterwards. + assert(cwk_path_is_separator(c)); + do { + ++c; + } while (cwk_path_is_separator(c)); + + // If the string ends here, we can safely assume that there is no other + // segment after this one. + if (*c == '\0') { + return false; + } + + // Now we are safe to assume there is a segment. We store the beginning of + // this segment in the segment struct of the caller. + segment->begin = c; + + // And now determine the size of this segment, and store it in the struct of + // the caller as well. + c = cwk_path_find_next_stop(c); + segment->end = c; + segment->size = c - segment->begin; + + // Tell the caller that we found a segment. + return true; +} + +bool cwk_path_get_previous_segment(struct cwk_segment *segment) +{ + const char *c; + + // The current position might point to the first character of the path, which + // means there are no previous segments available. + c = segment->begin; + if (c <= segment->segments) { + return false; + } + + // We move towards the beginning of the path until we either reached the + // beginning or the character is no separator anymore. + do { + --c; + if (c <= segment->segments) { + // So we reached the beginning here and there is no segment. So we return + // false and don't change the segment structure submitted by the caller. + return false; + } + } while (cwk_path_is_separator(c)); + + // We are guaranteed now that there is another segment, since we moved before + // the previous separator and did not reach the segment path beginning. + segment->end = c + 1; + segment->begin = cwk_path_find_previous_stop(segment->segments, c); + segment->size = segment->end - segment->begin; + + return true; +} + +enum cwk_segment_type cwk_path_get_segment_type( + const struct cwk_segment *segment) +{ + // We just make a string comparison with the segment contents and return the + // appropriate type. + if (strncmp(segment->begin, ".", segment->size) == 0) { + return CWK_CURRENT; + } else if (strncmp(segment->begin, "..", segment->size) == 0) { + return CWK_BACK; + } + + return CWK_NORMAL; +} + +bool cwk_path_is_separator(const char *str) +{ + const char *c; + + // We loop over all characters in the read symbols. + c = separators[path_style]; + while (*c) { + if (*c == *str) { + return true; + } + + ++c; + } + + return false; +} + +size_t cwk_path_change_segment(struct cwk_segment *segment, const char *value, + char *buffer, size_t buffer_size) +{ + size_t pos, value_size, tail_size; + + // First we have to output the head, which is the whole string up to the + // beginning of the segment. This part of the path will just stay the same. + pos = cwk_path_output_sized(buffer, buffer_size, 0, segment->path, + segment->begin - segment->path); + + // In order to trip the submitted value, we will skip any separator at the + // beginning of it and behave as if it was never there. + while (cwk_path_is_separator(value)) { + ++value; + } + + // Now we determine the length of the value. In order to do that we first + // locate the '\0'. + value_size = 0; + while (value[value_size]) { + ++value_size; + } + + // Since we trim separators at the beginning and in the end of the value we + // have to subtract from the size until there are either no more characters + // left or the last character is no separator. + while (value_size > 0 && cwk_path_is_separator(&value[value_size - 1])) { + --value_size; + } + + // We also have to determine the tail size, which is the part of the string + // following the current segment. This part will not change. + tail_size = strlen(segment->end); + + // Now we output the tail. We have to do that, because if the buffer and the + // source are overlapping we would override the tail if the value is + // increasing in length. + cwk_path_output_sized(buffer, buffer_size, pos + value_size, segment->end, + tail_size); + + // Finally we can output the value in the middle of the head and the tail, + // where we have enough space to fit the whole trimmed value. + pos += cwk_path_output_sized(buffer, buffer_size, pos, value, value_size); + + // Now we add the tail size to the current position and terminate the output - + // basically, ensure that there is a '\0' at the end of the buffer. + pos += tail_size; + cwk_path_terminate_output(buffer, buffer_size, pos); + + // And now tell the caller how long the whole path would be. + return pos; +} + +enum cwk_path_style cwk_path_guess_style(const char *path) +{ + const char *c; + size_t root_length; + struct cwk_segment segment; + + // First we determine the root. Only windows roots can be longer than a single + // slash, so if we can determine that it starts with something like "C:", we + // know that this is a windows path. + cwk_path_get_root_windows(path, &root_length); + if (root_length > 1) { + return CWK_STYLE_WINDOWS; + } + + // Next we check for slashes. Windows uses backslashes, while unix uses + // forward slashes. Windows actually supports both, but our best guess is to + // assume windows with backslashes and unix with forward slashes. + for (c = path; *c; ++c) { + if (*c == *separators[CWK_STYLE_UNIX]) { + return CWK_STYLE_UNIX; + } else if (*c == *separators[CWK_STYLE_WINDOWS]) { + return CWK_STYLE_WINDOWS; + } + } + + // This path does not have any slashes. We grab the last segment (which + // actually must be the first one), and determine whether the segment starts + // with a dot. A dot is a hidden folder or file in the UNIX world, in that + // case we assume the path to have UNIX style. + if (!cwk_path_get_last_segment(path, &segment)) { + // We couldn't find any segments, so we default to a UNIX path style since + // there is no way to make any assumptions. + return CWK_STYLE_UNIX; + } + + if (*segment.begin == '.') { + return CWK_STYLE_UNIX; + } + + // And finally we check whether the last segment contains a dot. If it + // contains a dot, that might be an extension. Windows is more likely to have + // file names with extensions, so our guess would be windows. + for (c = segment.begin; *c; ++c) { + if (*c == '.') { + return CWK_STYLE_WINDOWS; + } + } + + // All our checks failed, so we will return a default value which is currently + // UNIX. + return CWK_STYLE_UNIX; +} + +void cwk_path_set_style(enum cwk_path_style style) +{ + // We can just set the global path style variable and then the behaviour for + // all functions will change accordingly. + assert(style == CWK_STYLE_UNIX || style == CWK_STYLE_WINDOWS); + path_style = style; +} + +enum cwk_path_style cwk_path_get_style(void) +{ + // Simply return the path style which we store in a global variable. + return path_style; +} diff --git a/src/minivhd/cwalk.h b/src/minivhd/cwalk.h new file mode 100644 index 0000000..baa5d43 --- /dev/null +++ b/src/minivhd/cwalk.h @@ -0,0 +1,457 @@ +#pragma once + +#ifndef CWK_LIBRARY_H +#define CWK_LIBRARY_H + +#include +#include + +/** + * A segment represents a single component of a path. For instance, on linux a + * path might look like this "/var/log/", which consists of two segments "var" + * and "log". + */ +struct cwk_segment +{ + const char *path; + const char *segments; + const char *begin; + const char *end; + size_t size; +}; + +/** + * The segment type can be used to identify whether a segment is a special + * segment or not. + * + * CWK_NORMAL - normal folder or file segment + * CWK_CURRENT - "./" current folder segment + * CWK_BACK - "../" relative back navigation segment + */ +enum cwk_segment_type +{ + CWK_NORMAL, + CWK_CURRENT, + CWK_BACK +}; + +/** + * @brief Determines the style which is used for the path parsing and + * generation. + */ +enum cwk_path_style +{ + CWK_STYLE_WINDOWS, + CWK_STYLE_UNIX +}; + +/** + * @brief Generates an absolute path based on a base. + * + * This function generates an absolute path based on a base path and another + * path. It is guaranteed to return an absolute path. If the second submitted + * path is absolute, it will override the base path. The result will be written + * to a buffer, which might be truncated if the buffer is not large enough to + * hold the full path. However, the truncated result will always be + * null-terminated. The returned value is the amount of characters which the + * resulting path would take if it was not truncated (excluding the + * null-terminating character). + * + * @param base The base path on which the relative path will be applied. + * @param path The relative path which will be applied on the base path. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the new absolute path. + */ +size_t cwk_path_get_absolute(const char *base, const char *path, char *buffer, + size_t buffer_size); + +/** + * @brief Generates a relative path based on a base. + * + * This function generates a relative path based on a base path and another + * path. It determines how to get to the submitted path, starting from the base + * directory. The result will be written to a buffer, which might be truncated + * if the buffer is not large enough to hold the full path. However, the + * truncated result will always be null-terminated. The returned value is the + * amount of characters which the resulting path would take if it was not + * truncated (excluding the null-terminating character). + * + * @param base_directory The base path from which the relative path will start. + * @param path The target path where the relative path will point to. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full path. + */ +size_t cwk_path_get_relative(const char *base_directory, const char *path, + char *buffer, size_t buffer_size); + +/** + * @brief Joins two paths together. + * + * This function generates a new path by combining the two submitted paths. It + * will remove double separators, and unlike cwk_path_get_absolute it permits + * the use of two relative paths to combine. The result will be written to a + * buffer, which might be truncated if the buffer is not large enough to hold + * the full path. However, the truncated result will always be null-terminated. + * The returned value is the amount of characters which the resulting path would + * take if it was not truncated (excluding the null-terminating character). + * + * @param path_a The first path which comes first. + * @param path_b The second path which comes after the first. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full, combined path. + */ +size_t cwk_path_join(const char *path_a, const char *path_b, char *buffer, + size_t buffer_size); + +/** + * @brief Joins multiple paths together. + * + * This function generates a new path by joining multiple paths together. It + * will remove double separators, and unlike cwk_path_get_absolute it permits + * the use of multiple relative paths to combine. The last path of the submitted + * string array must be set to NULL. The result will be written to a buffer, + * which might be truncated if the buffer is not large enough to hold the full + * path. However, the truncated result will always be null-terminated. The + * returned value is the amount of characters which the resulting path would + * take if it was not truncated (excluding the null-terminating character). + * + * @param paths An array of paths which will be joined. + * @param buffer The buffer where the result will be written to. + * @param buffer_size The size of the result buffer. + * @return Returns the total amount of characters of the full, combined path. + */ +size_t cwk_path_join_multiple(const char **paths, char *buffer, + size_t buffer_size); + +/** + * @brief Determines the root of a path. + * + * This function determines the root of a path by finding it's length. The root + * always starts at the submitted path. If the path has no root, the length will + * be set to zero. + * + * @param path The path which will be inspected. + * @param length The output of the root length. + */ +void cwk_path_get_root(const char *path, size_t *length); + +/** + * @brief Changes the root of a path. + * + * This function changes the root of a path. It does not normalize the result. + * The result will be written to a buffer, which might be truncated if the + * buffer is not large enough to hold the full path. However, the truncated + * result will always be null-terminated. The returned value is the amount of + * characters which the resulting path would take if it was not truncated + * (excluding the null-terminating character). + * + * @param path The original path which will get a new root. + * @param new_root The new root which will be placed in the path. + * @param buffer The output buffer where the result is written to. + * @param buffer_size The size of the output buffer where the result is written + * to. + * @return Returns the total amount of characters of the new path. + */ +size_t cwk_path_change_root(const char *path, const char *new_root, + char *buffer, size_t buffer_size); + +/** + * @brief Determine whether the path is absolute or not. + * + * This function checks whether the path is an absolute path or not. A path is + * considered to be absolute if the root ends with a separator. + * + * @param path The path which will be checked. + * @return Returns true if the path is absolute or false otherwise. + */ +bool cwk_path_is_absolute(const char *path); + +/** + * @brief Determine whether the path is relative or not. + * + * This function checks whether the path is a relative path or not. A path is + * considered to be relative if the root does not end with a separator. + * + * @param path The path which will be checked. + * @return Returns true if the path is relative or false otherwise. + */ +bool cwk_path_is_relative(const char *path); + +/** + * @brief Gets the basename of a file path. + * + * This function gets the basename of a file path. A pointer to the beginning of + * the basename will be returned through the basename parameter. This pointer + * will be positioned on the first letter after the separator. The length of the + * file path will be returned through the length parameter. The length will be + * set to zero and the basename to NULL if there is no basename available. + * + * @param path The path which will be inspected. + * @param basename The output of the basename pointer. + * @param length The output of the length of the basename. + */ +void cwk_path_get_basename(const char *path, const char **basename, + size_t *length); + +/** + * @brief Changes the basename of a file path. + * + * This function changes the basename of a file path. This function will not + * write out more than the specified buffer can contain. However, the generated + * string is always null-terminated - even if not the whole path is written out. + * The function returns the total number of characters the complete buffer would + * have, even if it was not written out completely. The path may be the same + * memory address as the buffer. + * + * @param path The original path which will be used for the modified path. + * @param new_basename The new basename which will replace the old one. + * @param buffer The buffer where the changed path will be written to. + * @param buffer_size The size of the result buffer where the changed path is + * written to. + * @return Returns the size which the complete new path would have if it was not + * truncated. + */ +size_t cwk_path_change_basename(const char *path, const char *new_basename, + char *buffer, size_t buffer_size); + +/** + * @brief Gets the dirname of a file path. + * + * This function determines the dirname of a file path and returns the length up + * to which character is considered to be part of it. If no dirname is found, + * the length will be set to zero. The beginning of the dirname is always equal + * to the submitted path pointer. + * + * @param path The path which will be inspected. + * @param length The length of the dirname. + */ +void cwk_path_get_dirname(const char *path, size_t *length); + +/** + * @brief Gets the extension of a file path. + * + * This function extracts the extension portion of a file path. A pointer to + * the beginning of the extension will be returned through the extension + * parameter if an extension is found and true is returned. This pointer will be + * positioned on the dot. The length of the extension name will be returned + * through the length parameter. If no extension is found both parameters won't + * be touched and false will be returned. + * + * @param path The path which will be inspected. + * @param extension The output of the extension pointer. + * @param length The output of the length of the extension. + * @return Returns true if an extension is found or false otherwise. + */ +bool cwk_path_get_extension(const char *path, const char **extension, + size_t *length); + +/** + * @brief Determines whether the file path has an extension. + * + * This function determines whether the submitted file path has an extension. + * This will evaluate to true if the last segment of the path contains a dot. + * + * @param path The path which will be inspected. + * @return Returns true if the path has an extension or false otherwise. + */ +bool cwk_path_has_extension(const char *path); + +/** + * @brief Changes the extension of a file path. + * + * This function changes the extension of a file name. The function will append + * an extension if the basename does not have an extension, or use the extension + * as a basename if the path does not have a basename. This function will not + * write out more than the specified buffer can contain. However, the generated + * string is always null-terminated - even if not the whole path is written out. + * The function returns the total number of characters the complete buffer would + * have, even if it was not written out completely. The path may be the same + * memory address as the buffer. + * + * @param path The path which will be used to make the change. + * @param new_extension The extension which will be placed within the new path. + * @param buffer The output buffer where the result will be written to. + * @param buffer_size The size of the output buffer where the result will be + * written to. + * @return Returns the total size which the output would have if it was not + * truncated. + */ +size_t cwk_path_change_extension(const char *path, const char *new_extension, + char *buffer, size_t buffer_size); + +/** + * @brief Creates a normalized version of the path. + * + * This function creates a normalized version of the path within the specified + * buffer. This function will not write out more than the specified buffer can + * contain. However, the generated string is always null-terminated - even if + * not the whole path is written out. The function returns the total number of + * characters the complete buffer would have, even if it was not written out + * completely. The path may be the same memory address as the buffer. + * + * The following will be true for the normalized path: + * 1) "../" will be resolved. + * 2) "./" will be removed. + * 3) double separators will be fixed with a single separator. + * 4) separator suffixes will be removed. + * + * @param path The path which will be normalized. + * @param buffer The buffer where the new path is written to. + * @param buffer_size The size of the buffer. + * @return The size which the complete normalized path has if it was not + * truncated. + */ +size_t cwk_path_normalize(const char *path, char *buffer, size_t buffer_size); + +/** + * @brief Finds common portions in two paths. + * + * This function finds common portions in two paths and returns the number + * characters from the beginning of the base path which are equal to the other + * path. + * + * @param path_base The base path which will be compared with the other path. + * @param path_other The other path which will compared with the base path. + * @return Returns the number of characters which are common in the base path. + */ +size_t cwk_path_get_intersection(const char *path_base, const char *path_other); + +/** + * @brief Gets the first segment of a path. + * + * This function finds the first segment of a path. The position of the segment + * is set to the first character after the separator, and the length counts all + * characters until the next separator (excluding the separator). + * + * @param path The path which will be inspected. + * @param segment The segment which will be extracted. + * @return Returns true if there is a segment or false if there is none. + */ +bool cwk_path_get_first_segment(const char *path, struct cwk_segment *segment); + +/** + * @brief Gets the last segment of the path. + * + * This function gets the last segment of a path. This function may return false + * if the path doesn't contain any segments, in which case the submitted segment + * parameter is not modified. The position of the segment is set to the first + * character after the separator, and the length counts all characters until the + * end of the path (excluding the separator). + * + * @param path The path which will be inspected. + * @param segment The segment which will be extracted. + * @return Returns true if there is a segment or false if there is none. + */ +bool cwk_path_get_last_segment(const char *path, struct cwk_segment *segment); + +/** + * @brief Advances to the next segment. + * + * This function advances the current segment to the next segment. If there are + * no more segments left, the submitted segment structure will stay unchanged + * and false is returned. + * + * @param segment The current segment which will be advanced to the next one. + * @return Returns true if another segment was found or false otherwise. + */ +bool cwk_path_get_next_segment(struct cwk_segment *segment); + +/** + * @brief Moves to the previous segment. + * + * This function moves the current segment to the previous segment. If the + * current segment is the first one, the submitted segment structure will stay + * unchanged and false is returned. + * + * @param segment The current segment which will be moved to the previous one. + * @return Returns true if there is a segment before this one or false + * otherwise. + */ +bool cwk_path_get_previous_segment(struct cwk_segment *segment); + +/** + * @brief Gets the type of the submitted path segment. + * + * This function inspects the contents of the segment and determines the type of + * it. Currently, there are three types CWK_NORMAL, CWK_CURRENT and CWK_BACK. A + * CWK_NORMAL segment is a normal folder or file entry. A CWK_CURRENT is a "./" + * and a CWK_BACK a "../" segment. + * + * @param segment The segment which will be inspected. + * @return Returns the type of the segment. + */ +enum cwk_segment_type cwk_path_get_segment_type( + const struct cwk_segment *segment); + +/** + * @brief Changes the content of a segment. + * + * This function overrides the content of a segment to the submitted value and + * outputs the whole new path to the submitted buffer. The result might require + * less or more space than before if the new value length differs from the + * original length. The output is truncated if the new path is larger than the + * submitted buffer size, but it is always null-terminated. The source of the + * segment and the submitted buffer may be the same. + * + * @param segment The segment which will be modifier. + * @param value The new content of the segment. + * @param buffer The buffer where the modified path will be written to. + * @param buffer_size The size of the output buffer. + * @return Returns the total size which would have been written if the output + * was not truncated. + */ +size_t cwk_path_change_segment(struct cwk_segment *segment, const char *value, + char *buffer, size_t buffer_size); + +/** + * @brief Checks whether the submitted pointer points to a separator. + * + * This function simply checks whether the submitted pointer points to a + * separator, which has to be null-terminated (but not necessarily after the + * separator). The function will return true if it is a separator, or false + * otherwise. + * + * @param symbol A pointer to a string. + * @return Returns true if it is a separator, or false otherwise. + */ +bool cwk_path_is_separator(const char *str); + +/** + * @brief Guesses the path style. + * + * This function guesses the path style based on a submitted path-string. The + * guessing will look at the root and the type of slashes contained in the path + * and return the style which is more likely used in the path. + * + * @param path The path which will be inspected. + * @return Returns the style which is most likely used for the path. + */ +enum cwk_path_style cwk_path_guess_style(const char *path); + +/** + * @brief Configures which path style is used. + * + * This function configures which path style is used. The following styles are + * currently supported. + * + * CWK_STYLE_WINDOWS: Use backslashes as a separator and volume for the root. + * CWK_STYLE_UNIX: Use slashes as a separator and a slash for the root. + * + * @param style The style which will be used from now on. + */ +void cwk_path_set_style(enum cwk_path_style style); + +/** + * @brief Gets the path style configuration. + * + * This function gets the style configuration which is currently used for the + * paths. This configuration determines how paths are parsed and generated. + * + * @return Returns the current path style configuration. + */ +enum cwk_path_style cwk_path_get_style(void); + +#endif diff --git a/src/minivhd/libxml2_encoding.c b/src/minivhd/libxml2_encoding.c new file mode 100644 index 0000000..1c9575b --- /dev/null +++ b/src/minivhd/libxml2_encoding.c @@ -0,0 +1,447 @@ +/* + * encoding.c : implements the encoding conversion functions needed for XML + * + * Related specs: + * rfc2044 (UTF-8 and UTF-16) F. Yergeau Alis Technologies + * rfc2781 UTF-16, an encoding of ISO 10646, P. Hoffman, F. Yergeau + * [ISO-10646] UTF-8 and UTF-16 in Annexes + * [ISO-8859-1] ISO Latin-1 characters codes. + * [UNICODE] The Unicode Consortium, "The Unicode Standard -- + * Worldwide Character Encoding -- Version 1.0", Addison- + * Wesley, Volume 1, 1991, Volume 2, 1992. UTF-8 is + * described in Unicode Technical Report #4. + * [US-ASCII] Coded Character Set--7-bit American Standard Code for + * Information Interchange, ANSI X3.4-1986. + * + * See Copyright for the status of this software. + * + * daniel@veillard.com + * + * Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" + * + * Adapted and abridged for MiniVHD by Sherman Perry + */ +#include + +static int xmlLittleEndian = 1; + +/* Note: extracted from original 'void xmlInitCharEncodingHandlers(void)' function */ +void xmlEncodingInit(void) +{ + unsigned short int tst = 0x1234; + unsigned char *ptr = (unsigned char *) &tst; + + if (*ptr == 0x12) xmlLittleEndian = 0; + else if (*ptr == 0x34) xmlLittleEndian = 1; +} + +/** + * UTF16LEToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-16LE passwd as a byte array + * @inlenb: the length of @in in UTF-16LE chars + * + * Take a block of UTF-16LE ushorts in and try to convert it to an UTF-8 + * block of chars out. This function assumes the endian property + * is the same between the native type of this machine and the + * inputed one. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding fails (if *in is not a valid utf16 string) + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +int UTF16LEToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + unsigned char* outstart = out; + const unsigned char* processed = inb; + unsigned char* outend = out + *outlen; + unsigned short* in = (unsigned short*) inb; + unsigned short* inend; + unsigned int c, d, inlen; + unsigned char *tmp; + int bits; + + if ((*inlenb % 2) == 1) + (*inlenb)--; + inlen = *inlenb / 2; + inend = in + inlen; + while ((in < inend) && (out - outstart + 5 < *outlen)) { + if (xmlLittleEndian) { + c= *in++; + } else { + tmp = (unsigned char *) in; + c = *tmp++; + c = c | (((unsigned int)*tmp) << 8); + in++; + } + if ((c & 0xFC00) == 0xD800) { /* surrogates */ + if (in >= inend) { /* (in > inend) shouldn't happens */ + break; + } + if (xmlLittleEndian) { + d = *in++; + } else { + tmp = (unsigned char *) in; + d = *tmp++; + d = d | (((unsigned int)*tmp) << 8); + in++; + } + if ((d & 0xFC00) == 0xDC00) { + c &= 0x03FF; + c <<= 10; + c |= d & 0x03FF; + c += 0x10000; + } + else { + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + } + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) { *out++= c; bits= -6; } + else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; } + else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; } + + for ( ; bits >= 0; bits-= 6) { + if (out >= outend) + break; + *out++= ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlenb = processed - inb; + return(*outlen); +} + +/** + * UTF8ToUTF16LE: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16LE + * block of chars out. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding failed. + */ +int UTF8ToUTF16LE(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + unsigned short* out = (unsigned short*) outb; + const unsigned char* processed = in; + const unsigned char *const instart = in; + unsigned short* outstart= out; + unsigned short* outend; + const unsigned char* inend; + unsigned int c, d; + int trailing; + unsigned char *tmp; + unsigned short tmp1, tmp2; + + /* UTF16LE encoding has no BOM */ + if ((out == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + *outlen = 0; + *inlen = 0; + return(0); + } + inend= in + *inlen; + outend = out + (*outlen / 2); + while (in < inend) { + d= *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in UTF-16 */ + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) + break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x10000) { + if (out >= outend) + break; + if (xmlLittleEndian) { + *out++ = c; + } else { + tmp = (unsigned char *) out; + *tmp = c ; + *(tmp + 1) = c >> 8 ; + out++; + } + } + else if (c < 0x110000) { + if (out+1 >= outend) + break; + c -= 0x10000; + if (xmlLittleEndian) { + *out++ = 0xD800 | (c >> 10); + *out++ = 0xDC00 | (c & 0x03FF); + } else { + tmp1 = 0xD800 | (c >> 10); + tmp = (unsigned char *) out; + *tmp = (unsigned char) tmp1; + *(tmp + 1) = tmp1 >> 8; + out++; + + tmp2 = 0xDC00 | (c & 0x03FF); + tmp = (unsigned char *) out; + *tmp = (unsigned char) tmp2; + *(tmp + 1) = tmp2 >> 8; + out++; + } + } + else + break; + processed = in; + } + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(*outlen); +} + +/** + * UTF16BEToUTF8: + * @out: a pointer to an array of bytes to store the result + * @outlen: the length of @out + * @inb: a pointer to an array of UTF-16 passed as a byte array + * @inlenb: the length of @in in UTF-16 chars + * + * Take a block of UTF-16 ushorts in and try to convert it to an UTF-8 + * block of chars out. This function assumes the endian property + * is the same between the native type of this machine and the + * inputed one. + * + * Returns the number of bytes written, or -1 if lack of space, or -2 + * if the transcoding fails (if *in is not a valid utf16 string) + * The value of *inlen after return is the number of octets consumed + * if the return value is positive, else unpredictable. + */ +int UTF16BEToUTF8(unsigned char* out, int *outlen, + const unsigned char* inb, int *inlenb) +{ + unsigned char* outstart = out; + const unsigned char* processed = inb; + unsigned char* outend = out + *outlen; + unsigned short* in = (unsigned short*) inb; + unsigned short* inend; + unsigned int c, d, inlen; + unsigned char *tmp; + int bits; + + if ((*inlenb % 2) == 1) + (*inlenb)--; + inlen = *inlenb / 2; + inend= in + inlen; + while (in < inend) { + if (xmlLittleEndian) { + tmp = (unsigned char *) in; + c = *tmp++; + c = c << 8; + c = c | (unsigned int) *tmp; + in++; + } else { + c= *in++; + } + if ((c & 0xFC00) == 0xD800) { /* surrogates */ + if (in >= inend) { /* (in > inend) shouldn't happens */ + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + if (xmlLittleEndian) { + tmp = (unsigned char *) in; + d = *tmp++; + d = d << 8; + d = d | (unsigned int) *tmp; + in++; + } else { + d= *in++; + } + if ((d & 0xFC00) == 0xDC00) { + c &= 0x03FF; + c <<= 10; + c |= d & 0x03FF; + c += 0x10000; + } + else { + *outlen = out - outstart; + *inlenb = processed - inb; + return(-2); + } + } + + /* assertion: c is a single UTF-4 value */ + if (out >= outend) + break; + if (c < 0x80) { *out++= c; bits= -6; } + else if (c < 0x800) { *out++= ((c >> 6) & 0x1F) | 0xC0; bits= 0; } + else if (c < 0x10000) { *out++= ((c >> 12) & 0x0F) | 0xE0; bits= 6; } + else { *out++= ((c >> 18) & 0x07) | 0xF0; bits= 12; } + + for ( ; bits >= 0; bits-= 6) { + if (out >= outend) + break; + *out++= ((c >> bits) & 0x3F) | 0x80; + } + processed = (const unsigned char*) in; + } + *outlen = out - outstart; + *inlenb = processed - inb; + return(*outlen); +} + +/** + * UTF8ToUTF16BE: + * @outb: a pointer to an array of bytes to store the result + * @outlen: the length of @outb + * @in: a pointer to an array of UTF-8 chars + * @inlen: the length of @in + * + * Take a block of UTF-8 chars in and try to convert it to an UTF-16BE + * block of chars out. + * + * Returns the number of byte written, or -1 by lack of space, or -2 + * if the transcoding failed. + */ +int UTF8ToUTF16BE(unsigned char* outb, int *outlen, + const unsigned char* in, int *inlen) +{ + unsigned short* out = (unsigned short*) outb; + const unsigned char* processed = in; + const unsigned char *const instart = in; + unsigned short* outstart= out; + unsigned short* outend; + const unsigned char* inend; + unsigned int c, d; + int trailing; + unsigned char *tmp; + unsigned short tmp1, tmp2; + + /* UTF-16BE has no BOM */ + if ((outb == NULL) || (outlen == NULL) || (inlen == NULL)) return(-1); + if (in == NULL) { + *outlen = 0; + *inlen = 0; + return(0); + } + inend= in + *inlen; + outend = out + (*outlen / 2); + while (in < inend) { + d= *in++; + if (d < 0x80) { c= d; trailing= 0; } + else if (d < 0xC0) { + /* trailing byte in leading position */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } else if (d < 0xE0) { c= d & 0x1F; trailing= 1; } + else if (d < 0xF0) { c= d & 0x0F; trailing= 2; } + else if (d < 0xF8) { c= d & 0x07; trailing= 3; } + else { + /* no chance for this in UTF-16 */ + *outlen = out - outstart; + *inlen = processed - instart; + return(-2); + } + + if (inend - in < trailing) { + break; + } + + for ( ; trailing; trailing--) { + if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80)) break; + c <<= 6; + c |= d & 0x3F; + } + + /* assertion: c is a single UTF-4 value */ + if (c < 0x10000) { + if (out >= outend) break; + if (xmlLittleEndian) { + tmp = (unsigned char *) out; + *tmp = c >> 8; + *(tmp + 1) = c; + out++; + } else { + *out++ = c; + } + } + else if (c < 0x110000) { + if (out+1 >= outend) break; + c -= 0x10000; + if (xmlLittleEndian) { + tmp1 = 0xD800 | (c >> 10); + tmp = (unsigned char *) out; + *tmp = tmp1 >> 8; + *(tmp + 1) = (unsigned char) tmp1; + out++; + + tmp2 = 0xDC00 | (c & 0x03FF); + tmp = (unsigned char *) out; + *tmp = tmp2 >> 8; + *(tmp + 1) = (unsigned char) tmp2; + out++; + } else { + *out++ = 0xD800 | (c >> 10); + *out++ = 0xDC00 | (c & 0x03FF); + } + } + else + break; + processed = in; + } + *outlen = (out - outstart) * 2; + *inlen = processed - instart; + return(*outlen); +} + +/* This file is licenced under the MIT licence as follows: + +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 fur- +nished 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, FIT- +NESS 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. */ diff --git a/src/minivhd/libxml2_encoding.h b/src/minivhd/libxml2_encoding.h new file mode 100644 index 0000000..d86770b --- /dev/null +++ b/src/minivhd/libxml2_encoding.h @@ -0,0 +1,12 @@ +#ifndef LIBXML2_ENCODING_H +#define LIBXML2_ENCODING_H + +#include +typedef uint16_t mvhd_utf16; + +void xmlEncodingInit(void); +int UTF16LEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb); +int UTF8ToUTF16LE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen); +int UTF16BEToUTF8(unsigned char* out, int *outlen, const unsigned char* inb, int *inlenb); +int UTF8ToUTF16BE(unsigned char* outb, int *outlen, const unsigned char* in, int *inlen); +#endif diff --git a/src/minivhd/minivhd.h b/src/minivhd/minivhd.h new file mode 100644 index 0000000..aafd559 --- /dev/null +++ b/src/minivhd/minivhd.h @@ -0,0 +1,309 @@ +#ifndef MINIVHD_H +#define MINIVHD_H + +#include +#include +#include + +extern int mvhd_errno; + +typedef enum MVHDError { + MVHD_ERR_MEM = -128, + MVHD_ERR_FILE, + MVHD_ERR_NOT_VHD, + MVHD_ERR_TYPE, + MVHD_ERR_FOOTER_CHECKSUM, + MVHD_ERR_SPARSE_CHECKSUM, + MVHD_ERR_UTF_TRANSCODING_FAILED, + MVHD_ERR_UTF_SIZE, + MVHD_ERR_PATH_REL, + MVHD_ERR_PATH_LEN, + MVHD_ERR_PAR_NOT_FOUND, + MVHD_ERR_INVALID_PAR_UUID, + MVHD_ERR_INVALID_GEOM, + MVHD_ERR_INVALID_SIZE, + MVHD_ERR_INVALID_BLOCK_SIZE, + MVHD_ERR_INVALID_PARAMS, + MVHD_ERR_CONV_SIZE, + MVHD_ERR_TIMESTAMP +} MVHDError; + +typedef enum MVHDType { + MVHD_TYPE_FIXED = 2, + MVHD_TYPE_DYNAMIC = 3, + MVHD_TYPE_DIFF = 4 +} MVHDType; + +typedef enum MVHDBlockSize { + MVHD_BLOCK_DEFAULT = 0, /**< 2 MB blocks */ + MVHD_BLOCK_SMALL = 1024, /**< 512 KB blocks */ + MVHD_BLOCK_LARGE = 4096 /**< 2 MB blocks */ +} MVHDBlockSize; + +typedef struct MVHDGeom { + uint16_t cyl; + uint8_t heads; + uint8_t spt; +} MVHDGeom; + +typedef void (*mvhd_progress_callback)(uint32_t current_sector, uint32_t total_sectors); + +typedef struct MVHDCreationOptions { + int type; /** MVHD_TYPE_FIXED, MVHD_TYPE_DYNAMIC, or MVHD_TYPE_DIFF */ + char* path; /** Absolute path of the new VHD file */ + char* parent_path; /** For MVHD_TYPE_DIFF, this is the absolute path of the VHD's parent. For non-diff VHDs, this should be NULL. */ + uint64_t size_in_bytes; /** Total size of the VHD's virtual disk in bytes. Must be a multiple of 512. If 0, the size is auto-calculated from the geometry field. Ignored for MVHD_TYPE_DIFF. */ + MVHDGeom geometry; /** The geometry of the VHD. If set to 0, the geometry is auto-calculated from the size_in_bytes field. */ + uint32_t block_size_in_sectors; /** MVHD_BLOCK_LARGE or MVHD_BLOCK_SMALL, or 0 for the default value. The number of sectors per block. */ + mvhd_progress_callback progress_callback; /** Optional; if not NULL, gets called to indicate progress on the creation operation. Only applies to MVHD_TYPE_FIXED. */ +} MVHDCreationOptions; + +typedef struct MVHDMeta MVHDMeta; + +/** + * \brief Output a string from a MiniVHD error number + * + * \param [in] err is the error number to return string from + * + * \return Error string + */ +const char* mvhd_strerr(MVHDError err); + +/** + * \brief A simple test to see if a given file is a VHD + * + * \param [in] f file to test + * + * \retval true if f is a VHD + * \retval false if f is not a VHD + */ +bool mvhd_file_is_vhd(FILE* f); + +/** + * \brief Open a VHD image for reading and/or writing + * + * The returned pointer contains all required values and structures (and files) to + * read and write to a VHD file. + * + * Remember to call mvhd_close() when you are finished. + * + * \param [in] Absolute path to VHD file. Relative path will cause issues when opening + * a differencing VHD file + * \param [in] readonly set this to true to open the VHD in a read only manner + * \param [out] err will be set if the VHD fails to open. Value could be one of + * MVHD_ERR_MEM, MVHD_ERR_FILE, MVHD_ERR_NOT_VHD, MVHD_ERR_FOOTER_CHECKSUM, MVHD_ERR_SPARSE_CHECKSUM, + * MVHD_ERR_TYPE, MVHD_ERR_TIMESTAMP + * If MVHD_ERR_FILE is set, mvhd_errno will be set to the appropriate system errno value + * + * \return MVHDMeta pointer. If NULL, check err. err may also be set to MVHD_ERR_TIMESTAMP if + * opening a differencing VHD. + */ +MVHDMeta* mvhd_open(const char* path, bool readonly, int* err); + +/** + * \brief Update the parent modified timestamp in the VHD file + * + * Differencing VHD's use a parent last modified timestamp to try and detect if the + * parent has been modified after the child has been created. However, this is rather + * fragile and can be broken by moving/copying the parent. Also, MS DiskPart does not + * set this timestamp in the child :( + * + * Be careful when using this function that you don't update the timestamp after the + * parent actually has been modified. + * + * \param [in] vhdm Differencing VHD to update. + * \param [out] err will be set if the timestamp could not be updated + * + * \return non-zero on error, 0 on success + */ +int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err); + +/** + * \brief Create a fixed VHD image + * + * \param [in] path is the absolute path to the image to create + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [out] err indicates what error occurred, if any + * \param [out] progress_callback optional; if not NULL, gets called to indicate progress on the creation operation + * + * \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback); + +/** + * \brief Create sparse (dynamic) VHD image. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err); + +/** + * \brief Create differencing VHD imagee. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err); + +/** + * \brief Create a VHD using the provided options + * + * Use mvhd_create_ex if you want more control over the VHD's options. For quick creation, you can use mvhd_create_fixed, mvhd_create_sparse, or mvhd_create_diff. + * + * \param [in] options the VHD creation options. + * \param [out] err indicates what error occurred, if any + * + * \retval NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err); + +/** + * \brief Safely close a VHD image + * + * \param [in] vhdm MiniVHD data structure to close + */ +void mvhd_close(MVHDMeta* vhdm); + +/** + * \brief Calculate hard disk geometry from a provided size + * + * The VHD format uses Cylinder, Heads, Sectors per Track (CHS) when accessing the disk. + * The size of the disk can be determined from C * H * S * sector_size. + * + * Note, maximum geometry size (in bytes) is 65535 * 16 * 255 * 512, which is 127GB. + * However, the maximum VHD size is 2040GB. For VHDs larger than 127GB, the geometry size will be + * smaller than the actual VHD size. + * + * This function determines the appropriate CHS geometry from a provided size in bytes. + * The calculations used are those provided in "Appendix: CHS Calculation" from the document + * "Virtual Hard Disk Image Format Specification" provided by Microsoft. + * + * \param [in] size the desired VHD image size, in bytes + * + * \return MVHDGeom the calculated geometry. This can be used in the appropriate create functions. + */ +MVHDGeom mvhd_calculate_geometry(uint64_t size); + +/** + * \brief Get the CHS geometry from the image + * + * \param [in] vhdm MiniVHD data structure + * + * \return The CHS geometry as stored in the image + */ +MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm); + +/** + * \brief Get the 'current_size' value from the image + * + * Note that the size returned may not match the size calculated from the + * CHS geometry. It is up to the caller to decide how best to handle this. + * + * \param [in] vhdm MiniVHD data structure + * + * \return The 'current_size' value in bytes, as stored in the image. + * Note, this may not match the CHS geometry. + */ +uint64_t mvhd_get_current_size(MVHDMeta* vhdm); + +/** + * \brief Calculate CHS geometry size in bytes + * + * \param [in] geom the CHS geometry to calculate + * + * \return the size in bytes + */ +uint64_t mvhd_calc_size_bytes(MVHDGeom *geom); + +/** + * \brief Calculate CHS geometry size in sectors + * + * \param [in] geom the CHS geometry to calculate + * + * \return the size in sectors + */ +uint32_t mvhd_calc_size_sectors(MVHDGeom *geom); + +/** + * \brief Convert a raw disk image to a fixed VHD image + * + * \param [in] utf8_raw_path is the path of the raw image to convert + * \param [in] utf8_vhd_path is the path of the VHD to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err); + +/** + * \brief Convert a raw disk image to a sparse VHD image + * + * \param [in] utf8_raw_path is the path of the raw image to convert + * \param [in] utf8_vhd_path is the path of the VHD to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err); + +/** + * \brief Convert a VHD image to a raw disk image + * + * \param [in] utf8_vhd_path is the path of the VHD to convert + * \param [in] utf8_raw_path is the path of the raw image to create + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns the raw disk image FILE pointer + */ +FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err); + +/** + * \brief Read sectors from VHD file + * + * Read num_sectors, beginning at offset from the VHD file into a buffer + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start reading from + * \param [in] num_sectors the number of sectors to read + * \param [out] out_buff the buffer to write sector data to + * + * \return the number of sectors that were not read, or zero + */ +int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Write sectors to VHD file + * + * Write num_sectors, beginning at offset from a buffer VHD file into the VHD file + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start writing to + * \param [in] num_sectors the number of sectors to write + * \param [in] in_buffer the buffer to write sector data to + * + * \return the number of sectors that were not written, or zero + */ +int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief Write zeroed sectors to VHD file + * + * Write num_sectors, beginning at offset, of zero data into the VHD file. + * We reuse the existing write functions, with a preallocated zero buffer as + * our source buffer. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset the sector offset from which to start writing to + * \param [in] num_sectors the number of sectors to write + * + * \return the number of sectors that were not written, or zero + */ +int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors); +#endif diff --git a/src/minivhd/minivhd_convert.c b/src/minivhd/minivhd_convert.c new file mode 100644 index 0000000..1b4f4f0 --- /dev/null +++ b/src/minivhd/minivhd_convert.c @@ -0,0 +1,108 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "minivhd_create.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" +#include "minivhd.h" + +static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err); + +static FILE* mvhd_open_existing_raw_img(const char* utf8_raw_path, MVHDGeom* geom, int* err) { + FILE *raw_img = mvhd_fopen(utf8_raw_path, "rb", err); + if (raw_img == NULL) { + *err = MVHD_ERR_FILE; + return NULL; + } + if (geom == NULL) { + *err = MVHD_ERR_INVALID_GEOM; + return NULL; + } + mvhd_fseeko64(raw_img, 0, SEEK_END); + uint64_t size_bytes = (uint64_t)mvhd_ftello64(raw_img); + MVHDGeom new_geom = mvhd_calculate_geometry(size_bytes); + if (mvhd_calc_size_bytes(&new_geom) != size_bytes) { + *err = MVHD_ERR_CONV_SIZE; + return NULL; + } + geom->cyl = new_geom.cyl; + geom->heads = new_geom.heads; + geom->spt = new_geom.spt; + mvhd_fseeko64(raw_img, 0, SEEK_SET); + return raw_img; +} + +MVHDMeta* mvhd_convert_to_vhd_fixed(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) { + MVHDGeom geom; + FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err); + if (raw_img == NULL) { + return NULL; + } + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + MVHDMeta *vhdm = mvhd_create_fixed_raw(utf8_vhd_path, raw_img, size_in_bytes, &geom, err, NULL); + if (vhdm == NULL) { + return NULL; + } + return vhdm; +} +MVHDMeta* mvhd_convert_to_vhd_sparse(const char* utf8_raw_path, const char* utf8_vhd_path, int* err) { + MVHDGeom geom; + MVHDMeta *vhdm = NULL; + FILE *raw_img = mvhd_open_existing_raw_img(utf8_raw_path, &geom, err); + if (raw_img == NULL) { + return NULL; + } + vhdm = mvhd_create_sparse(utf8_vhd_path, geom, err); + if (vhdm == NULL) { + goto end; + } + uint8_t buff[4096] = {0}; // 8 sectors + uint8_t empty_buff[4096] = {0}; + int total_sectors = mvhd_calc_size_sectors(&geom); + int copy_sect = 0, i; + for (i = 0; i < total_sectors; i += 8) { + copy_sect = 8; + if ((i + 8) >= total_sectors) { + copy_sect = total_sectors - i; + memset(buff, 0, sizeof buff); + } + fread(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img); + /* Only write data if there's data to write, to take advantage of the sparse VHD format */ + if (memcmp(buff, empty_buff, sizeof buff) != 0) { + mvhd_write_sectors(vhdm, i, copy_sect, buff); + } + } +end: + fclose(raw_img); + return vhdm; +} +FILE* mvhd_convert_to_raw(const char* utf8_vhd_path, const char* utf8_raw_path, int *err) { + FILE *raw_img = mvhd_fopen(utf8_raw_path, "wb", err); + if (raw_img == NULL) { + return NULL; + } + MVHDMeta *vhdm = mvhd_open(utf8_vhd_path, true, err); + if (vhdm == NULL) { + fclose(raw_img); + return NULL; + } + uint8_t buff[4096] = {0}; // 8 sectors + int total_sectors = mvhd_calc_size_sectors((MVHDGeom*)&vhdm->footer.geom); + int copy_sect = 0, i; + for (i = 0; i < total_sectors; i += 8) { + copy_sect = 8; + if ((i + 8) >= total_sectors) { + copy_sect = total_sectors - i; + } + mvhd_read_sectors(vhdm, i, copy_sect, buff); + fwrite(buff, MVHD_SECTOR_SIZE, copy_sect, raw_img); + } + mvhd_close(vhdm); + mvhd_fseeko64(raw_img, 0, SEEK_SET); + return raw_img; +} diff --git a/src/minivhd/minivhd_create.c b/src/minivhd/minivhd_create.c new file mode 100644 index 0000000..9bb63c1 --- /dev/null +++ b/src/minivhd/minivhd_create.c @@ -0,0 +1,488 @@ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "cwalk.h" +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" +#include "minivhd_struct_rw.h" +#include "minivhd_io.h" +#include "minivhd_create.h" +#include "minivhd.h" + +static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off); +static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors); +static int mvhd_gen_par_loc(MVHDSparseHeader* header, + const char* child_path, + const char* par_path, + uint64_t start_offset, + mvhd_utf16* w2ku_path_buff, + mvhd_utf16* w2ru_path_buff, + MVHDError* err); +static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err); + +/** + * \brief Populate a VHD footer + * + * \param [in] footer to populate + * \param [in] size_in_bytes is the total size of the virtual hard disk in bytes + * \param [in] geom to use + * \param [in] type of HVD that is being created + * \param [in] sparse_header_off, an absolute file offset to the sparse header. Not used for fixed VHD images + */ +static void mvhd_gen_footer(MVHDFooter* footer, uint64_t size_in_bytes, MVHDGeom* geom, MVHDType type, uint64_t sparse_header_off) { + memcpy(footer->cookie, "conectix", sizeof footer->cookie); + footer->features = 0x00000002; + footer->fi_fmt_vers = 0x00010000; + footer->data_offset = (type == MVHD_TYPE_DIFF || type == MVHD_TYPE_DYNAMIC) ? sparse_header_off : 0xffffffffffffffff; + footer->timestamp = vhd_calc_timestamp(); + memcpy(footer->cr_app, "mvhd", sizeof footer->cr_app); + footer->cr_vers = 0x000e0000; + memcpy(footer->cr_host_os, "Wi2k", sizeof footer->cr_host_os); + footer->orig_sz = footer->curr_sz = size_in_bytes; + footer->geom.cyl = geom->cyl; + footer->geom.heads = geom->heads; + footer->geom.spt = geom->spt; + footer->disk_type = type; + mvhd_generate_uuid(footer->uuid); + footer->checksum = mvhd_gen_footer_checksum(footer); +} + +/** + * \brief Populate a VHD sparse header + * + * \param [in] header for sparse and differencing images + * \param [in] num_blks is the number of data blocks that the image contains + * \param [in] bat_offset is the absolute file offset for start of the Block Allocation Table + * \param [in] block_size_in_sectors is the block size in sectors. + */ +static void mvhd_gen_sparse_header(MVHDSparseHeader* header, uint32_t num_blks, uint64_t bat_offset, uint32_t block_size_in_sectors) { + memcpy(header->cookie, "cxsparse", sizeof header->cookie); + header->data_offset = 0xffffffffffffffff; + header->bat_offset = bat_offset; + header->head_vers = 0x00010000; + header->max_bat_ent = num_blks; + header->block_sz = block_size_in_sectors * (uint32_t)MVHD_SECTOR_SIZE; + header->checksum = mvhd_gen_sparse_checksum(header); +} + +/** + * \brief Generate parent locators for differencing VHD images + * + * \param [in] header the sparse header to populate with parent locator entries + * \param [in] child_path is the full path to the VHD being created + * \param [in] par_path is the full path to the parent image + * \param [in] start_offset is the absolute file offset from where to start storing the entries themselves. Must be sector aligned. + * \param [out] w2ku_path_buff is a buffer containing the full path to the parent, encoded as UTF16-LE + * \param [out] w2ru_path_buff is a buffer containing the relative path to the parent, encoded as UTF16-LE + * \param [out] err indicates what error occurred, if any + * + * \retval 0 if success + * \retval < 0 if an error occurrs. Check value of *err for actual error + */ +static int mvhd_gen_par_loc(MVHDSparseHeader* header, + const char* child_path, + const char* par_path, + uint64_t start_offset, + mvhd_utf16* w2ku_path_buff, + mvhd_utf16* w2ru_path_buff, + MVHDError* err) { + /* Get our paths to store in the differencing VHD. We want both the absolute path to the parent, + as well as the relative path from the child VHD */ + int rv = 0; + char* par_filename; + size_t par_fn_len; + char rel_path[MVHD_MAX_PATH_BYTES] = {0}; + char child_dir[MVHD_MAX_PATH_BYTES] = {0}; + size_t child_dir_len; + if (strlen(child_path) < sizeof child_dir) { + strcpy(child_dir, child_path); + } else { + *err = MVHD_ERR_PATH_LEN; + rv = -1; + goto end; + } + cwk_path_get_basename(par_path, (const char**)&par_filename, &par_fn_len); + cwk_path_get_dirname(child_dir, &child_dir_len); + child_dir[child_dir_len] = '\0'; + size_t rel_len = cwk_path_get_relative(child_dir, par_path, rel_path, sizeof rel_path); + if (rel_len > sizeof rel_path) { + *err = MVHD_ERR_PATH_LEN; + rv = -1; + goto end; + } + /* We have our paths, now store the parent filename directly in the sparse header. */ + int outlen = sizeof header->par_utf16_name; + int utf_ret; + utf_ret = UTF8ToUTF16BE((unsigned char*)header->par_utf16_name, &outlen, (const unsigned char*)par_filename, (int*)&par_fn_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + + /* And encode the paths to UTF16-LE */ + size_t par_path_len = strlen(par_path); + outlen = sizeof *w2ku_path_buff * MVHD_MAX_PATH_CHARS; + utf_ret = UTF8ToUTF16LE((unsigned char*)w2ku_path_buff, &outlen, (const unsigned char*)par_path, (int*)&par_path_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + int w2ku_len = utf_ret; + outlen = sizeof *w2ru_path_buff * MVHD_MAX_PATH_CHARS; + utf_ret = UTF8ToUTF16LE((unsigned char*)w2ru_path_buff, &outlen, (const unsigned char*)rel_path, (int*)&rel_len); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, (int*)err); + rv = -1; + goto end; + } + int w2ru_len = utf_ret; + /** + * Finally populate the parent locaters in the sparse header. + * This is the information needed to find the paths saved elsewhere + * in the VHD image + */ + + /* Note about the plat_data_space field: The VHD spec says this field stores the number of sectors needed to store the locator path. + * However, Hyper-V and VPC store the number of bytes, not the number of sectors, and will refuse to open VHDs which have the + * number of sectors in this field. + * See https://stackoverflow.com/questions/40760181/mistake-in-virtual-hard-disk-image-format-specification + */ + header->par_loc_entry[0].plat_code = MVHD_DIF_LOC_W2KU; + header->par_loc_entry[0].plat_data_len = (uint32_t)w2ku_len; + header->par_loc_entry[0].plat_data_offset = (uint64_t)start_offset; + header->par_loc_entry[0].plat_data_space = ((header->par_loc_entry[0].plat_data_len / MVHD_SECTOR_SIZE) + 1) * MVHD_SECTOR_SIZE; + header->par_loc_entry[1].plat_code = MVHD_DIF_LOC_W2RU; + header->par_loc_entry[1].plat_data_len = (uint32_t)w2ru_len; + header->par_loc_entry[1].plat_data_offset = (uint64_t)start_offset + ((uint64_t)header->par_loc_entry[0].plat_data_space); + header->par_loc_entry[1].plat_data_space = ((header->par_loc_entry[1].plat_data_len / MVHD_SECTOR_SIZE) + 1) * MVHD_SECTOR_SIZE; + goto end; + +end: + return rv; +} + +MVHDMeta* mvhd_create_fixed(const char* path, MVHDGeom geom, int* err, mvhd_progress_callback progress_callback) { + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + return mvhd_create_fixed_raw(path, NULL, size_in_bytes, &geom, err, progress_callback); +} + +/** + * \brief internal function that implements public mvhd_create_fixed() functionality + * + * Contains one more parameter than the public function, to allow using an existing + * raw disk image as the data source for the new fixed VHD. + * + * \param [in] raw_image file handle to a raw disk image to populate VHD + */ +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback) { + uint8_t img_data[MVHD_SECTOR_SIZE] = {0}; + uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; + MVHDMeta* vhdm = calloc(1, sizeof *vhdm); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) { + *err = MVHD_ERR_INVALID_GEOM; + goto cleanup_vhdm; + } + FILE* f = mvhd_fopen(path, "wb+", err); + if (f == NULL) { + goto cleanup_vhdm; + } + mvhd_fseeko64(f, 0, SEEK_SET); + uint32_t size_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE); + uint32_t s; + if (progress_callback) + progress_callback(0, size_sectors); + if (raw_img != NULL) { + mvhd_fseeko64(raw_img, 0, SEEK_END); + uint64_t raw_size = (uint64_t)mvhd_ftello64(raw_img); + MVHDGeom raw_geom = mvhd_calculate_geometry(raw_size); + if (mvhd_calc_size_bytes(&raw_geom) != raw_size) { + *err = MVHD_ERR_CONV_SIZE; + goto cleanup_vhdm; + } + mvhd_gen_footer(&vhdm->footer, raw_size, geom, MVHD_TYPE_FIXED, 0); + mvhd_fseeko64(raw_img, 0, SEEK_SET); + for (s = 0; s < size_sectors; s++) { + fread(img_data, sizeof img_data, 1, raw_img); + fwrite(img_data, sizeof img_data, 1, f); + if (progress_callback) + progress_callback(s + 1, size_sectors); + } + } else { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_FIXED, 0); + for (s = 0; s < size_sectors; s++) { + fwrite(img_data, sizeof img_data, 1, f); + if (progress_callback) + progress_callback(s + 1, size_sectors); + } + } + mvhd_footer_to_buffer(&vhdm->footer, footer_buff); + fwrite(footer_buff, sizeof footer_buff, 1, f); + fclose(f); + f = NULL; + free(vhdm); + vhdm = mvhd_open(path, false, err); + goto end; + +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +end: + return vhdm; +} + +/** + * \brief Create sparse or differencing VHD image. + * + * \param [in] path is the absolute path to the VHD file to create + * \param [in] par_path is the absolute path to a parent image. If NULL, a sparse image is created, otherwise create a differencing image + * \param [in] size_in_bytes is the total size in bytes of the virtual hard disk image + * \param [in] geom is the HDD geometry of the image to create. Determines final image size + * \param [in] block_size_in_sectors is the block size in sectors + * \param [out] err indicates what error occurred, if any + * + * \return NULL if an error occurrs. Check value of *err for actual error. Otherwise returns pointer to a MVHDMeta struct + */ +static MVHDMeta* mvhd_create_sparse_diff(const char* path, const char* par_path, uint64_t size_in_bytes, MVHDGeom* geom, uint32_t block_size_in_sectors, int* err) { + uint8_t footer_buff[MVHD_FOOTER_SIZE] = {0}; + uint8_t sparse_buff[MVHD_SPARSE_SIZE] = {0}; + uint8_t bat_sect[MVHD_SECTOR_SIZE]; + MVHDGeom par_geom = {0}; + memset(bat_sect, 0xffffffff, sizeof bat_sect); + MVHDMeta* vhdm = NULL; + MVHDMeta* par_vhdm = NULL; + mvhd_utf16* w2ku_path_buff = NULL; + mvhd_utf16* w2ru_path_buff = NULL; + uint32_t par_mod_timestamp = 0; + if (par_path != NULL) { + par_mod_timestamp = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + goto end; + } + par_vhdm = mvhd_open(par_path, true, err); + if (par_vhdm == NULL) { + goto end; + } + } + vhdm = calloc(1, sizeof *vhdm); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto cleanup_par_vhdm; + } + if (par_vhdm != NULL) { + /* We use the geometry from the parent VHD, not what was passed in */ + par_geom.cyl = par_vhdm->footer.geom.cyl; + par_geom.heads = par_vhdm->footer.geom.heads; + par_geom.spt = par_vhdm->footer.geom.spt; + geom = &par_geom; + size_in_bytes = par_vhdm->footer.curr_sz; + } else if (geom == NULL || (geom->cyl == 0 || geom->heads == 0 || geom->spt == 0)) { + *err = MVHD_ERR_INVALID_GEOM; + goto cleanup_vhdm; + } + + FILE* f = mvhd_fopen(path, "wb+", err); + if (f == NULL) { + goto cleanup_vhdm; + } + mvhd_fseeko64(f, 0, SEEK_SET); + /* Note, the sparse header follows the footer copy at the beginning of the file */ + if (par_path == NULL) { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DYNAMIC, MVHD_FOOTER_SIZE); + } else { + mvhd_gen_footer(&vhdm->footer, size_in_bytes, geom, MVHD_TYPE_DIFF, MVHD_FOOTER_SIZE); + } + mvhd_footer_to_buffer(&vhdm->footer, footer_buff); + /* As mentioned, start with a copy of the footer */ + fwrite(footer_buff, sizeof footer_buff, 1, f); + /** + * Calculate the number of (2MB or 512KB) data blocks required to store the entire + * contents of the disk image, followed by the number of sectors the + * BAT occupies in the image. Note, the BAT is sector aligned, and is padded + * to the next sector boundary + * */ + uint32_t size_in_sectors = (uint32_t)(size_in_bytes / MVHD_SECTOR_SIZE); + uint32_t num_blks = size_in_sectors / block_size_in_sectors; + if (size_in_sectors % block_size_in_sectors != 0) { + num_blks += 1; + } + uint32_t num_bat_sect = num_blks / MVHD_BAT_ENT_PER_SECT; + if (num_blks % MVHD_BAT_ENT_PER_SECT != 0) { + num_bat_sect += 1; + } + /* Storing the BAT directly following the footer and header */ + uint64_t bat_offset = MVHD_FOOTER_SIZE + MVHD_SPARSE_SIZE; + uint64_t par_loc_offset = 0; + + /** + * If creating a differencing VHD, populate the sparse header with additional + * data about the parent image, and where to find it, and it's last modified timestamp + * */ + if (par_vhdm != NULL) { + /** + * Create output buffers to encode paths into. + * The paths are not stored directly in the sparse header, hence the need to + * store them in buffers to be written to the VHD image later + */ + w2ku_path_buff = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ku_path_buff); + if (w2ku_path_buff == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + w2ru_path_buff = calloc(MVHD_MAX_PATH_CHARS, sizeof * w2ru_path_buff); + if (w2ru_path_buff == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + memcpy(vhdm->sparse.par_uuid, par_vhdm->footer.uuid, sizeof vhdm->sparse.par_uuid); + par_loc_offset = bat_offset + ((uint64_t)num_bat_sect * MVHD_SECTOR_SIZE) + (5 * MVHD_SECTOR_SIZE); + if (mvhd_gen_par_loc(&vhdm->sparse, path, par_path, par_loc_offset, w2ku_path_buff, w2ru_path_buff, (MVHDError*)err) < 0) { + goto cleanup_vhdm; + } + vhdm->sparse.par_timestamp = par_mod_timestamp; + } + mvhd_gen_sparse_header(&vhdm->sparse, num_blks, bat_offset, block_size_in_sectors); + mvhd_header_to_buffer(&vhdm->sparse, sparse_buff); + fwrite(sparse_buff, sizeof sparse_buff, 1, f); + /* The BAT sectors need to be filled with 0xffffffff */ + uint32_t i; + for (i = 0; i < num_bat_sect; i++) { + fwrite(bat_sect, sizeof bat_sect, 1, f); + } + mvhd_write_empty_sectors(f, 5); + /** + * If creating a differencing VHD, the paths to the parent image need to be written + * tp the file. Both absolute and relative paths are written + * */ + if (par_vhdm != NULL) { + uint64_t curr_pos = (uint64_t)mvhd_ftello64(f); + /* Double check my sums... */ + assert(curr_pos == par_loc_offset); + /* Fill the space required for location data with zero */ + uint8_t empty_sect[MVHD_SECTOR_SIZE] = {0}; + int i; + uint32_t j; + for (i = 0; i < 2; i++) { + for (j = 0; j < (vhdm->sparse.par_loc_entry[i].plat_data_space / MVHD_SECTOR_SIZE); j++) { + fwrite(empty_sect, sizeof empty_sect, 1, f); + } + } + /* Now write the location entries */ + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[0].plat_data_offset, SEEK_SET); + fwrite(w2ku_path_buff, vhdm->sparse.par_loc_entry[0].plat_data_len, 1, f); + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset, SEEK_SET); + fwrite(w2ru_path_buff, vhdm->sparse.par_loc_entry[1].plat_data_len, 1, f); + /* and reset the file position to continue */ + mvhd_fseeko64(f, vhdm->sparse.par_loc_entry[1].plat_data_offset + vhdm->sparse.par_loc_entry[1].plat_data_space, SEEK_SET); + mvhd_write_empty_sectors(f, 5); + } + /* And finish with the footer */ + fwrite(footer_buff, sizeof footer_buff, 1, f); + fclose(f); + f = NULL; + free(vhdm); + vhdm = mvhd_open(path, false, err); + goto end; + +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +cleanup_par_vhdm: + if (par_vhdm != NULL) { + mvhd_close(par_vhdm); + } +end: + free(w2ku_path_buff); + free(w2ru_path_buff); + return vhdm; +} + +MVHDMeta* mvhd_create_sparse(const char* path, MVHDGeom geom, int* err) { + uint64_t size_in_bytes = mvhd_calc_size_bytes(&geom); + return mvhd_create_sparse_diff(path, NULL, size_in_bytes, &geom, MVHD_BLOCK_LARGE, err); +} + +MVHDMeta* mvhd_create_diff(const char* path, const char* par_path, int* err) { + return mvhd_create_sparse_diff(path, par_path, 0, NULL, MVHD_BLOCK_LARGE, err); +} + +MVHDMeta* mvhd_create_ex(MVHDCreationOptions options, int* err) { + uint32_t geom_sector_size; + switch (options.type) + { + case MVHD_TYPE_FIXED: + case MVHD_TYPE_DYNAMIC: + geom_sector_size = mvhd_calc_size_sectors(&(options.geometry)); + if ((options.size_in_bytes > 0 && (options.size_in_bytes % MVHD_SECTOR_SIZE) > 0) + || (options.size_in_bytes > MVHD_MAX_SIZE_IN_BYTES) + || (options.size_in_bytes == 0 && geom_sector_size == 0)) + { + *err = MVHD_ERR_INVALID_SIZE; + return NULL; + } + + if (options.size_in_bytes > 0 && ((uint64_t)geom_sector_size * MVHD_SECTOR_SIZE) > options.size_in_bytes) + { + *err = MVHD_ERR_INVALID_GEOM; + return NULL; + } + + if (options.size_in_bytes == 0) + options.size_in_bytes = (uint64_t)geom_sector_size * MVHD_SECTOR_SIZE; + + if (geom_sector_size == 0) + options.geometry = mvhd_calculate_geometry(options.size_in_bytes); + break; + case MVHD_TYPE_DIFF: + if (options.parent_path == NULL) + { + *err = MVHD_ERR_FILE; + return NULL; + } + break; + default: + *err = MVHD_ERR_TYPE; + return NULL; + } + + if (options.path == NULL) + { + *err = MVHD_ERR_FILE; + return NULL; + } + + if (options.type != MVHD_TYPE_FIXED) + { + if (options.block_size_in_sectors == MVHD_BLOCK_DEFAULT) + options.block_size_in_sectors = MVHD_BLOCK_LARGE; + + if (options.block_size_in_sectors != MVHD_BLOCK_LARGE && options.block_size_in_sectors != MVHD_BLOCK_SMALL) + { + *err = MVHD_ERR_INVALID_BLOCK_SIZE; + return NULL; + } + } + + switch (options.type) + { + case MVHD_TYPE_FIXED: + return mvhd_create_fixed_raw(options.path, NULL, options.size_in_bytes, &(options.geometry), err, options.progress_callback); + case MVHD_TYPE_DYNAMIC: + return mvhd_create_sparse_diff(options.path, NULL, options.size_in_bytes, &(options.geometry), options.block_size_in_sectors, err); + case MVHD_TYPE_DIFF: + return mvhd_create_sparse_diff(options.path, options.parent_path, 0, NULL, options.block_size_in_sectors, err); + } + + return NULL; /* Make the compiler happy */ +} diff --git a/src/minivhd/minivhd_create.h b/src/minivhd/minivhd_create.h new file mode 100644 index 0000000..203834a --- /dev/null +++ b/src/minivhd/minivhd_create.h @@ -0,0 +1,8 @@ +#ifndef MINIVHD_CREATE_H +#define MINIVHD_CREATE_H +#include +#include "minivhd.h" + +MVHDMeta* mvhd_create_fixed_raw(const char* path, FILE* raw_img, uint64_t size_in_bytes, MVHDGeom* geom, int* err, mvhd_progress_callback progress_callback); + +#endif diff --git a/src/minivhd/minivhd_internal.h b/src/minivhd/minivhd_internal.h new file mode 100644 index 0000000..f42ca58 --- /dev/null +++ b/src/minivhd/minivhd_internal.h @@ -0,0 +1,96 @@ +#ifndef MINIVHD_INTERNAL_H +#define MINIVHD_INTERNAL_H +#include +#include +#include +#include "minivhd.h" /* Pull in the MVHDMeta typedef */ + +#define MVHD_FOOTER_SIZE 512 +#define MVHD_SPARSE_SIZE 1024 + +#define MVHD_SECTOR_SIZE 512 +#define MVHD_BAT_ENT_PER_SECT 128 + +#define MVHD_MAX_SIZE_IN_BYTES 0x1fe00000000 + +#define MVHD_SPARSE_BLK 0xffffffff +/* For simplicity, we don't handle paths longer than this + * Note, this is the max path in characters, as that is what + * Windows uses + */ +#define MVHD_MAX_PATH_CHARS 260 +#define MVHD_MAX_PATH_BYTES 1040 + +#define MVHD_DIF_LOC_W2RU 0x57327275 +#define MVHD_DIF_LOC_W2KU 0x57326B75 + +typedef struct MVHDSectorBitmap { + uint8_t* curr_bitmap; + int sector_count; + int curr_block; +} MVHDSectorBitmap; + +typedef struct MVHDFooter { + uint8_t cookie[8]; + uint32_t features; + uint32_t fi_fmt_vers; + uint64_t data_offset; + uint32_t timestamp; + uint8_t cr_app[4]; + uint32_t cr_vers; + uint8_t cr_host_os[4]; + uint64_t orig_sz; + uint64_t curr_sz; + struct { + uint16_t cyl; + uint8_t heads; + uint8_t spt; + } geom; + uint32_t disk_type; + uint32_t checksum; + uint8_t uuid[16]; + uint8_t saved_st; + uint8_t reserved[427]; +} MVHDFooter; + +typedef struct MVHDSparseHeader { + uint8_t cookie[8]; + uint64_t data_offset; + uint64_t bat_offset; + uint32_t head_vers; + uint32_t max_bat_ent; + uint32_t block_sz; + uint32_t checksum; + uint8_t par_uuid[16]; + uint32_t par_timestamp; + uint32_t reserved_1; + uint8_t par_utf16_name[512]; + struct { + uint32_t plat_code; + uint32_t plat_data_space; + uint32_t plat_data_len; + uint32_t reserved; + uint64_t plat_data_offset; + } par_loc_entry[8]; + uint8_t reserved_2[256]; +} MVHDSparseHeader; + +struct MVHDMeta { + FILE* f; + bool readonly; + char filename[MVHD_MAX_PATH_BYTES]; + struct MVHDMeta* parent; + MVHDFooter footer; + MVHDSparseHeader sparse; + uint32_t* block_offset; + int sect_per_block; + MVHDSectorBitmap bitmap; + int (*read_sectors)(MVHDMeta*, uint32_t, int, void*); + int (*write_sectors)(MVHDMeta*, uint32_t, int, void*); + struct { + uint8_t* zero_data; + int sector_count; + } format_buffer; +}; + +#endif diff --git a/src/minivhd/minivhd_io.c b/src/minivhd/minivhd_io.c new file mode 100644 index 0000000..c21f68d --- /dev/null +++ b/src/minivhd/minivhd_io.c @@ -0,0 +1,281 @@ +/** + * \file + * \brief Sector reading and writing implementations + */ + +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include "minivhd_internal.h" +#include "minivhd_util.h" + +/* The following bit array macros adapted from + http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html */ + +#define VHD_SETBIT(A,k) ( A[(k/8)] |= (0x80 >> (k%8)) ) +#define VHD_CLEARBIT(A,k) ( A[(k/8)] &= ~(0x80 >> (k%8)) ) +#define VHD_TESTBIT(A,k) ( A[(k/8)] & (0x80 >> (k%8)) ) + +static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect); +static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk); +static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk); +static void mvhd_create_block(MVHDMeta* vhdm, int blk); +static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm); + +/** + * \brief Check that we will not be overflowing buffers + * + * \param [in] offset The offset from which we are beginning from + * \param [in] num_sectors The number of sectors which we desire to read/write + * \param [in] total_sectors The total number of sectors available + * \param [out] transfer_sect The number of sectors to actually write. + * This may be lower than num_sectors if offset + num_sectors >= total_sectors + * \param [out] trunc_sectors The number of sectors truncated if transfer_sectors < num_sectors + */ +static inline void mvhd_check_sectors(uint32_t offset, int num_sectors, uint32_t total_sectors, int* transfer_sect, int* trunc_sect) { + *transfer_sect = num_sectors; + *trunc_sect = 0; + if ((total_sectors - offset) < (uint32_t)*transfer_sect) { + *transfer_sect = total_sectors - offset; + *trunc_sect = num_sectors - *transfer_sect; + } +} + +void mvhd_write_empty_sectors(FILE* f, int sector_count) { + uint8_t zero_bytes[MVHD_SECTOR_SIZE] = {0}; + int i; + for (i = 0; i < sector_count; i++) { + fwrite(zero_bytes, sizeof zero_bytes, 1, f); + } +} + +/** + * \brief Read the sector bitmap for a block. + * + * If the block is sparse, the sector bitmap in memory will be + * zeroed. Otherwise, the sector bitmap is read from the VHD file. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block for which to read the sector bitmap from + */ +static void mvhd_read_sect_bitmap(MVHDMeta* vhdm, int blk) { + if (vhdm->block_offset[blk] != MVHD_SPARSE_BLK) { + mvhd_fseeko64(vhdm->f, (uint64_t)vhdm->block_offset[blk] * MVHD_SECTOR_SIZE, SEEK_SET); + fread(vhdm->bitmap.curr_bitmap, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE, 1, vhdm->f); + } else { + memset(vhdm->bitmap.curr_bitmap, 0, vhdm->bitmap.sector_count * MVHD_SECTOR_SIZE); + } + vhdm->bitmap.curr_block = blk; +} + +/** + * \brief Write the current sector bitmap in memory to file + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_write_curr_sect_bitmap(MVHDMeta* vhdm) { + if (vhdm->bitmap.curr_block >= 0) { + int64_t abs_offset = (int64_t)vhdm->block_offset[vhdm->bitmap.curr_block] * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, abs_offset, SEEK_SET); + fwrite(vhdm->bitmap.curr_bitmap, MVHD_SECTOR_SIZE, vhdm->bitmap.sector_count, vhdm->f); + } +} + +/** + * \brief Write block offset from memory into file + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block for which to write the offset for + */ +static void mvhd_write_bat_entry(MVHDMeta* vhdm, int blk) { + uint64_t table_offset = vhdm->sparse.bat_offset + ((uint64_t)blk * sizeof *vhdm->block_offset); + uint32_t offset = mvhd_to_be32(vhdm->block_offset[blk]); + mvhd_fseeko64(vhdm->f, table_offset, SEEK_SET); + fwrite(&offset, sizeof offset, 1, vhdm->f); +} + +/** + * \brief Create an empty block in a sparse or differencing VHD image + * + * VHD images store data in blocks, which are typically 4096 sectors in size + * (~2MB). These blocks may be stored on disk in any order. Blocks are created + * on demand when required. + * + * This function creates new, empty blocks, by replacing the footer at the end of the file + * and then re-inserting the footer at the new file end. The BAT table entry for the + * new block is updated with the new offset. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] blk The block number to create + */ +static void mvhd_create_block(MVHDMeta* vhdm, int blk) { + uint8_t footer[MVHD_FOOTER_SIZE]; + /* Seek to where the footer SHOULD be */ + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(footer, sizeof footer, 1, vhdm->f); + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + if (!mvhd_is_conectix_str(footer)) { + /* Oh dear. We use the header instead, since something has gone wrong at the footer */ + mvhd_fseeko64(vhdm->f, 0, SEEK_SET); + fread(footer, sizeof footer, 1, vhdm->f); + mvhd_fseeko64(vhdm->f, 0, SEEK_END); + } + int64_t abs_offset = mvhd_ftello64(vhdm->f); + if (abs_offset % MVHD_SECTOR_SIZE != 0) { + /* Yikes! We're supposed to be on a sector boundary. Add some padding */ + int64_t padding_amount = (int64_t)MVHD_SECTOR_SIZE - (abs_offset % MVHD_SECTOR_SIZE); + uint8_t zero_byte = 0; + int i; + for (i = 0; i < padding_amount; i++) { + fwrite(&zero_byte, sizeof zero_byte, 1, vhdm->f); + } + abs_offset += padding_amount; + } + uint32_t sect_offset = (uint32_t)(abs_offset / MVHD_SECTOR_SIZE); + int blk_size_sectors = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE; + mvhd_write_empty_sectors(vhdm->f, vhdm->bitmap.sector_count + blk_size_sectors); + /* Add a bit of padding. That's what Windows appears to do, although it's not strictly necessary... */ + mvhd_write_empty_sectors(vhdm->f, 5); + /* And we finish with the footer */ + fwrite(footer, sizeof footer, 1, vhdm->f); + /* We no longer have a sparse block. Update that BAT! */ + vhdm->block_offset[blk] = sect_offset; + mvhd_write_bat_entry(vhdm, blk); +} + +int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int64_t addr; + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + addr = (int64_t)offset * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + fread(out_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f); + return truncated_sectors; +} + +int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)out_buff; + int64_t addr; + uint32_t s, ls; + int blk, prev_blk, sib; + ls = offset + transfer_sectors; + prev_blk = -1; + for (s = offset; s < ls; s++) { + blk = s / vhdm->sect_per_block; + sib = s % vhdm->sect_per_block; + if (blk != prev_blk) { + prev_blk = blk; + if (vhdm->bitmap.curr_block != blk) { + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); + } else { + addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + } + } + if (VHD_TESTBIT(vhdm->bitmap.curr_bitmap, sib)) { + fread(buff, MVHD_SECTOR_SIZE, 1, vhdm->f); + } else { + memset(buff, 0, MVHD_SECTOR_SIZE); + mvhd_fseeko64(vhdm->f, MVHD_SECTOR_SIZE, SEEK_CUR); + } + buff += MVHD_SECTOR_SIZE; + } + return truncated_sectors; +} + +int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)out_buff; + MVHDMeta* curr_vhdm = vhdm; + uint32_t s, ls; + int blk, sib; + ls = offset + transfer_sectors; + for (s = offset; s < ls; s++) { + while (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF) { + blk = s / curr_vhdm->sect_per_block; + sib = s % curr_vhdm->sect_per_block; + if (curr_vhdm->bitmap.curr_block != blk) { + mvhd_read_sect_bitmap(curr_vhdm, blk); + } + if (!VHD_TESTBIT(curr_vhdm->bitmap.curr_bitmap, sib)) { + curr_vhdm = curr_vhdm->parent; + } else { break; } + } + /* We handle actual sector reading using the fixed or sparse functions, + as a differencing VHD is also a sparse VHD */ + if (curr_vhdm->footer.disk_type == MVHD_TYPE_DIFF || curr_vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) { + mvhd_sparse_read(curr_vhdm, s, 1, buff); + } else { + mvhd_fixed_read(curr_vhdm, s, 1, buff); + } + curr_vhdm = vhdm; + buff += MVHD_SECTOR_SIZE; + } + return truncated_sectors; +} + +int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + int64_t addr; + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + addr = (int64_t)offset * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + fwrite(in_buff, transfer_sectors*MVHD_SECTOR_SIZE, 1, vhdm->f); + return truncated_sectors; +} + +int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + int transfer_sectors, truncated_sectors; + uint32_t total_sectors = (uint32_t)(vhdm->footer.curr_sz / MVHD_SECTOR_SIZE); + mvhd_check_sectors(offset, num_sectors, total_sectors, &transfer_sectors, &truncated_sectors); + uint8_t* buff = (uint8_t*)in_buff; + int64_t addr; + uint32_t s, ls; + int blk, prev_blk, sib; + ls = offset + transfer_sectors; + prev_blk = -1; + for (s = offset; s < ls; s++) { + blk = s / vhdm->sect_per_block; + sib = s % vhdm->sect_per_block; + if (vhdm->bitmap.curr_block != blk && prev_blk >= 0) { + /* Write the sector bitmap for the previous block, before we replace it. */ + mvhd_write_curr_sect_bitmap(vhdm); + } + if (vhdm->block_offset[blk] == MVHD_SPARSE_BLK) { + /* "read" the sector bitmap first, before creating a new block, as the bitmap will be + zero either way */ + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_create_block(vhdm, blk); + } + if (blk != prev_blk) { + if (vhdm->bitmap.curr_block != blk) { + mvhd_read_sect_bitmap(vhdm, blk); + mvhd_fseeko64(vhdm->f, (uint64_t)sib * MVHD_SECTOR_SIZE, SEEK_CUR); + } else { + addr = ((int64_t)vhdm->block_offset[blk] + vhdm->bitmap.sector_count + sib) * MVHD_SECTOR_SIZE; + mvhd_fseeko64(vhdm->f, addr, SEEK_SET); + } + prev_blk = blk; + } + fwrite(buff, MVHD_SECTOR_SIZE, 1, vhdm->f); + VHD_SETBIT(vhdm->bitmap.curr_bitmap, sib); + buff += MVHD_SECTOR_SIZE; + } + /* And write the sector bitmap for the last block we visited to disk */ + mvhd_write_curr_sect_bitmap(vhdm); + return truncated_sectors; +} + +int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + return 0; +} diff --git a/src/minivhd/minivhd_io.h b/src/minivhd/minivhd_io.h new file mode 100644 index 0000000..0f4017a --- /dev/null +++ b/src/minivhd/minivhd_io.h @@ -0,0 +1,132 @@ +#ifndef MINIVHD_IO_H +#define MINIVHD_IO_H +#include "minivhd.h" + +/** + * \brief Write zero filled sectors to file. + * + * Note, the caller should set the file position before calling this + * function for correct operation. + * + * \param [in] f File to write sectors to + * \param [in] sector_count The number of sectors to write + */ +void mvhd_write_empty_sectors(FILE* f, int sector_count); + +/** + * \brief Read a fixed VHD image + * + * Fixed VHD images are essentially raw image files with a footer tacked on + * the end. They are therefore straightforward to write + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_fixed_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Read a sparse VHD image + * + * Sparse, or dynamic images are VHD images that grow as data is written to them. + * + * This function implements the logic to read sectors from the file, taking into + * account the fact that blocks may be stored on disk in any order, and that the + * read could cross block boundaries. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_sparse_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Read a differencing VHD image + * + * Differencing images are a variant of a sparse image. They contain the grow-on-demand + * properties of sparse images, but also reference a parent image. Data is read from the + * child image only if it is newer than the data stored in the parent image. + * + * This function implements the logic to read sectors from the child, or a parent image. + * Differencing images may have a differencing image as a parent, creating a chain of images. + * There is no theoretical chain length limit, although I do not consider long chains to be + * advisable. Verifying the parent-child relationship is not very robust. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to read from + * \param [in] num_sectors The desired number of sectors to read + * \param [out] out_buff An output buffer to store read sectors. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were read from file + * \retval >0 < num_sectors were read from file + */ +int mvhd_diff_read(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff); + +/** + * \brief Write to a fixed VHD image + * + * Fixed VHD images are essentially raw image files with a footer tacked on + * the end. They are therefore straightforward to write + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_fixed_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief Write to a sparse or differencing VHD image + * + * Sparse, or dynamic images are VHD images that grow as data is written to them. + * + * Differencing images are a variant of a sparse image. They contain the grow-on-demand + * properties of sparse images, but also reference a parent image. Data is always written + * to the child image. This makes writing to differencing images essentially identical to + * writing to sparse images, hence they use the same function. + * + * This function implements the logic to write sectors to the file, taking into + * account the fact that blocks may be stored on disk in any order, and that the + * write operation could cross block boundaries. + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_sparse_diff_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +/** + * \brief A no-op function to "write" to read-only VHD images + * + * \param [in] vhdm MiniVHD data structure + * \param [in] offset Sector offset to write to + * \param [in] num_sectors The desired number of sectors to write + * \param [in] in_buff A source buffer to write sectors from. Must be + * large enough to hold num_sectors worth of sectors. + * + * \retval 0 num_sectors were written to file + * \retval >0 < num_sectors were written to file + */ +int mvhd_noop_write(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff); + +#endif diff --git a/src/minivhd/minivhd_manage.c b/src/minivhd/minivhd_manage.c new file mode 100644 index 0000000..d852a94 --- /dev/null +++ b/src/minivhd/minivhd_manage.c @@ -0,0 +1,538 @@ +/** + * \file + * \brief VHD management functions (open, close, read write etc) + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "cwalk.h" +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_io.h" +#include "minivhd_util.h" +#include "minivhd_struct_rw.h" +#include "minivhd.h" + +int mvhd_errno = 0; +static char tmp_open_path[MVHD_MAX_PATH_BYTES] = {0}; +struct MVHDPaths { + char dir_path[MVHD_MAX_PATH_BYTES]; + char file_name[MVHD_MAX_PATH_BYTES]; + char w2ku_path[MVHD_MAX_PATH_BYTES]; + char w2ru_path[MVHD_MAX_PATH_BYTES]; + char joined_path[MVHD_MAX_PATH_BYTES]; + uint16_t tmp_src_path[MVHD_MAX_PATH_CHARS]; +}; + +static void mvhd_read_footer(MVHDMeta* vhdm); +static void mvhd_read_sparse_header(MVHDMeta* vhdm); +static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm); +static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm); +static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err); +static void mvhd_calc_sparse_values(MVHDMeta* vhdm); +static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err); + +/** + * \brief Populate data stuctures with content from a VHD footer + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_read_footer(MVHDMeta* vhdm) { + uint8_t buffer[MVHD_FOOTER_SIZE]; + mvhd_fseeko64(vhdm->f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(buffer, sizeof buffer, 1, vhdm->f); + mvhd_buffer_to_footer(&vhdm->footer, buffer); +} + +/** + * \brief Populate data stuctures with content from a VHD sparse header + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_read_sparse_header(MVHDMeta* vhdm) { + uint8_t buffer[MVHD_SPARSE_SIZE]; + mvhd_fseeko64(vhdm->f, vhdm->footer.data_offset, SEEK_SET); + fread(buffer, sizeof buffer, 1, vhdm->f); + mvhd_buffer_to_header(&vhdm->sparse, buffer); +} + +/** + * \brief Validate VHD footer checksum + * + * This works by generating a checksum from the footer, and comparing it against the stored checksum. + * + * \param [in] vhdm MiniVHD data structure + */ +static bool mvhd_footer_checksum_valid(MVHDMeta* vhdm) { + return vhdm->footer.checksum == mvhd_gen_footer_checksum(&vhdm->footer); +} + +/** + * \brief Validate VHD sparse header checksum + * + * This works by generating a checksum from the sparse header, and comparing it against the stored checksum. + * + * \param [in] vhdm MiniVHD data structure + */ +static bool mvhd_sparse_checksum_valid(MVHDMeta* vhdm) { + return vhdm->sparse.checksum == mvhd_gen_sparse_checksum(&vhdm->sparse); +} + +/** + * \brief Read BAT into MiniVHD data structure + * + * The Block Allocation Table (BAT) is the structure in a sparse and differencing VHD which stores + * the 4-byte sector offsets for each data block. This function allocates enough memory to contain + * the entire BAT, and then reads the contents of the BAT into the buffer. + * + * \param [in] vhdm MiniVHD data structure + * \param [out] err this is populated with MVHD_ERR_MEM if the calloc fails + * + * \retval -1 if an error occurrs. Check value of err in this case + * \retval 0 if the function call succeeds + */ +static int mvhd_read_bat(MVHDMeta *vhdm, MVHDError* err) { + vhdm->block_offset = calloc(vhdm->sparse.max_bat_ent, sizeof *vhdm->block_offset); + if (vhdm->block_offset == NULL) { + *err = MVHD_ERR_MEM; + return -1; + } + mvhd_fseeko64(vhdm->f, vhdm->sparse.bat_offset, SEEK_SET); + uint32_t i; + for (i = 0; i < vhdm->sparse.max_bat_ent; i++) { + fread(&vhdm->block_offset[i], sizeof *vhdm->block_offset, 1, vhdm->f); + vhdm->block_offset[i] = mvhd_from_be32(vhdm->block_offset[i]); + } + return 0; +} + +/** + * \brief Perform a one-time calculation of some sparse VHD values + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_calc_sparse_values(MVHDMeta* vhdm) { + vhdm->sect_per_block = vhdm->sparse.block_sz / MVHD_SECTOR_SIZE; + int bm_bytes = vhdm->sect_per_block / 8; + vhdm->bitmap.sector_count = bm_bytes / MVHD_SECTOR_SIZE; + if (bm_bytes % MVHD_SECTOR_SIZE > 0) { + vhdm->bitmap.sector_count++; + } +} + +/** + * \brief Allocate memory for a sector bitmap. + * + * Each data block is preceded by a sector bitmap. Each bit indicates whether the corresponding sector + * is considered 'clean' or 'dirty' (for sparse VHD images), or whether to read from the parent or current + * image (for differencing images). + * + * \param [in] vhdm MiniVHD data structure + * \param [out] err this is populated with MVHD_ERR_MEM if the calloc fails + * + * \retval -1 if an error occurrs. Check value of err in this case + * \retval 0 if the function call succeeds + */ +static int mvhd_init_sector_bitmap(MVHDMeta* vhdm, MVHDError* err) { + vhdm->bitmap.curr_bitmap = calloc(vhdm->bitmap.sector_count, MVHD_SECTOR_SIZE); + if (vhdm->bitmap.curr_bitmap == NULL) { + *err = MVHD_ERR_MEM; + return -1; + } + vhdm->bitmap.curr_block = -1; + return 0; +} + +/** + * \brief Check if the path for a given platform code exists + * + * From the available paths, both relative and absolute, construct a full path + * and attempt to open a file at that path. + * + * Note, this function makes no attempt to verify that the path is the correct + * VHD image, or even a VHD image at all. + * + * \param [in] paths a struct containing all available paths to work with + * \param [in] the platform code to try and obtain a path for. Setting this to zero + * will try using the directory of the child image + * + * \retval true if a file is found + * \retval false if a file is not found + */ +static bool mvhd_parent_path_exists(struct MVHDPaths* paths, uint32_t plat_code) { + memset(paths->joined_path, 0, sizeof paths->joined_path); + FILE* f; + int cwk_ret, ferr; + enum cwk_path_style style = cwk_path_guess_style((const char*)paths->dir_path); + cwk_path_set_style(style); + cwk_ret = 1; + if (plat_code == MVHD_DIF_LOC_W2RU && *paths->w2ru_path) { + cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->w2ru_path, paths->joined_path, sizeof paths->joined_path); + } else if (plat_code == MVHD_DIF_LOC_W2KU && *paths->w2ku_path) { + memcpy(paths->joined_path, paths->w2ku_path, (sizeof paths->joined_path) - 1); + cwk_ret = 0; + } else if (plat_code == 0) { + cwk_ret = cwk_path_join((const char*)paths->dir_path, (const char*)paths->file_name, paths->joined_path, sizeof paths->joined_path); + } + if (cwk_ret > MVHD_MAX_PATH_BYTES) { + return false; + } + f = mvhd_fopen((const char*)paths->joined_path, "rb", &ferr); + if (f != NULL) { + /* We found a file at the requested path! */ + memcpy(tmp_open_path, paths->joined_path, (sizeof paths->joined_path) - 1); + tmp_open_path[sizeof tmp_open_path - 1] = '\0'; + fclose(f); + return true; + } else { + return false; + } +} + +/** + * \brief attempt to obtain a file path to a file that may be a valid VHD image + * + * Differential VHD images store both a UTF-16BE file name (or path), and up to + * eight "parent locator" entries. Using this information, this function tries to + * find a parent image. + * + * This function does not verify if the path returned is a valid parent image. + * + * \param [in] vhdm current MiniVHD data structure + * \param [out] err any errors that may occurr. Check this if NULL is returned + * + * \return a pointer to the global string `tmp_open_path`, or NULL if a path could + * not be found, or some error occurred + */ +static char* mvhd_get_diff_parent_path(MVHDMeta* vhdm, int* err) { + int utf_outlen, utf_inlen, utf_ret; + char* par_fp = NULL; + /* We can't resolve relative paths if we don't have an absolute + path to work with */ + if (!cwk_path_is_absolute((const char*)vhdm->filename)) { + *err = MVHD_ERR_PATH_REL; + goto end; + } + struct MVHDPaths* paths = calloc(1, sizeof *paths); + if (paths == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + size_t dirlen; + cwk_path_get_dirname((const char*)vhdm->filename, &dirlen); + if (dirlen >= sizeof paths->dir_path) { + *err = MVHD_ERR_PATH_LEN; + goto paths_cleanup; + } + memcpy(paths->dir_path, vhdm->filename, dirlen); + /* Get the filename field from the sparse header. */ + utf_outlen = (int)sizeof paths->file_name; + utf_inlen = (int)sizeof vhdm->sparse.par_utf16_name; + utf_ret = UTF16BEToUTF8((unsigned char*)paths->file_name, &utf_outlen, (const unsigned char*)vhdm->sparse.par_utf16_name, &utf_inlen); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, err); + goto paths_cleanup; + } + /* Now read the parent locator entries, both relative and absolute, if they exist */ + unsigned char* loc_path; + int i; + for (i = 0; i < 8; i++) { + utf_outlen = MVHD_MAX_PATH_BYTES - 1; + if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2RU) { + loc_path = (unsigned char*)paths->w2ru_path; + } else if (vhdm->sparse.par_loc_entry[i].plat_code == MVHD_DIF_LOC_W2KU) { + loc_path = (unsigned char*)paths->w2ku_path; + } else { + continue; + } + utf_inlen = vhdm->sparse.par_loc_entry[i].plat_data_len; + if (utf_inlen > MVHD_MAX_PATH_BYTES) { + *err = MVHD_ERR_PATH_LEN; + goto paths_cleanup; + } + mvhd_fseeko64(vhdm->f, vhdm->sparse.par_loc_entry[i].plat_data_offset, SEEK_SET); + fread(paths->tmp_src_path, sizeof (uint8_t), utf_inlen, vhdm->f); + /* Note, the W2*u parent locators are UTF-16LE, unlike the filename field previously obtained, + which is UTF-16BE */ + utf_ret = UTF16LEToUTF8(loc_path, &utf_outlen, (const unsigned char*)paths->tmp_src_path, &utf_inlen); + if (utf_ret < 0) { + mvhd_set_encoding_err(utf_ret, err); + goto paths_cleanup; + } + } + /* We have paths in UTF-8. We should have enough info to try and find the parent VHD */ + /* Does the relative path exist? */ + if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2RU)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* What about trying the child directory? */ + if (mvhd_parent_path_exists(paths, 0)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* Well, all else fails, try the stored absolute path, if it exists */ + if (mvhd_parent_path_exists(paths, MVHD_DIF_LOC_W2KU)) { + par_fp = tmp_open_path; + goto paths_cleanup; + } + /* If we reach this point, we could not find a path with a valid file */ + par_fp = NULL; + *err = MVHD_ERR_PAR_NOT_FOUND; + +paths_cleanup: + free(paths); + paths = NULL; +end: + return par_fp; +} + +/** + * \brief Attach the read/write function pointers to read/write functions + * + * Depending on the VHD type, different sector reading and writing functions are used. + * The functions are called via function pointers stored in the vhdm struct. + * + * \param [in] vhdm MiniVHD data structure + */ +static void mvhd_assign_io_funcs(MVHDMeta* vhdm) { + switch (vhdm->footer.disk_type) { + case MVHD_TYPE_FIXED: + vhdm->read_sectors = mvhd_fixed_read; + vhdm->write_sectors = mvhd_fixed_write; + break; + case MVHD_TYPE_DYNAMIC: + vhdm->read_sectors = mvhd_sparse_read; + vhdm->write_sectors = mvhd_sparse_diff_write; + break; + case MVHD_TYPE_DIFF: + vhdm->read_sectors = mvhd_diff_read; + vhdm->write_sectors = mvhd_sparse_diff_write; + break; + } + if (vhdm->readonly) { + vhdm->write_sectors = mvhd_noop_write; + } +} + +bool mvhd_file_is_vhd(FILE* f) { + if (f) { + uint8_t con_str[8]; + mvhd_fseeko64(f, -MVHD_FOOTER_SIZE, SEEK_END); + fread(con_str, sizeof con_str, 1, f); + return mvhd_is_conectix_str(con_str); + } else { + return false; + } +} + +MVHDGeom mvhd_calculate_geometry(uint64_t size) { + MVHDGeom chs; + uint32_t ts = (uint32_t)(size / MVHD_SECTOR_SIZE); + uint32_t spt, heads, cyl, cth; + if (ts > 65535 * 16 * 255) { + ts = 65535 * 16 * 255; + } + if (ts >= 65535 * 16 * 63) { + spt = 255; + heads = 16; + cth = ts / spt; + } else { + spt = 17; + cth = ts / spt; + heads = (cth + 1023) / 1024; + if (heads < 4) { + heads = 4; + } + if (cth >= (heads * 1024) || heads > 16) { + spt = 31; + heads = 16; + cth = ts / spt; + } + if (cth >= (heads * 1024)) { + spt = 63; + heads = 16; + cth = ts / spt; + } + } + cyl = cth / heads; + chs.heads = heads; + chs.spt = spt; + chs.cyl = cyl; + return chs; +} + +MVHDMeta* mvhd_open(const char* path, bool readonly, int* err) { + MVHDError open_err; + MVHDMeta *vhdm = calloc(sizeof *vhdm, 1); + if (vhdm == NULL) { + *err = MVHD_ERR_MEM; + goto end; + } + if (strlen(path) >= sizeof vhdm->filename) { + *err = MVHD_ERR_PATH_LEN; + goto cleanup_vhdm; + } + //This is safe, as we've just checked for potential overflow above + strcpy(vhdm->filename, path); + vhdm->f = readonly ? mvhd_fopen((const char*)vhdm->filename, "rb", err) : mvhd_fopen((const char*)vhdm->filename, "rb+", err); + if (vhdm->f == NULL) { + /* note, mvhd_fopen sets err for us */ + goto cleanup_vhdm; + } + vhdm->readonly = readonly; + if (!mvhd_file_is_vhd(vhdm->f)) { + *err = MVHD_ERR_NOT_VHD; + goto cleanup_file; + } + mvhd_read_footer(vhdm); + if (!mvhd_footer_checksum_valid(vhdm)) { + *err = MVHD_ERR_FOOTER_CHECKSUM; + goto cleanup_file; + } + if (vhdm->footer.disk_type == MVHD_TYPE_DIFF || vhdm->footer.disk_type == MVHD_TYPE_DYNAMIC) { + mvhd_read_sparse_header(vhdm); + if (!mvhd_sparse_checksum_valid(vhdm)) { + *err = MVHD_ERR_SPARSE_CHECKSUM; + goto cleanup_file; + } + if (mvhd_read_bat(vhdm, &open_err) == -1) { + *err = open_err; + goto cleanup_file; + } + mvhd_calc_sparse_values(vhdm); + if (mvhd_init_sector_bitmap(vhdm, &open_err) == -1) { + *err = open_err; + goto cleanup_bat; + } + + } else if (vhdm->footer.disk_type != MVHD_TYPE_FIXED) { + *err = MVHD_ERR_TYPE; + goto cleanup_bitmap; + } + mvhd_assign_io_funcs(vhdm); + vhdm->format_buffer.zero_data = calloc(64, MVHD_SECTOR_SIZE); + if (vhdm->format_buffer.zero_data == NULL) { + *err = MVHD_ERR_MEM; + goto cleanup_bitmap; + } + vhdm->format_buffer.sector_count = 64; + if (vhdm->footer.disk_type == MVHD_TYPE_DIFF) { + char* par_path = mvhd_get_diff_parent_path(vhdm, err); + if (par_path == NULL) { + goto cleanup_format_buff; + } + uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + goto cleanup_format_buff; + } + if (vhdm->sparse.par_timestamp != par_mod_ts) { + /* The last-modified timestamp is to fragile to make this a fatal error. + Instead, we inform the caller of the potential problem. */ + *err = MVHD_ERR_TIMESTAMP; + } + vhdm->parent = mvhd_open(par_path, true, err); + if (vhdm->parent == NULL) { + goto cleanup_format_buff; + } + if (memcmp(vhdm->sparse.par_uuid, vhdm->parent->footer.uuid, sizeof vhdm->sparse.par_uuid) != 0) { + *err = MVHD_ERR_INVALID_PAR_UUID; + goto cleanup_format_buff; + } + } + /* If we've reached this point, we are good to go, so skip the cleanup steps */ + goto end; +cleanup_format_buff: + free(vhdm->format_buffer.zero_data); + vhdm->format_buffer.zero_data = NULL; +cleanup_bitmap: + free(vhdm->bitmap.curr_bitmap); + vhdm->bitmap.curr_bitmap = NULL; +cleanup_bat: + free(vhdm->block_offset); + vhdm->block_offset = NULL; +cleanup_file: + fclose(vhdm->f); + vhdm->f = NULL; +cleanup_vhdm: + free(vhdm); + vhdm = NULL; +end: + return vhdm; +} + +void mvhd_close(MVHDMeta* vhdm) { + if (vhdm != NULL) { + if (vhdm->parent != NULL) { + mvhd_close(vhdm->parent); + } + fclose(vhdm->f); + if (vhdm->block_offset != NULL) { + free(vhdm->block_offset); + vhdm->block_offset = NULL; + } + if (vhdm->bitmap.curr_bitmap != NULL) { + free(vhdm->bitmap.curr_bitmap); + vhdm->bitmap.curr_bitmap = NULL; + } + if (vhdm->format_buffer.zero_data != NULL) { + free(vhdm->format_buffer.zero_data); + vhdm->format_buffer.zero_data = NULL; + } + free(vhdm); + vhdm = NULL; + } +} + +int mvhd_diff_update_par_timestamp(MVHDMeta* vhdm, int* err) { + uint8_t sparse_buff[1024]; + if (vhdm == NULL || err == NULL) { + *err = MVHD_ERR_INVALID_PARAMS; + return -1; + } + if (vhdm->footer.disk_type != MVHD_TYPE_DIFF) { + *err = MVHD_ERR_TYPE; + return -1; + } + char* par_path = mvhd_get_diff_parent_path(vhdm, err); + if (par_path == NULL) { + return -1; + } + uint32_t par_mod_ts = mvhd_file_mod_timestamp(par_path, err); + if (*err != 0) { + return -1; + } + /* Update the timestamp and sparse header checksum */ + vhdm->sparse.par_timestamp = par_mod_ts; + vhdm->sparse.checksum = mvhd_gen_sparse_checksum(&vhdm->sparse); + /* Generate and write the updated sparse header */ + mvhd_header_to_buffer(&vhdm->sparse, sparse_buff); + mvhd_fseeko64(vhdm->f, (int64_t)vhdm->footer.data_offset, SEEK_SET); + fwrite(sparse_buff, sizeof sparse_buff, 1, vhdm->f); + return 0; +} + +int mvhd_read_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* out_buff) { + return vhdm->read_sectors(vhdm, offset, num_sectors, out_buff); +} + +int mvhd_write_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors, void* in_buff) { + return vhdm->write_sectors(vhdm, offset, num_sectors, in_buff); +} + +int mvhd_format_sectors(MVHDMeta* vhdm, uint32_t offset, int num_sectors) { + int num_full = num_sectors / vhdm->format_buffer.sector_count; + int remain = num_sectors % vhdm->format_buffer.sector_count; + int i; + for (i = 0; i < num_full; i++) { + vhdm->write_sectors(vhdm, offset, vhdm->format_buffer.sector_count, vhdm->format_buffer.zero_data); + offset += vhdm->format_buffer.sector_count; + } + vhdm->write_sectors(vhdm, offset, remain, vhdm->format_buffer.zero_data); + return 0; +} diff --git a/src/minivhd/minivhd_struct_rw.c b/src/minivhd/minivhd_struct_rw.c new file mode 100644 index 0000000..77f26a4 --- /dev/null +++ b/src/minivhd/minivhd_struct_rw.c @@ -0,0 +1,169 @@ +/** + * \file + * \brief Header and footer serialize/deserialize functions + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include "minivhd_util.h" +#include "minivhd_internal.h" + +/* Read data from footer into the struct members, swapping endian where necessary + Note: order matters here! We must read each field in the order the struct is in. + Doing this may be less elegant than performing a memcpy to a packed struct, but + it avoids potential data alignment issues, and the endian swapping allows us to + use the fields directly. */ + +static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer); +static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer); + +/** + * \brief Get the next field from a buffer and store it in a struct member, converting endian if necessary + * + * \param [out] struct_memb struct member to save the field to + * \param [in] memb_size the size of struct_memb, in bytes + * \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32) + * \param [in] buffer the buffer from which fields are read from. Will be advanced at the end of the function call + */ +static void mvhd_next_buffer_to_struct(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) { + memcpy(struct_memb, *buffer, memb_size); + if (req_endian) { + switch (memb_size) { + case 2: + *(uint16_t*)(struct_memb) = mvhd_from_be16(*(uint16_t*)(struct_memb)); + break; + case 4: + *(uint32_t*)(struct_memb) = mvhd_from_be32(*(uint32_t*)(struct_memb)); + break; + case 8: + *(uint64_t*)(struct_memb) = mvhd_from_be64(*(uint64_t*)(struct_memb)); + break; + } + } + *buffer += memb_size; +} + +/** + * \brief Save a struct member into a buffer, converting endian if necessary + * + * \param [in] struct_memb struct member read from + * \param [in] memb_size the size of struct_memb, in bytes + * \param [in] req_endian is the field a value that requires endian conversion (eg: uint16, uint32) + * \param [out] buffer the buffer from which struct member is saved to. Will be advanced at the end of the function call + */ +static void mvhd_next_struct_to_buffer(void* struct_memb, size_t memb_size, bool req_endian, uint8_t** buffer) { + uint8_t *buf_ptr = *buffer; + memcpy(buf_ptr, struct_memb, memb_size); + if (req_endian) { + switch (memb_size) { + case 2: + *((uint16_t*)buf_ptr) = mvhd_to_be16(*(uint16_t*)(struct_memb)); + break; + case 4: + *((uint32_t*)buf_ptr) = mvhd_to_be32(*(uint32_t*)(struct_memb)); + break; + case 8: + *((uint64_t*)buf_ptr) = mvhd_to_be64(*(uint64_t*)(struct_memb)); + break; + } + } + buf_ptr += memb_size; + *buffer = buf_ptr; +} + +void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_buffer_to_struct(&footer->cookie, sizeof footer->cookie, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->features, sizeof footer->features, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->checksum, sizeof footer->checksum, true, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->uuid, sizeof footer->uuid, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr); + mvhd_next_buffer_to_struct(&footer->reserved, sizeof footer->reserved, false, &buff_ptr); +} + +void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_struct_to_buffer(&footer->cookie, sizeof footer->cookie, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->features, sizeof footer->features, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->fi_fmt_vers, sizeof footer->fi_fmt_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->data_offset, sizeof footer->data_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->timestamp, sizeof footer->timestamp, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_app, sizeof footer->cr_app, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_vers, sizeof footer->cr_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->cr_host_os, sizeof footer->cr_host_os, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->orig_sz, sizeof footer->orig_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->curr_sz, sizeof footer->curr_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.cyl, sizeof footer->geom.cyl, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.heads, sizeof footer->geom.heads, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->geom.spt, sizeof footer->geom.spt, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->disk_type, sizeof footer->disk_type, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->checksum, sizeof footer->checksum, true, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->uuid, sizeof footer->uuid, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->saved_st, sizeof footer->saved_st, false, &buff_ptr); + mvhd_next_struct_to_buffer(&footer->reserved, sizeof footer->reserved, false, &buff_ptr); +} + +void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_buffer_to_struct(&header->cookie, sizeof header->cookie, false, &buff_ptr); + mvhd_next_buffer_to_struct(&header->data_offset, sizeof header->data_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->head_vers, sizeof header->head_vers, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->block_sz, sizeof header->block_sz, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->checksum, sizeof header->checksum, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr); + int i; + for (i = 0; i < 8; i++) { + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr); + mvhd_next_buffer_to_struct(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr); + } + mvhd_next_buffer_to_struct(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr); +} + +void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer) { + uint8_t* buff_ptr = buffer; + mvhd_next_struct_to_buffer(&header->cookie, sizeof header->cookie, false, &buff_ptr); + mvhd_next_struct_to_buffer(&header->data_offset, sizeof header->data_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->bat_offset, sizeof header->bat_offset, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->head_vers, sizeof header->head_vers, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->max_bat_ent, sizeof header->max_bat_ent, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->block_sz, sizeof header->block_sz, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->checksum, sizeof header->checksum, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_uuid, sizeof header->par_uuid, false, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_timestamp, sizeof header->par_timestamp, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->reserved_1, sizeof header->reserved_1, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_utf16_name, sizeof header->par_utf16_name, false, &buff_ptr); + int i; + for (i = 0; i < 8; i++) { + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_code, sizeof header->par_loc_entry[i].plat_code, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_space, sizeof header->par_loc_entry[i].plat_data_space, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_len, sizeof header->par_loc_entry[i].plat_data_len, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].reserved, sizeof header->par_loc_entry[i].reserved, true, &buff_ptr); + mvhd_next_struct_to_buffer(&header->par_loc_entry[i].plat_data_offset, sizeof header->par_loc_entry[i].plat_data_offset, true, &buff_ptr); + } + mvhd_next_struct_to_buffer(&header->reserved_2, sizeof header->reserved_2, false, &buff_ptr); +} diff --git a/src/minivhd/minivhd_struct_rw.h b/src/minivhd/minivhd_struct_rw.h new file mode 100644 index 0000000..a587177 --- /dev/null +++ b/src/minivhd/minivhd_struct_rw.h @@ -0,0 +1,38 @@ +#ifndef MINIVHD_STRUCT_RW_H +#define MINIVHD_STRUCT_RW_H + +#include "minivhd_internal.h" + +/** + * \brief Save the contents of a VHD footer from a buffer to a struct + * + * \param [out] footer save contents of buffer into footer + * \param [in] buffer VHD footer in raw bytes + */ +void mvhd_buffer_to_footer(MVHDFooter* footer, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD sparse header from a buffer to a struct + * + * \param [out] header save contents of buffer into header + * \param [in] buffer VHD header in raw bytes + */ +void mvhd_buffer_to_header(MVHDSparseHeader* header, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD footer struct to a buffer + * + * \param [in] footer save contents of struct into buffer + * \param [out] buffer VHD footer in raw bytes + */ +void mvhd_footer_to_buffer(MVHDFooter* footer, uint8_t* buffer); + +/** + * \brief Save the contents of a VHD sparse header struct to a buffer + * + * \param [in] header save contents of struct into buffer + * \param [out] buffer VHD sparse header in raw bytes + */ +void mvhd_header_to_buffer(MVHDSparseHeader* header, uint8_t* buffer); + +#endif diff --git a/src/minivhd/minivhd_util.c b/src/minivhd/minivhd_util.c new file mode 100644 index 0000000..b04e022 --- /dev/null +++ b/src/minivhd/minivhd_util.c @@ -0,0 +1,339 @@ +/** + * \file + * \brief Utility functions + */ +#ifndef _FILE_OFFSET_BITS +#define _FILE_OFFSET_BITS 64 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include "libxml2_encoding.h" +#include "minivhd_internal.h" +#include "minivhd_util.h" +#include "minivhd.h" + +const char MVHD_CONECTIX_COOKIE[] = "conectix"; +const char MVHD_CREATOR[] = "pcem"; +const char MVHD_CREATOR_HOST_OS[] = "Wi2k"; +const char MVHD_CXSPARSE_COOKIE[] = "cxsparse"; + +uint16_t mvhd_from_be16(uint16_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint16_t ret = 0; + ret |= (uint16_t)tmp[0] << 8; + ret |= (uint16_t)tmp[1] << 0; + return ret; +} +uint32_t mvhd_from_be32(uint32_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint32_t ret = 0; + ret = (uint32_t)tmp[0] << 24; + ret |= (uint32_t)tmp[1] << 16; + ret |= (uint32_t)tmp[2] << 8; + ret |= (uint32_t)tmp[3] << 0; + return ret; +} +uint64_t mvhd_from_be64(uint64_t val) { + uint8_t *tmp = (uint8_t*)&val; + uint64_t ret = 0; + ret = (uint64_t)tmp[0] << 56; + ret |= (uint64_t)tmp[1] << 48; + ret |= (uint64_t)tmp[2] << 40; + ret |= (uint64_t)tmp[3] << 32; + ret |= (uint64_t)tmp[4] << 24; + ret |= (uint64_t)tmp[5] << 16; + ret |= (uint64_t)tmp[6] << 8; + ret |= (uint64_t)tmp[7] << 0; + return ret; +} +uint16_t mvhd_to_be16(uint16_t val) { + uint16_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (val & 0xff00) >> 8; + tmp[1] = (val & 0x00ff) >> 0; + return ret; +} +uint32_t mvhd_to_be32(uint32_t val) { + uint32_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (val & 0xff000000) >> 24; + tmp[1] = (val & 0x00ff0000) >> 16; + tmp[2] = (val & 0x0000ff00) >> 8; + tmp[3] = (val & 0x000000ff) >> 0; + return ret; +} +uint64_t mvhd_to_be64(uint64_t val) { + uint64_t ret = 0; + uint8_t *tmp = (uint8_t*)&ret; + tmp[0] = (uint8_t)((val & 0xff00000000000000) >> 56); + tmp[1] = (uint8_t)((val & 0x00ff000000000000) >> 48); + tmp[2] = (uint8_t)((val & 0x0000ff0000000000) >> 40); + tmp[3] = (uint8_t)((val & 0x000000ff00000000) >> 32); + tmp[4] = (uint8_t)((val & 0x00000000ff000000) >> 24); + tmp[5] = (uint8_t)((val & 0x0000000000ff0000) >> 16); + tmp[6] = (uint8_t)((val & 0x000000000000ff00) >> 8); + tmp[7] = (uint8_t)((val & 0x00000000000000ff) >> 0); + return ret; +} + +bool mvhd_is_conectix_str(const void* buffer) { + if (strncmp(buffer, MVHD_CONECTIX_COOKIE, strlen(MVHD_CONECTIX_COOKIE)) == 0) { + return true; + } else { + return false; + } +} + +void mvhd_generate_uuid(uint8_t* uuid) +{ + /* We aren't doing crypto here, so using system time as seed should be good enough */ + srand((unsigned int)time(0)); + int n; + for (n = 0; n < 16; n++) { + uuid[n] = rand(); + } + uuid[6] &= 0x0F; + uuid[6] |= 0x40; /* Type 4 */ + uuid[8] &= 0x3F; + uuid[8] |= 0x80; /* Variant 1 */ +} + +uint32_t vhd_calc_timestamp(void) +{ + time_t start_time; + time_t curr_time; + double vhd_time; + start_time = MVHD_START_TS; /* 1 Jan 2000 00:00 */ + curr_time = time(NULL); + vhd_time = difftime(curr_time, start_time); + return (uint32_t)vhd_time; +} + +uint32_t mvhd_epoch_to_vhd_ts(time_t ts) { + time_t start_time = MVHD_START_TS; + if (ts < start_time) { + return start_time; + } + double vhd_time = difftime(ts, start_time); + return (uint32_t)vhd_time; +} + +time_t vhd_get_created_time(MVHDMeta *vhdm) +{ + time_t vhd_time = (time_t)vhdm->footer.timestamp; + time_t vhd_time_unix = MVHD_START_TS + vhd_time; + return vhd_time_unix; +} + +FILE* mvhd_fopen(const char* path, const char* mode, int* err) { + FILE* f = NULL; +#ifdef _WIN32 + size_t path_len = strlen(path); + size_t mode_len = strlen(mode); + mvhd_utf16 new_path[260] = {0}; + int new_path_len = (sizeof new_path) - 2; + mvhd_utf16 mode_str[5] = {0}; + int new_mode_len = (sizeof mode_str) - 2; + int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len); + int mode_res = UTF8ToUTF16LE((unsigned char*)mode_str, &new_mode_len, (const unsigned char*)mode, (int*)&mode_len); + if (path_res > 0 && mode_res > 0) { + f = _wfopen(new_path, mode_str); + if (f == NULL) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + } + } else { + if (path_res == -1 || mode_res == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (path_res == -2 || mode_res == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } + } +#else + f = fopen(path, mode); + if (f == NULL) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + } +#endif + return f; +} + +void mvhd_set_encoding_err(int encoding_retval, int* err) { + if (encoding_retval == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (encoding_retval == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } +} + +uint64_t mvhd_calc_size_bytes(MVHDGeom *geom) { + uint64_t img_size = (uint64_t)geom->cyl * (uint64_t)geom->heads * (uint64_t)geom->spt * (uint64_t)MVHD_SECTOR_SIZE; + return img_size; +} + +uint32_t mvhd_calc_size_sectors(MVHDGeom *geom) { + uint32_t sector_size = (uint32_t)geom->cyl * (uint32_t)geom->heads * (uint32_t)geom->spt; + return sector_size; +} + +MVHDGeom mvhd_get_geometry(MVHDMeta* vhdm) { + MVHDGeom geometry = { .cyl = vhdm->footer.geom.cyl, .heads = vhdm->footer.geom.heads, .spt = vhdm->footer.geom.spt }; + return geometry; +} + +uint64_t mvhd_get_current_size(MVHDMeta* vhdm) { + return vhdm->footer.curr_sz; +} + +uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer) { + uint32_t new_chk = 0; + uint32_t orig_chk = footer->checksum; + footer->checksum = 0; + uint8_t* footer_bytes = (uint8_t*)footer; + size_t i; + for (i = 0; i < sizeof *footer; i++) { + new_chk += footer_bytes[i]; + } + footer->checksum = orig_chk; + return ~new_chk; +} + +uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header) { + uint32_t new_chk = 0; + uint32_t orig_chk = header->checksum; + header->checksum = 0; + uint8_t* sparse_bytes = (uint8_t*)header; + size_t i; + for (i = 0; i < sizeof *header; i++) { + new_chk += sparse_bytes[i]; + } + header->checksum = orig_chk; + return ~new_chk; +} + +const char* mvhd_strerr(MVHDError err) { + switch (err) { + case MVHD_ERR_MEM: + return "memory allocation error"; + case MVHD_ERR_FILE: + return "file error"; + case MVHD_ERR_NOT_VHD: + return "file is not a VHD image"; + case MVHD_ERR_TYPE: + return "unsupported VHD image type"; + case MVHD_ERR_FOOTER_CHECKSUM: + return "invalid VHD footer checksum"; + case MVHD_ERR_SPARSE_CHECKSUM: + return "invalid VHD sparse header checksum"; + case MVHD_ERR_UTF_TRANSCODING_FAILED: + return "error converting path encoding"; + case MVHD_ERR_UTF_SIZE: + return "buffer size mismatch when converting path encoding"; + case MVHD_ERR_PATH_REL: + return "relative path detected where absolute path expected"; + case MVHD_ERR_PATH_LEN: + return "path length exceeds MVHD_MAX_PATH"; + case MVHD_ERR_PAR_NOT_FOUND: + return "parent VHD image not found"; + case MVHD_ERR_INVALID_PAR_UUID: + return "UUID mismatch between child and parent VHD"; + case MVHD_ERR_INVALID_GEOM: + return "invalid geometry detected"; + case MVHD_ERR_INVALID_SIZE: + return "invalid size"; + case MVHD_ERR_INVALID_BLOCK_SIZE: + return "invalid block size"; + case MVHD_ERR_INVALID_PARAMS: + return "invalid parameters passed to function"; + case MVHD_ERR_CONV_SIZE: + return "error converting image. Size mismatch detechted"; + default: + return "unknown error"; + } +} + +int64_t mvhd_ftello64(FILE* stream) +{ +#ifdef _MSC_VER + return _ftelli64(stream); +#elif defined(__MINGW32__) + return ftello64(stream); +#else /* This should work with linux (with _FILE_OFFSET_BITS), and hopefully OS X and BSD */ + return ftello(stream); +#endif +} + +int mvhd_fseeko64(FILE* stream, int64_t offset, int origin) +{ +#ifdef _MSC_VER + return _fseeki64(stream, offset, origin); +#elif defined(__MINGW32__) + return fseeko64(stream, offset, origin); +#else /* This should work with linux (with _FILE_OFFSET_BITS), and hopefully OS X and BSD */ + return fseeko(stream, offset, origin); +#endif +} + +uint32_t mvhd_crc32_for_byte(uint32_t r) { + int j; + for (j = 0; j < 8; ++j) + r = (r & 1 ? 0 : (uint32_t)0xEDB88320L) ^ r >> 1; + return r ^ (uint32_t)0xFF000000L; +} + +uint32_t mvhd_crc32(const void* data, size_t n_bytes) { + static uint32_t table[0x100]; + size_t i; + if (!*table) + for (i = 0; i < 0x100; ++i) + table[i] = mvhd_crc32_for_byte(i); + + uint32_t crc = 0; + for (i = 0; i < n_bytes; ++i) + crc = table[(uint8_t)crc ^ ((uint8_t*)data)[i]] ^ crc >> 8; + + return crc; +} + +uint32_t mvhd_file_mod_timestamp(const char* path, int *err) { + *err = 0; +#ifdef _WIN32 + struct _stat file_stat; + size_t path_len = strlen(path); + mvhd_utf16 new_path[260] = {0}; + int new_path_len = (sizeof new_path) - 2; + int path_res = UTF8ToUTF16LE((unsigned char*)new_path, &new_path_len, (const unsigned char*)path, (int*)&path_len); + if (path_res > 0) { + int stat_res = _wstat(new_path, &file_stat); + if (stat_res != 0) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + return 0; + } + return mvhd_epoch_to_vhd_ts(file_stat.st_mtime); + } else { + if (path_res == -1) { + *err = MVHD_ERR_UTF_SIZE; + } else if (path_res == -2) { + *err = MVHD_ERR_UTF_TRANSCODING_FAILED; + } + return 0; + } +#else + struct stat file_stat; + int stat_res = stat(path, &file_stat); + if (stat_res != 0) { + mvhd_errno = errno; + *err = MVHD_ERR_FILE; + return 0; + } + return mvhd_epoch_to_vhd_ts(file_stat.st_mtime); +#endif +} diff --git a/src/minivhd/minivhd_util.h b/src/minivhd/minivhd_util.h new file mode 100644 index 0000000..8a18b55 --- /dev/null +++ b/src/minivhd/minivhd_util.h @@ -0,0 +1,133 @@ +#ifndef MINIVHD_UTIL_H +#define MINIVHD_UTIL_H + +#include +#include +#include +#include "minivhd_internal.h" +#include "minivhd.h" +#define MVHD_START_TS 946684800 + +/** + * Functions to deal with endian issues + */ +uint16_t mvhd_from_be16(uint16_t val); +uint32_t mvhd_from_be32(uint32_t val); +uint64_t mvhd_from_be64(uint64_t val); +uint16_t mvhd_to_be16(uint16_t val); +uint32_t mvhd_to_be32(uint32_t val); +uint64_t mvhd_to_be64(uint64_t val); + +/** + * \brief Check if provided buffer begins with the string "conectix" + * + * \param [in] buffer The buffer to compare. Must be at least 8 bytes in length + * + * \return true if the buffer begins with "conectix" + * \return false if the buffer does not begin with "conectix" + */ +bool mvhd_is_conectix_str(const void* buffer); + +/** + * \brief Generate a raw 16 byte UUID + * + * \param [out] uuid A 16 byte buffer in which the generated UUID will be stored to + */ +void mvhd_generate_uuid(uint8_t *uuid); + +/** + * \brief Calculate a VHD formatted timestamp from the current time + */ +uint32_t vhd_calc_timestamp(void); + +/** + * \brief Convert an epoch timestamp to a VHD timestamp + * + * \param [in] ts epoch timestamp to convert. + * + * \return The adjusted timestamp, or 0 if the input timestamp is + * earlier that 1 Janurary 2000 + */ +uint32_t mvhd_epoch_to_vhd_ts(time_t ts); + +/** + * \brief Return the created time from a VHD image + * + * \param [in] vhdm Pointer to the MiniVHD metadata structure + * + * \return The created time, as a Unix timestamp + */ +time_t vhd_get_created_time(MVHDMeta *vhdm); + +/** + * \brief Cross platform, unicode filepath opening + * + * This function accounts for the fact that fopen() handles file paths differently compared to other + * operating systems. Windows version of fopen() will not handle multi byte encoded text like UTF-8. + * + * Unicode filepath support on Windows requires using the _wfopen() function, which expects UTF-16LE + * encoded path and modestring. + * + * \param [in] path The filepath to open as a UTF-8 string + * \param [in] mode The mode string to use (eg: "rb+"") + * \param [out] err The error value, if an error occurrs + * + * \return a FILE pointer if successful, NULL otherwise. If NULL, check the value of err + */ +FILE* mvhd_fopen(const char* path, const char* mode, int* err); + +void mvhd_set_encoding_err(int encoding_retval, int* err); + +/** + * \brief Generate VHD footer checksum + * + * \param [in] vhdm MiniVHD data structure + */ +uint32_t mvhd_gen_footer_checksum(MVHDFooter* footer); + +/** + * \brief Generate VHD sparse header checksum + * + * \param [in] vhdm MiniVHD data structure + */ +uint32_t mvhd_gen_sparse_checksum(MVHDSparseHeader* header); + +/** + * \brief Get current position in file stream + * + * This is a portable version of the POSIX ftello64(). * + */ +int64_t mvhd_ftello64(FILE* stream); + +/** + * \brief Reposition the file stream's position + * + * This is a portable version of the POSIX fseeko64(). * + */ +int mvhd_fseeko64(FILE* stream, int64_t offset, int origin); + +/** + * \brief Calculate the CRC32 of a data buffer. + * + * This function can be used for verifying data integrity. + * + * \param [in] data The data buffer + * \param [in] n_bytes The size of the data buffer in bytes + * + * \return The CRC32 of the data buffer + */ +uint32_t mvhd_crc32(const void* data, size_t n_bytes); + +/** + * \brief Calculate the file modification timestamp. + * + * This function is primarily to help protect differencing VHD's + * + * \param [in] path the UTF-8 file path + * \param [out] err The error value, if an error occurrs + * + * \return The file modified timestamp, in VHD compatible timestamp. + * 'err' will be set to non-zero on error + */ +uint32_t mvhd_file_mod_timestamp(const char* path, int *err); +#endif diff --git a/src/model.c b/src/model.c index e9a8460..6b9f71f 100644 --- a/src/model.c +++ b/src/model.c @@ -4,19 +4,33 @@ #include "io.h" #include "mouse.h" +#include "82091aa.h" +#include "acc2036.h" +#include "acc2168.h" +#include "acc3221.h" #include "acer386sx.h" #include "ali1429.h" #include "amstrad.h" +#include "cbm_io.h" +#include "cmd640.h" #include "compaq.h" +#include "cs8230.h" +#include "dells200.h" #include "device.h" +#include "cassette.h" #include "dma.h" +#include "f82c710_upc.h" #include "fdc.h" #include "fdc37c665.h" +#include "fdc37c93x.h" #include "gameport.h" #include "headland.h" #include "i430fx.h" +#include "i430hx.h" #include "i430lx.h" #include "i430vx.h" +#include "i440bx.h" +#include "i440fx.h" #include "ide.h" #include "intel.h" #include "intel_flash.h" @@ -26,14 +40,18 @@ #include "keyboard_olim24.h" #include "keyboard_pcjr.h" #include "keyboard_xt.h" +#include "laserxt.h" #include "lpt.h" #include "mem.h" #include "mouse_ps2.h" +#include "mvp3.h" #include "neat.h" #include "nmi.h" #include "nvr.h" #include "olivetti_m24.h" #include "opti495.h" +#include "pc87306.h" +#include "pc87307.h" #include "pci.h" #include "pic.h" #include "piix.h" @@ -41,102 +59,196 @@ #include "ps1.h" #include "ps2.h" #include "ps2_mca.h" +#include "scamp.h" #include "scat.h" #include "serial.h" +#include "sio.h" #include "sis496.h" +#include "sl82c460.h" #include "sound_ps1.h" #include "sound_pssj.h" #include "sound_sn76489.h" +#include "superxt.h" +#include "sst39sf010.h" #include "tandy_eeprom.h" #include "tandy_rom.h" #include "um8669f.h" -#include "um8881f.h" #include "vid_pcjr.h" #include "vid_tandy.h" +#include "vid_t1000.h" +#include "vl82c480.h" +#include "vt82c586b.h" +#include "w83877tf.h" +#include "w83977tf.h" #include "wd76c10.h" +#include "xi8088.h" +#include "zenith.h" void xt_init(); void pcjr_init(); void tandy1k_init(); void tandy1ksl2_init(); void ams_init(); +void pc5086_init(); void europc_init(); void olim24_init(); void at_init(); void ibm_at_init(); -void at_ide_init(); +void at_cbm_init(); +void dells200_init(); void deskpro386_init(); +void pb_l300sx_init(); void ps1_m2011_init(); void ps1_m2121_init(); +void ps1_m2133_init(void); void ps2_m30_286_init(); void ps2_model_50_init(); void ps2_model_55sx_init(); +void ps2_model_70_init(); void ps2_model_80_init(); void at_neat_init(); +void at_scamp_init(); void at_scat_init(); +void at_scatsx_init(); void at_acer386sx_init(); void at_wd76c10_init(); +void at_cs8230_init(); void at_ali1429_init(); void at_headland_init(); void at_opti495_init(); -void at_um8881f_init(); void at_sis496_init(); +void at_p55va_init(); +void at_p55tvp4_init(); void at_i430vx_init(); void at_batman_init(); void at_endeavor_init(); - +void at_p55t2p4_init(); +void xt_laserxt_init(); +void at_t3100e_init(); +void xt_t1000_init(); +void xt_t1200_init(); +void at_sl82c460_init(); +void at_zappa_init(); +void at_pb410a_init(); +void at_pb520r_init(); +void at_pb570_init(); +void compaq_xt_init(); +void xt_xi8088_init(); +void xt_zenith_init(); +void at_mvp3_init(); +void at_vs440fx_init(); +void at_ga686bx_init(); int model; -int AMSTRAD, AT, PCI, TANDY; +int AMSTRAD, AT, PCI, TANDY, MCA; MODEL models[] = { - {"IBM PC", ROM_IBMPC, "ibmpc", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"IBM XT", ROM_IBMXT, "ibmxt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"IBM PCjr", ROM_IBMPCJR, "ibmpcjr", { {"", cpus_pcjr}, {"", NULL}, {"", NULL}}, 1, 0, 128, 640, 64, pcjr_init, &pcjr_device}, - {"Generic XT clone", ROM_GENXT, "genxt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"AMI XT clone", ROM_AMIXT, "amixt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"DTK XT clone", ROM_DTKXT, "dtk", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"VTech Laser Turbo XT", ROM_LTXT, "ltxt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"VTech Laser XT3", ROM_LXT3, "lxt3", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"Phoenix XT clone", ROM_PXXT, "pxxt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"Juko XT clone", ROM_JUKOPC, "jukopc", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 0, 0, 64, 640, 64, xt_init, NULL}, - {"Tandy 1000", ROM_TANDY, "tandy", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 1, 0, 128, 640, 128, tandy1k_init, &tandy1000_device}, - {"Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, 1, 0, 256, 640, 128, tandy1k_init, &tandy1000hx_device}, - {"Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, 1, 0, 512, 768, 128, tandy1ksl2_init, NULL}, - {"Amstrad PC1512", ROM_PC1512, "pc1512", { {"", cpus_pc1512}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 512, 640, 128, ams_init, NULL}, - {"Sinclair PC200", ROM_PC200, "pc200", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 512, 640, 128, ams_init, NULL}, - {"Euro PC", ROM_EUROPC, "europc", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, 0, 0, 512, 640, 128, europc_init, NULL}, - {"Olivetti M24", ROM_OLIM24, "olivetti_m24", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, 1, MODEL_OLIM24, 128, 640, 128, olim24_init, NULL}, - {"Amstrad PC1640", ROM_PC1640, "pc1640", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, - {"Amstrad PC2086", ROM_PC2086, "pc2086", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, - {"Amstrad PC3086", ROM_PC3086, "pc3086", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, 1, MODEL_AMSTRAD, 640, 640, 0, ams_init, NULL}, - {"IBM AT", ROM_IBMAT, "ibmat", { {"", cpus_ibmat}, {"", NULL}, {"", NULL}}, 0, MODEL_AT, 1, 16, 1, ibm_at_init, NULL}, - {"Commodore PC 30 III", ROM_CMDPC30, "cmdpc30", { {"", cpus_286}, {"", NULL}, {"", NULL}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 16, 1, at_ide_init, NULL}, - {"AMI 286 clone", ROM_AMI286, "ami286", { {"", cpus_286}, {"", NULL}, {"", NULL}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 16, 1, at_neat_init, NULL}, - {"Award 286 clone", ROM_AWARD286, "award286", { {"", cpus_286}, {"", NULL}, {"", NULL}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 16, 1, at_scat_init, NULL}, - {"DELL System 200", ROM_DELL200, "dells200", { {"", cpus_286}, {"", NULL}, {"", NULL}}, 0, MODEL_AT, 1, 16, 1, at_init, NULL}, - {"IBM PS/1 model 2011", ROM_IBMPS1_2011, "ibmps1es", { {"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}}, 1, MODEL_AT|MODEL_PS2, 1, 16, 1, ps1_m2011_init, NULL}, - {"IBM PS/2 Model 30-286", ROM_IBMPS2_M30_286, "ibmps2_m30_286", { {"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}}, 1, MODEL_AT|MODEL_PS2, 1, 16, 1, ps2_m30_286_init, NULL}, - {"IBM PS/2 Model 50", ROM_IBMPS2_M50, "ibmps2_m50", { {"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}}, 1, MODEL_AT|MODEL_PS2|MODEL_MCA, 1, 16, 1, ps2_model_50_init, NULL}, - {"IBM PS/1 model 2121", ROM_IBMPS1_2121, "ibmps1_2121", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, 1, MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 16, 1, ps1_m2121_init, NULL}, - {"Compaq Deskpro 386", ROM_DESKPRO_386, "deskpro386", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, 0, MODEL_AT, 1, 15, 1, deskpro386_init, NULL}, - {"IBM PS/2 Model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, 1, MODEL_AT|MODEL_PS2|MODEL_MCA, 1, 8, 1, ps2_model_55sx_init, NULL}, - {"Acer 386SX25/N", ROM_ACER386, "acer386", { {"Intel", cpus_acer}, {"", NULL}, {"", NULL}}, 1, MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 16, 1, at_acer386sx_init, NULL}, - {"DTK 386SX clone", ROM_DTK386, "dtk386", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 16, 1, at_neat_init, NULL}, -/* {"Phoenix 386 clone", ROM_PX386, { "Intel", cpus_i386SX, "AMD", cpus_Am386SX, "Cyrix", cpus_486SLC}, 0, MODEL_AT, 1, 16, 1, at_init, NULL},*/ - {"Amstrad MegaPC", ROM_MEGAPC, "megapc", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, 1, MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 16, 1, at_wd76c10_init, NULL}, - {"AMI 386SX clone", ROM_AMI386SX, "ami386", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_headland_init, NULL}, - {"IBM PS/2 Model 80", ROM_IBMPS2_M80, "ibmps2_m80", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, 1, MODEL_AT|MODEL_PS2|MODEL_MCA, 1, 12, 1, ps2_model_80_init, NULL}, - {"MR 386DX clone", ROM_MR386DX_OPTI495, "mr386dx", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_opti495_init, NULL}, - {"AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_opti495_init, NULL}, - {"AMI 486 clone", ROM_AMI486, "ami486", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_ali1429_init, NULL}, - {"AMI WinBIOS 486", ROM_WIN486, "win486", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, 0, MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_ali1429_init, NULL}, -/* {"AMI WinBIOS 486 PCI", ROM_PCI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_um8881f_init},*/ - {"Award SiS 496/497", ROM_SIS496, "sis496", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, 0, MODEL_AT|MODEL_PCI|MODEL_HAS_IDE, 1, 256, 1, at_sis496_init, NULL}, - {"Intel Premiere/PCI", ROM_REVENGE, "revenge", { {"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}}, 0, MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 128, 1, at_batman_init, NULL}, - {"Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", { {"Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}}, 0, MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 128, 1, at_endeavor_init, NULL}, - {"Award 430VX PCI", ROM_430VX, "430vx", { {"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}}, 0, MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 256, 1, at_i430vx_init, NULL}, + {"[8088] AMI XT clone", ROM_AMIXT, "amixt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 64, 640, 64, xt_init, NULL}, + {"[8088] Atari PC3", ROM_ATARIPC3, "ataripc3", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 64, 640, 64, xt_init, NULL}, + {"[8088] Compaq Portable Plus", ROM_COMPAQ_PIP, "compaq_pip", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 128, 640, 64, compaq_xt_init, NULL}, + {"[8088] DTK XT clone", ROM_DTKXT, "dtk", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 64, 640, 64, xt_init, NULL}, + {"[8088] Generic XT clone", ROM_GENXT, "genxt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 32, 704, 16, xt_init, NULL}, + {"[8088] IBM PC", ROM_IBMPC, "ibmpc", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 64, 640, 32, xt_init, NULL}, + {"[8088] IBM PCjr", ROM_IBMPCJR, "ibmpcjr", { {"", cpus_pcjr}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED, 128, 640, 64, pcjr_init, &pcjr_device}, + {"[8088] IBM XT", ROM_IBMXT, "ibmxt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 64, 640, 64, xt_init, NULL}, + {"[8088] Juko XT clone", ROM_JUKOPC, "jukopc", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 64, 640, 64, xt_init, NULL}, + {"[8088] Leading Edge Model M", ROM_LEDGE_MODELM, "ledge_modelm", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 128, 704, 64, xt_init, NULL}, + {"[8088] NCR PC4i", ROM_NCR_PC4I, "ncr_pc4i", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 256, 640, 64, xt_init, NULL}, + {"[8088] Phoenix XT clone", ROM_PXXT, "pxxt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 64, 640, 64, xt_init, NULL}, + {"[8088] Schneider EuroPC", ROM_EUROPC, "europc", { {"", cpus_europc}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 512, 640, 128, europc_init, NULL}, + {"[8088] Tandy 1000", ROM_TANDY, "tandy", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED, 128, 640, 128, tandy1k_init, &tandy1000_device}, + {"[8088] Tandy 1000 HX", ROM_TANDY1000HX, "tandy1000hx", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED, 256, 640, 128, tandy1k_init, &tandy1000hx_device}, + {"[8088] Thomson TO16 PC", ROM_TO16_PC, "to16_pc", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 512, 640, 128, xt_init, NULL}, + {"[8088] Toshiba T1000", ROM_T1000, "t1000", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED, 512, 1280, 768, xt_t1000_init, NULL}, + {"[8088] VTech Laser Turbo XT", ROM_LTXT, "ltxt", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 64, 1152, 64, xt_laserxt_init, NULL}, + {"[8088] Xi8088", ROM_XI8088, "xi8088", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PS2, 64, 1024, 128, xt_xi8088_init, &xi8088_device}, + {"[8088] Zenith Data SupersPort", ROM_ZD_SUPERS, "zdsupers", { {"", cpus_8088}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 128, 640, 128, xt_zenith_init, NULL}, + + {"[8086] Amstrad PC1512", ROM_PC1512, "pc1512", { {"", cpus_pc1512}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED|MODEL_AMSTRAD, 512, 640, 128, ams_init, &ams1512_device}, + {"[8086] Amstrad PC1640", ROM_PC1640, "pc1640", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 640, 640, 0, ams_init, &ams1512_device}, + {"[8086] Amstrad PC2086", ROM_PC2086, "pc2086", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 640, 640, 0, ams_init, &ams2086_device}, + {"[8086] Amstrad PC3086", ROM_PC3086, "pc3086", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 640, 640, 0, ams_init, &ams3086_device}, + {"[8086] Amstrad PC5086", ROM_PC5086, "pc5086", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_PS2, 640, 640, 0, pc5086_init, &f82c710_upc_device}, + {"[8086] Amstrad PPC512/640", ROM_PPC512, "ppc512", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 512, 640, 128, ams_init, &ams1512_device}, + {"[8086] Compaq Deskpro", ROM_DESKPRO, "deskpro", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 128, 640, 128, compaq_xt_init, NULL}, + {"[8086] Olivetti M24", ROM_OLIM24, "olivetti_m24", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED|MODEL_OLIM24, 128, 640, 128, olim24_init, NULL}, + {"[8086] Sinclair PC200", ROM_PC200, "pc200", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AMSTRAD, 512, 640, 128, ams_init, &ams1512_device}, + {"[8086] Tandy 1000 SL/2", ROM_TANDY1000SL2, "tandy1000sl2", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED, 512, 768, 128, tandy1ksl2_init, NULL}, + {"[8088] Toshiba T1200", ROM_T1200, "t1200", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED, 1024, 2048,1024, xt_t1200_init, NULL}, + {"[8086] VTech Laser XT3", ROM_LXT3, "lxt3", { {"", cpus_8086}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE, 512, 1152, 128, xt_laserxt_init, NULL}, + + {"[286] AMI 286 clone", ROM_AMI286, "ami286", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 512,16384, 128, at_neat_init, NULL}, + {"[286] Award 286 clone", ROM_AWARD286, "award286", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 512,16384, 128, at_scat_init, NULL}, + {"[286] Bull Micral 45", ROM_BULL_MICRAL_45, "bull_micral_45", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 1024, 6144, 128, ibm_at_init, NULL}, + {"[286] Commodore PC 30 III", ROM_CMDPC30, "cmdpc30", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 640,16384, 128, at_cbm_init, NULL}, + {"[286] Compaq Portable II", ROM_COMPAQ_PII, "compaq_pii", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 256,15872, 128, ibm_at_init, NULL}, + {"[286] DELL System 200", ROM_DELL200, "dells200", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT, 640,16384, 128, dells200_init, NULL}, + {"[286] Epson PC AX", ROM_EPSON_PCAX, "epson_pcax", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT, 256,15872, 128, at_init, NULL}, + {"[286] Epson PC AX2e", ROM_EPSON_PCAX2E, "epson_pcax2e", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PS2, 256,15872, 128, at_init, NULL}, + {"[286] Goldstar GDC-212M", ROM_GDC212M, "gdc212m", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 512, 4096, 512, at_scat_init, NULL}, + {"[286] GW-286CT GEAR", ROM_GW286CT, "gw286ct", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT, 512,16384, 128, at_scat_init, NULL}, + {"[286] Hyundai Super-286TR", ROM_HYUNDAI_SUPER286TR, "super286tr", { {"AMD", cpus_super286tr}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 1024, 4096, 128, at_scat_init, &f82c710_upc_device}, + {"[286] IBM AT", ROM_IBMAT, "ibmat", { {"", cpus_ibmat}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT, 256,15872, 128, ibm_at_init, NULL}, + {"[286] IBM PS/1 model 2011", ROM_IBMPS1_2011, "ibmps1es", { {"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_PS2, 512,16384, 512, ps1_m2011_init, NULL}, + {"[286] IBM PS/2 Model 30-286", ROM_IBMPS2_M30_286, "ibmps2_m30_286", { {"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_PS2, 1, 16, 1, ps2_m30_286_init, NULL}, + {"[286] IBM PS/2 Model 50", ROM_IBMPS2_M50, "ibmps2_m50", { {"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_MCA, 1, 16, 1, ps2_model_50_init, NULL}, + {"[286] IBM XT Model 286", ROM_IBMXT286, "ibmxt286", { {"", cpus_ibmxt286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT, 256,15872, 128, ibm_at_init, NULL}, + {"[286] Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 512, 2048, 128, at_scat_init, NULL}, + {"[286] Samsung SPC-4216P", ROM_SPC4216P, "spc4216p", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 5, 1, at_scat_init, NULL}, + {"[286] Samsung SPC-4620P", ROM_SPC4620P, "spc4620p", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_HW|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 5, 1, at_scat_init, NULL}, + {"[286] Toshiba T3100e", ROM_T3100E, "t3100e", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_HAS_IDE, 1024, 5120, 256, at_t3100e_init, NULL}, + {"[286] Trigem 286M", ROM_TG286M, "tg286m", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 512, 8192, 128, at_headland_init, NULL}, + {"[286] Tulip AT Compact", ROM_TULIP_TC7, "tulip_tc7", { {"", cpus_286}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 640,15872, 128, ibm_at_init, NULL}, + + {"[386SX] Acer 386SX25/N", ROM_ACER386, "acer386", { {"Intel", cpus_acer}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 16, 1, at_acer386sx_init, NULL}, + {"[386SX] AMA-932J", ROM_AMA932J, "ama932j", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_HAS_IDE, 512, 8192, 128, at_headland_init, NULL}, + {"[386SX] AMI 386SX clone", ROM_AMI386SX, "ami386", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 512,16384, 128, at_headland_init, NULL}, + {"[386SX] Amstrad MegaPC", ROM_MEGAPC, "megapc", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_DISABLE_HW|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 16, 1, at_wd76c10_init, NULL}, + {"[386SX] Commodore SL386SX-25", ROM_CBM_SL386SX25, "cbm_sl386sx25", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1024,16384, 512, at_scamp_init, NULL}, + {"[386SX] DTK 386SX clone", ROM_DTK386, "dtk386", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 512,16384, 128, at_neat_init, NULL}, + {"[386SX] Epson PC AX3", ROM_EPSON_PCAX3, "epson_pcax3", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_NONE|MODEL_AT, 256,15872, 128, at_init, NULL}, + {"[386SX] IBM PS/1 model 2121", ROM_IBMPS1_2121, "ibmps1_2121", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 16, 1, ps1_m2121_init, NULL}, + {"[386SX] IBM PS/2 Model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_MCA, 1, 8, 1, ps2_model_55sx_init, NULL}, + {"[386SX] KMX-C-02", ROM_KMXC02, "kmxc02", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_NONE|MODEL_AT, 512,16384, 512, at_scatsx_init, NULL}, + {"[386SX] Packard Bell Legend 300SX", ROM_PB_L300SX, "pb_l300sx", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 16, 1, pb_l300sx_init, NULL}, + {"[386SX] Samsung SPC-6033P", ROM_SPC6033P, "spc6033p", { {"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}}, MODEL_GFX_DISABLE_HW|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 2, 12, 2, at_scamp_init, NULL}, + + {"[386DX] AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_opti495_init, NULL}, + {"[386DX] Compaq Deskpro 386", ROM_DESKPRO_386, "deskpro386", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, MODEL_GFX_NONE|MODEL_AT, 1, 15, 1, deskpro386_init, NULL}, + {"[386DX] ECS 386/32", ROM_ECS_386_32, "ecs_386_32", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, MODEL_GFX_NONE|MODEL_AT, 1, 16, 1, at_cs8230_init, NULL}, + {"[386DX] IBM PS/2 Model 70 (type 3)", ROM_IBMPS2_M70_TYPE3, "ibmps2_m70_type3", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_MCA, 2, 16, 2, ps2_model_70_init, NULL}, + {"[386DX] IBM PS/2 Model 80", ROM_IBMPS2_M80, "ibmps2_m80", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_MCA, 1, 12, 1, ps2_model_80_init, NULL}, + {"[386DX] MR 386DX clone", ROM_MR386DX_OPTI495, "mr386dx", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_opti495_init, NULL}, + {"[386DX] Samsung SPC-6000A", ROM_SPC6000A, "spc6000a", { {"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 1, 32, 1, at_cs8230_init, NULL}, + + {"[486] AMI 486 clone", ROM_AMI486, "ami486", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_ali1429_init, NULL}, + {"[486] AMI WinBIOS 486", ROM_WIN486, "win486", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_NONE|MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_ali1429_init, NULL}, + {"[486] Award SiS 496/497", ROM_SIS496, "sis496", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_HAS_IDE, 1, 256, 1, at_sis496_init, NULL}, + {"[486] Elonex PC-425X", ROM_ELX_PC425X, "elx_pc425x", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_HAS_IDE, 1, 256, 1, at_sl82c460_init, NULL}, + {"[486] IBM PS/1 Model 2133 (EMEA 451)",ROM_IBMPS1_2133_451, "ibmps1_2133", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_FIXED|MODEL_AT|MODEL_PS2, 2, 64, 2, ps1_m2133_init, NULL}, + {"[486] IBM PS/2 Model 70 (type 4)", ROM_IBMPS2_M70_TYPE4, "ibmps2_m70_type4", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_MCA, 2, 16, 2, ps2_model_70_init, NULL}, + {"[486] Packard Bell PB410A", ROM_PB410A, "pb410a", { {"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PS2|MODEL_HAS_IDE, 1, 64, 1, at_pb410a_init, NULL}, + + {"[Socket 4] Intel Premiere/PCI", ROM_REVENGE, "revenge", { {"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 128, 1, at_batman_init, NULL}, + {"[Socket 4] Packard Bell PB520R",ROM_PB520R, "pb520r", { {"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 128, 1, at_pb520r_init, NULL}, + + {"[Socket 5] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", { {"Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 128, 1, at_endeavor_init, NULL}, + {"[Socket 5] Intel Advanced/ZP", ROM_ZAPPA, "zappa", { {"Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 128, 1, at_zappa_init, NULL}, + {"[Socket 5] Itautec Infoway Multimidia", ROM_ITAUTEC_INFOWAYM, "infowaym",{ {"Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 8, 128, 1, at_zappa_init, NULL}, + {"[Socket 5] Packard Bell PB570", ROM_PB570, "pb570", { {"Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}}, MODEL_GFX_DISABLE_SW|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 128, 1, at_pb570_init, NULL}, + + {"[Socket 7] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", { {"Intel", cpus_Pentium}, {"AMD", cpus_K6_S7}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 8, 128, 1, at_p55tvp4_init, NULL}, + {"[Socket 7] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", { {"Intel", cpus_Pentium}, {"AMD", cpus_K6_S7}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 8, 256, 1, at_p55t2p4_init, NULL}, + {"[Socket 7] Epox P55-VA", ROM_P55VA, "p55va", { {"Intel", cpus_Pentium}, {"AMD", cpus_K6_S7}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 8, 128, 1, at_p55va_init, NULL}, + {"[Socket 7] Shuttle HOT-557", ROM_430VX, "430vx", { {"Intel", cpus_Pentium}, {"AMD", cpus_K6_S7}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 8, 128, 1, at_i430vx_init, NULL}, + + {"[Super 7] FIC VA-503+", ROM_FIC_VA503P, "fic_va503p", { {"Intel", cpus_Pentium}, {"AMD", cpus_K6_SS7}, {"IDT", cpus_WinChip_SS7}, {"Cyrix", cpus_6x86_SS7}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 1, 512, 1, at_mvp3_init, NULL}, + + {"[Socket 8] Intel VS440FX", ROM_VS440FX, "vs440fx", { {"Intel", cpus_PentiumPro}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 8, 256, 8, at_vs440fx_init, NULL}, + + {"[Slot 1] Gigabyte GA-686BX", ROM_GA686BX, "ga686bx", { {"Intel", cpus_Slot1_100MHz}, {"VIA", cpus_VIA_100MHz}}, MODEL_GFX_NONE|MODEL_AT|MODEL_PCI|MODEL_PS2|MODEL_HAS_IDE, 8, 512, 8, at_ga686bx_init, NULL}, + {"", -1, "", {{"", 0}, {"", 0}, {"", 0}}, 0,0,0, 0} }; @@ -150,6 +262,11 @@ int model_getromset() return models[model].id; } +int model_getromset_from_model(int model) +{ + return models[model].id; +} + int model_getmodel(int romset) { int c = 0; @@ -193,6 +310,20 @@ int model_get_model_from_internal_name(char *s) return 0; } +int model_has_fixed_gfx(int model) +{ + int gfx_flags = models[model].flags & MODEL_GFX_MASK; + + return (gfx_flags == MODEL_GFX_FIXED); +} + +int model_has_optional_gfx(int model) +{ + int gfx_flags = models[model].flags & MODEL_GFX_MASK; + + return (gfx_flags == MODEL_GFX_DISABLE_HW || gfx_flags == MODEL_GFX_DISABLE_SW); +} + void common_init() { dma_init(); @@ -200,8 +331,8 @@ void common_init() lpt_init(); pic_init(); pit_init(); - serial1_init(0x3f8, 4); - serial2_init(0x2f8, 3); + serial1_init(0x3f8, 4, 1); + serial2_init(0x2f8, 3, 1); } void xt_init() @@ -212,6 +343,16 @@ void xt_init() keyboard_xt_init(); nmi_init(); device_add(&gameport_device); + if (romset == ROM_IBMPC) + device_add(&cassette_device); +} + +void compaq_xt_init() +{ + xt_init(); + lpt1_remove(); + lpt2_remove(); + lpt1_init(0x3bc); } void pcjr_init() @@ -221,10 +362,11 @@ void pcjr_init() pic_init(); pit_init(); pit_set_out_func(&pit, 0, pit_irq0_timer_pcjr); - serial1_init(0x2f8, 3); + serial1_init(0x2f8, 3, 1); keyboard_pcjr_init(); device_add(&sn76489_device); nmi_mask = 0x80; + device_add(&cassette_device); } void tandy1k_init() @@ -260,14 +402,27 @@ void ams_init() AMSTRAD = 1; common_init(); mem_add_bios(); + lpt1_remove(); amstrad_init(); keyboard_amstrad_init(); - nvr_init(); - nmi_init(); - fdc_set_dskchg_activelow(); + device_add(&nvr_device); + nmi_init(); + fdc_set_dskchg_activelow(); device_add(&gameport_device); } +void pc5086_init() +{ + xt_init(); + lpt1_remove(); /* remove LPT ports, they will be enabled by 82C710 */ + lpt2_remove(); + serial1_remove(); /* remove COM ports, they will be enabled by 82C710 */ + serial2_remove(); + device_add(&nvr_device); + fdc_set_dskchg_activelow(); + superxt_init(); +} + void europc_init() { common_init(); @@ -283,12 +438,47 @@ void olim24_init() common_init(); mem_add_bios(); keyboard_olim24_init(); - nvr_init(); + device_add(&nvr_device); olivetti_m24_init(); nmi_init(); device_add(&gameport_device); } +void xt_laserxt_init() +{ + xt_init(); + laserxt_init(); +} + +void xt_zenith_init() /* [8088] Zenith Data Systems SupersPort */ +{ + dma_init(); + fdc_add(); + lpt_init(); + lpt2_remove(); /* only one parallel port */ + pic_init(); + pit_init(); + serial1_init(0x3f8, 4, 1); /* only one serial port */ + mem_add_bios(); + device_add(&zenith_scratchpad_device); + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + keyboard_xt_init(); + nmi_init(); +} + +void xt_xi8088_init() +{ + common_init(); + mem_add_bios(); + keyboard_at_init(); + keyboard_at_init_ps2(); + nmi_init(); + device_add(&nvr_device); + pic2_init(); + device_add(&gameport_device); + device_add(&sst_39sf010_device); +} + void at_init() { AT = 1; @@ -297,9 +487,10 @@ void at_init() pit_set_out_func(&pit, 1, pit_refresh_timer_at); dma16_init(); keyboard_at_init(); - nvr_init(); + device_add(&nvr_device); pic2_init(); device_add(&gameport_device); + nmi_mask = 0; } void ibm_at_init() @@ -308,10 +499,10 @@ void ibm_at_init() mem_remap_top_384k(); } -void at_ide_init() +void at_cbm_init() { at_init(); - ide_init(); + cbm_io_init(); } void deskpro386_init() @@ -320,6 +511,12 @@ void deskpro386_init() compaq_init(); } +void dells200_init() +{ + at_init(); + dells200_chipset_init(); +} + void ps1_common_init() { AT = 1; @@ -327,9 +524,8 @@ void ps1_common_init() mem_add_bios(); pit_set_out_func(&pit, 1, pit_refresh_timer_at); dma16_init(); - ide_init(); keyboard_at_init(); - nvr_init(); + device_add(&nvr_device); pic2_init(); fdc_set_dskchg_activelow(); device_add(&ps1_audio_device); @@ -341,6 +537,7 @@ void ps1_m2011_init() { ps1_common_init(); ps1mb_init(); + mem_remap_top_384k(); } void ps1_m2121_init() @@ -350,6 +547,13 @@ void ps1_m2121_init() fdc_set_ps1(); } +void ps1_m2133_init(void) +{ + at_init(); + vl82c480_init(); + ps1mb_m2133_init(); +} + void ps2_m30_286_init() { AT = 1; @@ -357,10 +561,9 @@ void ps2_m30_286_init() mem_add_bios(); pit_set_out_func(&pit, 1, pit_refresh_timer_at); dma16_init(); - ide_init(); keyboard_at_init(); // mouse_ps2_init(); - nvr_init(); + device_add(&nvr_device); pic2_init(); ps2board_init(); fdc_set_dskchg_activelow(); @@ -373,14 +576,15 @@ static void ps2_common_init() mem_add_bios(); dma16_init(); ps2_dma_init(); - ide_init(); keyboard_at_init(); keyboard_at_init_ps2(); // mouse_ps2_init(); - nvr_init(); + device_add(&nvr_device); pic2_init(); pit_ps2_init(); + + nmi_mask = 0x80; } void ps2_model_50_init() @@ -395,6 +599,12 @@ void ps2_model_55sx_init() ps2_mca_board_model_55sx_init(); } +void ps2_model_70_init() +{ + ps2_common_init(); + ps2_mca_board_model_70_type34_init(romset == ROM_IBMPS2_M70_TYPE4); +} + void ps2_model_80_init() { ps2_common_init(); @@ -404,106 +614,264 @@ void ps2_model_80_init() void at_neat_init() { at_init(); - ide_init(); neat_init(); } +void at_scamp_init() +{ + at_init(); + scamp_init(); +} + void at_scat_init() { at_init(); - ide_init(); scat_init(); } +void at_scatsx_init() +{ + at_init(); + scatsx_init(); +} + void at_acer386sx_init() { at_init(); - ide_init(); acer386sx_init(); } void at_wd76c10_init() { at_init(); - ide_init(); wd76c10_init(); } void at_headland_init() { at_init(); - ide_init(); headland_init(); } void at_opti495_init() { at_init(); - ide_init(); opti495_init(); } +void at_cs8230_init() +{ + at_init(); + cs8230_init(); +} + void at_ali1429_init() { at_init(); - ide_init(); ali1429_init(); } -void at_um8881f_init() +void pb_l300sx_init() { at_init(); - ide_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); - um8881f_init(); + acc2036_init(); } +void at_pb410a_init() +{ + at_init(); + acc2168_init(); + acc3221_init(); +} + + void at_sis496_init() { at_init(); - ide_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xb); + pci_slot(0xd); + pci_slot(0xf); device_add(&sis496_device); } +void at_sl82c460_init() +{ + at_init(); + sl82c460_init(); +} + void at_batman_init() { at_init(); - ide_init(); - pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); + pci_init(PCI_CONFIG_TYPE_2); + pci_slot(0xc); + pci_slot(0xe); + pci_slot(0x6); i430lx_init(); + sio_init(2, 0xc, 0xe, 0x6, 0); fdc37c665_init(); intel_batman_init(); device_add(&intel_flash_bxt_ami_device); } +void at_pb520r_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_2); + pci_slot(0xc); + pci_slot(0xe); + pci_slot(0x6); + i430lx_init(); + sio_init(2, 0xc, 0xe, 0x6, 0); + cmd640b_init(1); + aip_82091aa_init(0x22); + intel_batman_init(); + device_add(&intel_flash_bxt_ami_device); +} void at_endeavor_init() { at_init(); - ide_init(); - pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xd); + pci_slot(0xe); + pci_slot(0xf); + pci_slot(0x10); i430fx_init(); - piix_init(7); - um8669f_init(); + piix_init(7, 0xd, 0xe, 0xf, 0x10, i430fx_reset); + pc87306_init(0x2e); intel_endeavor_init(); device_add(&intel_flash_bxt_ami_device); } +void at_pb570_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x11); + pci_slot(0x13); + i430fx_init(); + piix_init(7, 0x11, 0x13, 0xb, 0x8, i430fx_reset); + pc87306_init(0x2e); + intel_endeavor_init(); + device_add(&intel_flash_bxt_ami_device); +} +void at_zappa_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xd); + pci_slot(0xe); + pci_slot(0xf); + pci_slot(0x10); + i430fx_init(); + piix_init(7, 0xd, 0xf, 0xe, 0x10, i430fx_reset); + pc87306_init(0x2e); + intel_zappa_init(); + device_add(&intel_flash_bxt_ami_device); +} + +void at_p55va_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x08); + pci_slot(0x09); + pci_slot(0x0A); + pci_slot(0x0B); + i430vx_init(); + piix_init(7, 0x08, 0x09, 0x0A, 0x0B, i430vx_reset); + fdc37c932fr_init(); + device_add(&intel_flash_bxt_device); +} + +void at_p55tvp4_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x0C); + pci_slot(0x0B); + pci_slot(0x0A); + pci_slot(0x09); + i430vx_init(); + piix_init(7, 0x0C, 0x0B, 0x0A, 0x09, i430vx_reset); + w83877f_init(0x3f0, 0x87); + device_add(&intel_flash_bxt_device); +} void at_i430vx_init() { at_init(); - ide_init(); - pci_init(PCI_CONFIG_TYPE_1, 0, 31); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x11); + pci_slot(0x12); + pci_slot(0x13); + pci_slot(0x14); i430vx_init(); - piix_init(7); + piix_init(7, 18, 17, 20, 19, i430vx_reset); um8669f_init(); device_add(&intel_flash_bxt_device); } +void at_p55t2p4_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x0C); + pci_slot(0x0B); + pci_slot(0x0A); + pci_slot(0x09); + i430hx_init(); + piix_init(7, 0x0C, 0x0B, 0x0A, 0x09, i430hx_reset); + w83877f_init(0x3f0, 0x87); + device_add(&intel_flash_bxt_device); +} + +void at_mvp3_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(8); + pci_slot(9); + pci_slot(10); + mvp3_init(); + vt82c586b_init(7, 8, 9, 10, 0); + w83877tf_init(0x250, 0x89); + device_add(&sst_39sf010_device); +} + +void at_vs440fx_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0xb); + pci_slot(0xf); + pci_slot(0x11); + pci_slot(0x13); + i440fx_init(); + piix_init(7, 0xb, 0xf, 0x11, 0x13, i440fx_reset); + pc87307_init(0x2e); +// i440fx_init(); + device_add(&intel_flash_28fb200bxt_device); +} + +void at_ga686bx_init() +{ + at_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_slot(0x8); + pci_slot(0x9); + pci_slot(0xa); + pci_slot(0xb); + i440bx_init(); + piix4_init(7, 0x8, 0x9, 0xa, 0xb, i440bx_reset); + w83977tf_init(0x3f0, 0x87); + device_add(&intel_flash_28f002bc_device); +} + void model_init() { pclog("Initting as %s\n", model_getname()); - AMSTRAD = AT = PCI = TANDY = 0; - io_init(); + AMSTRAD = AT = PCI = TANDY = MCA = 0; + ide_set_bus_master(NULL, NULL, NULL, NULL); models[model].init(); if (models[model].device) diff --git a/src/model.h b/src/model.h index 3931288..7b568f1 100644 --- a/src/model.h +++ b/src/model.h @@ -6,17 +6,26 @@ #define MODEL_MCA 0x20 #define MODEL_PCI 0x40 +/*Machine has no integrated graphics*/ +#define MODEL_GFX_NONE 0x000 +/*Machine has integrated graphics that can not be disabled*/ +#define MODEL_GFX_FIXED 0x100 +/*Machine has integrated graphics that can be disabled by jumpers or switches*/ +#define MODEL_GFX_DISABLE_HW 0x200 +/*Machine has integrated graphics that can be disabled through software*/ +#define MODEL_GFX_DISABLE_SW 0x300 +#define MODEL_GFX_MASK 0x300 + typedef struct { - char name[32]; + char name[64]; int id; char internal_name[24]; struct { char name[8]; CPU *cpus; - } cpu[4]; - int fixed_gfxcard; + } cpu[5]; int flags; int min_ram, max_ram; int ram_granularity; @@ -30,9 +39,12 @@ extern int model; int model_count(); int model_getromset(); +int model_getromset_from_model(int model); int model_getmodel(int romset); char *model_getname(); char *model_get_internal_name(); int model_get_model_from_internal_name(char *s); void model_init(); struct device_t *model_getdevice(int model); +int model_has_fixed_gfx(int model); +int model_has_optional_gfx(int model); diff --git a/src/mouse.c b/src/mouse.c index 3ac9b84..b808aac 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -1,6 +1,7 @@ #include "ibm.h" #include "mouse.h" #include "amstrad.h" +#include "mouse_msystems.h" #include "mouse_ps2.h" #include "mouse_serial.h" #include "keyboard_olim24.h" @@ -8,6 +9,7 @@ static mouse_t *mouse_list[] = { &mouse_serial_microsoft, + &mouse_serial_msystems, &mouse_ps2_2_button, &mouse_intellimouse, &mouse_amstrad, diff --git a/src/mouse.h b/src/mouse.h index 216ed73..d39f539 100644 --- a/src/mouse.h +++ b/src/mouse.h @@ -1,3 +1,6 @@ +#ifndef _MOUSE_H_ +#define _MOUSE_H_ + void mouse_emu_init(); void mouse_emu_close(); void mouse_poll(int x, int y, int z, int b); @@ -24,3 +27,5 @@ typedef struct } mouse_t; extern int mouse_type; + +#endif diff --git a/src/mouse_msystems.c b/src/mouse_msystems.c new file mode 100644 index 0000000..9424191 --- /dev/null +++ b/src/mouse_msystems.c @@ -0,0 +1,88 @@ +#include +#include "ibm.h" +#include "mouse.h" +#include "pic.h" +#include "serial.h" +#include "timer.h" + +typedef struct mouse_msystems_t +{ + int mousepos, mousedelay; + int oldb; + SERIAL *serial; +} mouse_msystems_t; + +static void mouse_msystems_poll(int x, int y, int z, int b, void *p) +{ + mouse_msystems_t *mouse = (mouse_msystems_t *)p; + SERIAL *serial = mouse->serial; + uint8_t mousedat[5]; + + if (!x && !y && b == mouse->oldb) + return; + + mouse->oldb = b; + y = -y; + if (x > 127) + x = 127; + if (y > 127) + y = 127; + if (x < -128) + x = -128; + if (y < -128) + y = -128; + + /*Use Mouse Systems format*/ + mousedat[0] = 0x87; + if (b & 1) + mousedat[0] &= ~0x04; + if (b & 2) + mousedat[0] &= ~0x01; + if (b & 4) + mousedat[0] &= ~0x02; + + mousedat[1] = x; + mousedat[2] = y; + mousedat[3] = 0; + mousedat[4] = 0; + + if (!(serial->mctrl & 0x10)) + { +// pclog("Serial data %02X %02X %02X\n", mousedat[0], mousedat[1], mousedat[2]); + serial_write_fifo(mouse->serial, mousedat[0]); + serial_write_fifo(mouse->serial, mousedat[1]); + serial_write_fifo(mouse->serial, mousedat[2]); + serial_write_fifo(mouse->serial, mousedat[3]); + serial_write_fifo(mouse->serial, mousedat[4]); + } +} + +static void *mouse_msystems_init() +{ + mouse_msystems_t *mouse = (mouse_msystems_t *)malloc(sizeof(mouse_msystems_t)); + memset(mouse, 0, sizeof(mouse_msystems_t)); + + mouse->serial = &serial1; + serial1.rcr_callback = NULL; + serial1.rcr_callback_p = NULL; + + return mouse; +} + +static void mouse_msystems_close(void *p) +{ + mouse_msystems_t *mouse = (mouse_msystems_t *)p; + + free(mouse); + + serial1.rcr_callback = NULL; +} + +mouse_t mouse_serial_msystems = +{ + "Mouse Systems 3-button mouse (serial)", + mouse_msystems_init, + mouse_msystems_close, + mouse_msystems_poll, + MOUSE_TYPE_SERIAL | MOUSE_TYPE_3BUTTON +}; diff --git a/src/mouse_msystems.h b/src/mouse_msystems.h new file mode 100644 index 0000000..0f1430f --- /dev/null +++ b/src/mouse_msystems.h @@ -0,0 +1 @@ +extern mouse_t mouse_serial_msystems; diff --git a/src/mouse_ps2.c b/src/mouse_ps2.c index 1603cd9..28a362b 100644 --- a/src/mouse_ps2.c +++ b/src/mouse_ps2.c @@ -4,6 +4,8 @@ #include "mouse.h" #include "mouse_ps2.h" #include "plat-mouse.h" +#include "x86.h" +#include "f82c710_upc.h" int mouse_scan = 0; @@ -96,6 +98,27 @@ void mouse_ps2_write(uint8_t val, void *p) keyboard_at_adddata_mouse(mouse->sample_rate); break; + case 0xeb: /*Get mouse data*/ + keyboard_at_adddata_mouse(0xfa); + + temp = 0; + if (mouse->x < 0) + temp |= 0x10; + if (mouse->y < 0) + temp |= 0x20; + if (mouse_buttons & 1) + temp |= 1; + if (mouse_buttons & 2) + temp |= 2; + if ((mouse_buttons & 4) && (mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON)) + temp |= 4; + keyboard_at_adddata_mouse(temp); + keyboard_at_adddata_mouse(mouse->x & 0xff); + keyboard_at_adddata_mouse(mouse->y & 0xff); + if (mouse->intellimouse_mode) + keyboard_at_adddata_mouse(mouse->z); + break; + case 0xf2: /*Read ID*/ keyboard_at_adddata_mouse(0xfa); if (mouse->intellimouse_mode) @@ -123,6 +146,7 @@ void mouse_ps2_write(uint8_t val, void *p) mouse->mode = MOUSE_STREAM; mouse->flags = 0; mouse->intellimouse_mode = 0; + mouse_queue_start = mouse_queue_end = 0; keyboard_at_adddata_mouse(0xfa); keyboard_at_adddata_mouse(0xaa); keyboard_at_adddata_mouse(0x00); @@ -153,7 +177,7 @@ void mouse_ps2_poll(int x, int y, int z, int b, void *p) { mouse_ps2_t *mouse = (mouse_ps2_t *)p; uint8_t packet[3] = {0x08, 0, 0}; - + if (!x && !y && !z && b == mouse->b) return; @@ -214,8 +238,11 @@ void *mouse_ps2_init() mouse->flags = 0; mouse->mode = MOUSE_STREAM; - keyboard_at_set_mouse(mouse_ps2_write, mouse); - + if(romset == ROM_PC5086) + upc_set_mouse(mouse_ps2_write, mouse); + else + keyboard_at_set_mouse(mouse_ps2_write, mouse); + return mouse; } diff --git a/src/mouse_serial.c b/src/mouse_serial.c index 9964153..b8bd187 100644 --- a/src/mouse_serial.c +++ b/src/mouse_serial.c @@ -7,7 +7,8 @@ typedef struct mouse_serial_t { - int mousepos, mousedelay; + int mousepos; + pc_timer_t mousedelay_timer; int oldb; SERIAL *serial; } mouse_serial_t; @@ -52,14 +53,13 @@ void mouse_serial_rcr(struct SERIAL *serial, void *p) mouse_serial_t *mouse = (mouse_serial_t *)p; mouse->mousepos = -1; - mouse->mousedelay = 5000 * (1 << TIMER_SHIFT); + timer_set_delay_u64(&mouse->mousedelay_timer, TIMER_USEC * 5000); } void mousecallback(void *p) { mouse_serial_t *mouse = (mouse_serial_t *)p; - mouse->mousedelay = 0; if (mouse->mousepos == -1) { mouse->mousepos = 0; @@ -75,7 +75,7 @@ void *mouse_serial_init() mouse->serial = &serial1; serial1.rcr_callback = mouse_serial_rcr; serial1.rcr_callback_p = mouse; - timer_add(mousecallback, &mouse->mousedelay, &mouse->mousedelay, mouse); + timer_add(&mouse->mousedelay_timer, mousecallback, mouse, 0); return mouse; } diff --git a/src/mvp3.c b/src/mvp3.c new file mode 100644 index 0000000..f2d77b1 --- /dev/null +++ b/src/mvp3.c @@ -0,0 +1,243 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "mvp3.h" + +static struct +{ + uint8_t host_bridge_regs[256]; + uint8_t pci_bridge_regs[256]; +} mvp3; + +static void mvp3_map(uint32_t addr, uint32_t size, int state) +{ + pclog("mvp3_map: addr=%08x size=%08x state=%i\n", addr, size, 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_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +static uint8_t mvp3_read(int func, int addr, void *priv) +{ + switch (func) + { + case 0: + return mvp3.host_bridge_regs[addr]; + + case 1: + return mvp3.pci_bridge_regs[addr]; + + default: + return 0xff; + } +} + + +static void mvp3_host_bridge_write(int addr, uint8_t val) +{ + /*Read-only addresses*/ + if ((addr < 4) || (addr >= 5 && addr < 7) + || (addr >= 8 && addr < 0xd) + || (addr >= 0xe && addr < 0x12) + || (addr >= 0x14 && addr < 0x50) + || (addr >= 0x79 && addr < 0x7e) + || (addr >= 0x85 && addr < 0x88) + || (addr >= 0x8c && addr < 0xa8) + || (addr >= 0xad && addr < 0xfd)) + return; + + switch (addr) + { + case 0x04: /*Command*/ + mvp3.host_bridge_regs[0x04] = (mvp3.host_bridge_regs[0x04] & ~0x40) | (val & 0x40); + break; + case 0x07: /*Status*/ + mvp3.host_bridge_regs[0x07] &= ~(val & 0xb0); + break; + + case 0x12: /*Graphics Aperture Base*/ + mvp3.host_bridge_regs[0x12] = (val & 0xf0); + break; + case 0x13: /*Graphics Aperture Base*/ + mvp3.host_bridge_regs[0x13] = val; + break; + + case 0x61: /*Shadow RAM Control 1*/ + if ((mvp3.host_bridge_regs[0x61] ^ val) & 0x03) + mvp3_map(0xc0000, 0x04000, val & 0x03); + if ((mvp3.host_bridge_regs[0x61] ^ val) & 0x0c) + mvp3_map(0xc4000, 0x04000, (val & 0x0c) >> 2); + if ((mvp3.host_bridge_regs[0x61] ^ val) & 0x30) + mvp3_map(0xc8000, 0x04000, (val & 0x30) >> 4); + if ((mvp3.host_bridge_regs[0x61] ^ val) & 0xc0) + mvp3_map(0xcc000, 0x04000, (val & 0xc0) >> 6); + mvp3.host_bridge_regs[0x61] = val; + return; + case 0x62: /*Shadow RAM Control 2*/ + if ((mvp3.host_bridge_regs[0x62] ^ val) & 0x03) + mvp3_map(0xd0000, 0x04000, val & 0x03); + if ((mvp3.host_bridge_regs[0x62] ^ val) & 0x0c) + mvp3_map(0xd4000, 0x04000, (val & 0x0c) >> 2); + if ((mvp3.host_bridge_regs[0x62] ^ val) & 0x30) + mvp3_map(0xd8000, 0x04000, (val & 0x30) >> 4); + if ((mvp3.host_bridge_regs[0x62] ^ val) & 0xc0) + mvp3_map(0xdc000, 0x04000, (val & 0xc0) >> 6); + mvp3.host_bridge_regs[0x62] = val; + return; + case 0x63: /*Shadow RAM Control 3*/ + if ((mvp3.host_bridge_regs[0x63] ^ val) & 0x30) + mvp3_map(0xf0000, 0x10000, (val & 0x30) >> 4); + if ((mvp3.host_bridge_regs[0x63] ^ val) & 0xc0) + mvp3_map(0xe0000, 0x10000, (val & 0xc0) >> 6); + mvp3.host_bridge_regs[0x63] = val; + if ((val & 3) == 1 || ((val & 3) == 3 && (cpu_cur_status & CPU_STATUS_SMM))) /*SMRAM enabled*/ + { + pclog("Enable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + } + else + { + pclog("Disable SMRAM\n"); + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } +// if (val == 0xb0) +// output = 3; + return; + + default: + mvp3.host_bridge_regs[addr] = val; + break; + } +} +static void mvp3_pci_bridge_write(int addr, uint8_t val) +{ + /*Read-only addresses*/ + if ((addr < 4) || (addr >= 5 && addr < 7) + || (addr >= 8 && addr < 0x18) + || (addr == 0x1b) + || (addr >= 0x1e && addr < 0x20) + || (addr >= 0x28 && addr < 0x3e) + || (addr >= 0x43)) + return; + + switch (addr) + { + case 0x04: /*Command*/ + mvp3.pci_bridge_regs[0x04] = (mvp3.pci_bridge_regs[0x04] & ~0x47) | (val & 0x47); + break; + case 0x07: /*Status*/ + mvp3.pci_bridge_regs[0x07] &= ~(val & 0x30); + break; + + case 0x20: /*Memory Base*/ + mvp3.pci_bridge_regs[0x20] = val & 0xf0; + break; + case 0x22: /*Memory Limit*/ + mvp3.pci_bridge_regs[0x22] = val & 0xf0; + break; + case 0x24: /*Prefetchable Memory Base*/ + mvp3.pci_bridge_regs[0x24] = val & 0xf0; + break; + case 0x26: /*Prefetchable Memory Limit*/ + mvp3.pci_bridge_regs[0x26] = val & 0xf0; + break; + + default: + mvp3.pci_bridge_regs[addr] = val; + break; + } +} + +static void mvp3_write(int func, int addr, uint8_t val, void *priv) +{ + switch (func) + { + case 0: + mvp3_host_bridge_write(addr, val); + break; + + case 1: + mvp3_pci_bridge_write(addr, val); + break; + } +} + +static void mvp3_smram_enable(void) +{ + if ((mvp3.host_bridge_regs[0x63] & 3) == 3) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); +} +static void mvp3_smram_disable(void) +{ + if ((mvp3.host_bridge_regs[0x63] & 3) != 1) + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + +void mvp3_init() +{ + pci_add_specific(0, mvp3_read, mvp3_write, NULL); + + memset(&mvp3, 0, sizeof(mvp3)); + mvp3.host_bridge_regs[0x00] = 0x06; mvp3.host_bridge_regs[0x01] = 0x11; /*VIA*/ + mvp3.host_bridge_regs[0x02] = 0x98; mvp3.host_bridge_regs[0x03] = 0x05; /*VT82C598MVP*/ + mvp3.host_bridge_regs[0x04] = 0x06; mvp3.host_bridge_regs[0x05] = 0x00; + mvp3.host_bridge_regs[0x06] = 0x90; mvp3.host_bridge_regs[0x07] = 0x02; + mvp3.host_bridge_regs[0x0b] = 0x06; + mvp3.host_bridge_regs[0x10] = 0x08; + mvp3.host_bridge_regs[0x34] = 0xa0; + + mvp3.host_bridge_regs[0x5a] = 0x01; + mvp3.host_bridge_regs[0x5b] = 0x01; + mvp3.host_bridge_regs[0x5c] = 0x01; + mvp3.host_bridge_regs[0x5d] = 0x01; + mvp3.host_bridge_regs[0x5e] = 0x01; + mvp3.host_bridge_regs[0x5f] = 0x01; + + mvp3.host_bridge_regs[0x64] = 0xec; + mvp3.host_bridge_regs[0x65] = 0xec; + mvp3.host_bridge_regs[0x66] = 0xec; + mvp3.host_bridge_regs[0x6b] = 0x01; + + mvp3.host_bridge_regs[0xa0] = 0x02; + mvp3.host_bridge_regs[0xa2] = 0x10; + mvp3.host_bridge_regs[0xa4] = 0x03; + mvp3.host_bridge_regs[0xa5] = 0x02; + mvp3.host_bridge_regs[0xa6] = 0x00; + mvp3.host_bridge_regs[0xa7] = 0x07; + + mvp3.pci_bridge_regs[0x00] = 0x06; mvp3.pci_bridge_regs[0x01] = 0x11; /*VIA*/ + mvp3.pci_bridge_regs[0x02] = 0x98; mvp3.pci_bridge_regs[0x03] = 0x85; /*VT82C598MVP*/ + mvp3.pci_bridge_regs[0x04] = 0x07; mvp3.pci_bridge_regs[0x05] = 0x00; + mvp3.pci_bridge_regs[0x06] = 0x20; mvp3.pci_bridge_regs[0x07] = 0x02; + mvp3.pci_bridge_regs[0x0a] = 0x04; + mvp3.pci_bridge_regs[0x0b] = 0x06; + mvp3.pci_bridge_regs[0x0e] = 0x01; + + mvp3.pci_bridge_regs[0x1c] = 0xf0; + + mvp3.pci_bridge_regs[0x20] = 0xf0; + mvp3.pci_bridge_regs[0x21] = 0xff; + + mvp3.pci_bridge_regs[0x24] = 0xf0; + mvp3.pci_bridge_regs[0x25] = 0xff; + + smram_enable = mvp3_smram_enable; + smram_disable = mvp3_smram_disable; +} diff --git a/src/mvp3.h b/src/mvp3.h new file mode 100644 index 0000000..69dac83 --- /dev/null +++ b/src/mvp3.h @@ -0,0 +1 @@ +void mvp3_init(); diff --git a/src/ne2000.c b/src/ne2000.c new file mode 100644 index 0000000..2622f2b --- /dev/null +++ b/src/ne2000.c @@ -0,0 +1,2103 @@ +///////////////////////////////////////////////////////////////////////// +// $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" +#ifdef _WIN32 +#include +#endif + +#include "ibm.h" +#include "device.h" + +#include "nethandler.h" + +#include "config.h" +#include "io.h" +#include "ne2000.h" +#include "pic.h" +#include "pci.h" +#include "timer.h" + +/*MAC address*/ +uint8_t maclocal[6]; + +typedef enum +{ + NE2000_NE2000, + NE2000_RTL8029AS +} ne2000_type; + +#define NE2000_PCI_IRQ -1 + +#define NETBLOCKING 0 //we won't block our pcap + +//#define NE2000_DEBUG + +#ifdef _WIN32 +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; +#endif + +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) + +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) + + // + // 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. + // + + // 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; + + ne2000_type type; + + /*PCI stuff*/ + int is_pci; + int card; + uint32_t base_addr; + uint8_t pci_command; + uint8_t int_line; + + /*RTL8029AS registers*/ + uint8_t config0, config2, config3; + uint8_t _9346cr; +} ne2000_t; + +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; +} + +static void ne2000_raise_irq(ne2000_t *ne2000) +{ + if (ne2000->is_pci) + pci_set_irq(ne2000->card, PCI_INTA); + else + picint(1 << ne2000->base_irq); +} + +static void ne2000_lower_irq(ne2000_t *ne2000) +{ + if (ne2000->is_pci) + pci_clear_irq(ne2000->card, PCI_INTA); + else + picintc(1 << ne2000->base_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; + int i; + + pclog("ne2000 reset\n"); + + // 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; + ne2000_raise_irq(ne2000); + ne2000_lower_irq(ne2000); + + //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) + { + ne2000_raise_irq(ne2000); + } + } + + return 0; +} + +uint16_t ne2000_asic_read_w(uint16_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); + } +#ifdef NE2000_DEBUG + pclog("asic read val=0x%04x\n", retval); +#endif + 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) + { + ne2000_raise_irq(ne2000); + } + } +} + +void ne2000_asic_write_w(uint16_t offset, uint16_t value, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; +#ifdef NE2000_DEBUG + pclog("asic write val=0x%04x\n", value); +#endif + 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(uint16_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(uint16_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); +} + +uint8_t ne2000_reset_read(uint16_t offset, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + ne2000_reset(BX_RESET_SOFTWARE, ne2000); + return 0; +} + +void ne2000_reset_write(uint16_t offset, uint8_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 +// +uint8_t ne2000_read(uint16_t address, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + int ret = 0; + +#ifdef NE2000_DEBUG + pclog("read addr %x\n", address); +#endif + 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)); +#ifdef NE2000_DEBUG + pclog("read CR returns 0x%08x\n", ret); +#endif + } + else + { + switch (ne2000->CR.pgsel) + { + case 0x00: +#ifdef NE2000_DEBUG + pclog("page 0 read from port %04x\n", address); +#endif + switch (address) + { + case 0x1: // CLDA0 + return ne2000->local_dma & 0xff; + + case 0x2: // CLDA1 + return ne2000->local_dma >> 8; + + case 0x3: // BNRY + return ne2000->bound_ptr; + + 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)); + + case 0x5: // NCR + return ne2000->num_coll; + + case 0x6: // FIFO + // reading FIFO is only valid in loopback mode +#ifdef NE2000_DEBUG + pclog("reading FIFO not supported yet\n"); +#endif + return ne2000->fifo; + + 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)); + + case 0x8: // CRDA0 + return ne2000->remote_dma & 0xff; + + case 0x9: // CRDA1 + return ne2000->remote_dma >> 8; + + case 0xa: // reserved +#ifdef NE2000_DEBUG + pclog("reserved read - page 0, 0xa\n"); +#endif + return 0xff; + + case 0xb: // reserved +#ifdef NE2000_DEBUG + pclog("reserved read - page 0, 0xb\n"); +#endif + return 0xff; + + 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)); + + case 0xd: // CNTR0 + return ne2000->tallycnt_0; + + case 0xe: // CNTR1 + return ne2000->tallycnt_1; + + case 0xf: // CNTR2 + return ne2000->tallycnt_2; + } + + return 0; + + case 0x01: +#ifdef NE2000_DEBUG + pclog("page 1 read from port %04x\n", address); +#endif + switch (address) + { + case 0x1: // PAR0-5 + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + return ne2000->physaddr[address - 1]; + + case 0x7: // CURR +#ifdef NE2000_DEBUG + pclog("returning current page: %02x\n", (ne2000->curr_page)); +#endif + 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]; + } + + return 0; + + case 0x02: +#ifdef NE2000_DEBUG + pclog("page 2 read from port %04x\n", address); +#endif + switch (address) + { + case 0x1: // PSTART + return (ne2000->page_start); + + case 0x2: // PSTOP + return ne2000->page_stop; + + case 0x3: // Remote Next-packet pointer + return ne2000->rempkt_ptr; + + case 0x4: // TPSR + return ne2000->tx_page_start; + + case 0x5: // Local Next-packet pointer + return ne2000->localpkt_ptr; + + case 0x6: // Address counter (upper) + return ne2000->address_cnt >> 8; + + case 0x7: // Address counter (lower) + return ne2000->address_cnt & 0xff; + + case 0x8: // Reserved + case 0x9: + case 0xa: + case 0xb: +#ifdef NE2000_DEBUG + pclog("reserved read - page 2, 0x%02x\n", address); +#endif + 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)); + + case 0xd: // TCR + return ((ne2000->TCR.coll_prio << 4) | + (ne2000->TCR.ext_stoptx << 3) | + ((ne2000->TCR.loop_cntl & 0x3) << 1) | + (ne2000->TCR.crc_disable)); + + 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)); + + 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; + + case 0x03: + if (ne2000->type != NE2000_RTL8029AS) + fatal("ne2000 unknown value of pgsel in read - %d\n", ne2000->CR.pgsel); +#ifdef NE2000_DEBUG + pclog("page 3 read from port %04x\n", address); +#endif + switch (address) + { + case 0x1: /*9346CR*/ + return ne2000->_9346cr; + + case 0x3: /*CONFIG0*/ + return 0x00; /*Cable not BNC*/ + + case 0x5: /*CONFIG2*/ + return ne2000->config2 & 0xe0; /*No boot ROM*/ + + case 0x6: /*CONFIG3*/ + return ne2000->config3 & 0x46; + + case 0xe: /*8029ASID0*/ + return 0x29; + + case 0xf: /*8029ASID1*/ + return 0x08; + } + + pclog("reserved read - page 3, 0x%02x\n", address); + break; + } + } + + 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(uint16_t address, uint8_t value, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; +#ifdef NE2000_DEBUG + pclog("write address %x, val=%x\n", address, value); +#endif + 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) + { +#ifdef NE2000_DEBUG + pclog("wrote 0x%02x to CR\n", value); +#endif + // Validate remote-DMA + if ((value & 0x38) == 0x00) + { +#ifdef NE2000_DEBUG + pclog("CR write - invalid rDMA value 0\n"); +#endif + 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]); +#ifdef NE2000_DEBUG + pclog("Sending buffer #x%x length %d\n", + ne2000->remote_start, + ne2000->remote_bytes); +#endif + } + + // Check for start-tx + if ((value & 0x04) && ne2000->TCR.loop_cntl) + { + // loopback mode + if (ne2000->TCR.loop_cntl != 1) + { +#ifdef NE2000_DEBUG + pclog("Loop mode %d not supported.\n", ne2000->TCR.loop_cntl); +#endif + } + 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"); + ne2000_raise_irq(ne2000); + } + ne2000->ISR.pkt_tx = 1; + } + } + else if (value & 0x04) + { + // start-tx and no loopback +#ifdef NE2000_DEBUG + 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"); +#endif + // 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); +#ifdef NE2000_DEBUG + pclog("ne2000 slirp sending packet\n"); +#endif + } +#ifdef _WIN32 + if(net_is_pcap && net_pcap!=NULL) + { + _pcap_sendpacket(net_pcap, &ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); +#ifdef NE2000_DEBUG + pclog("ne2000 pcap sending packet\n"); +#endif + } +#endif + 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) + { + ne2000_raise_irq(ne2000); + //DEV_pic_raise_irq(ne2000->base_irq); + } + } + } + else + { + switch (ne2000->CR.pgsel) + { + case 0x00: +#ifdef NE2000_DEBUG + pclog("page 0 write to port %04x\n", address); +#endif + // 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) + ne2000_lower_irq(ne2000); + //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 +#ifdef NE2000_DEBUG + if (value & 0xc0) + pclog("RCR write, reserved bits set\n"); +#endif + // 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... +#ifdef NE2000_DEBUG + if (value & 0x20) + pclog("RCR write, monitor bit set!\n"); +#endif + break; + + case 0xd: // TCR + // Check reserved bits +#ifdef NE2000_DEBUG + if (value & 0xe0) + pclog("TCR write, reserved bits set\n"); +#endif + // Test loop mode (not supported) + if (value & 0x06) + { + ne2000->TCR.loop_cntl = (value & 0x6) >> 1; +#ifdef NE2000_DEBUG + pclog("TCR write, loop mode %d not supported\n", ne2000->TCR.loop_cntl); +#endif + } + else + ne2000->TCR.loop_cntl = 0; + + // Inhibit-CRC not supported. + if (value & 0x01) + { + //fatal("ne2000 TCR write, inhibit-CRC not supported\n"); +#ifdef NE2000_DEBUG + pclog("ne2000 TCR write, inhibit-CRC not supported\n"); +#endif + return; + } + + // Auto-transmit disable very suspicious + if (value & 0x08) + { + //fatal("ne2000 TCR write, auto transmit disable not supported\n"); +#ifdef NE2000_DEBUG + pclog("ne2000 TCR write, auto transmit disable not supported\n"); +#endif + } + + // 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 +#ifdef NE2000_DEBUG + 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"); +#endif + // 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 +#ifdef NE2000_DEBUG + if (value & 0x80) + pclog("IMR write, reserved bit set\n"); +#endif + // 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); + 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) + ne2000_raise_irq(ne2000); + else + ne2000_lower_irq(ne2000); + break; + } + break; + + case 0x01: +#ifdef NE2000_DEBUG + pclog("page 1 w offset %04x\n", address); +#endif + 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: +#ifdef NE2000_DEBUG + if (address != 0) + pclog("page 2 write ?\n"); +#endif + 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. +#ifdef NE2000_DEBUG + pclog("ne2000 page 2 write to reserved offset 4\n"); +#endif + 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); +#ifdef NE2000_DEBUG + pclog("ne2000 page 2 write to reserved offset %0x\n", address); +#endif + default: + break; + } + break; + + case 0x03: + if (ne2000->type != NE2000_RTL8029AS) + { + pclog("ne2000 unknown value of pgsel in write - %d\n", ne2000->CR.pgsel); + break; + } +#ifdef NE2000_DEBUG + pclog("page 3 write to port %04x\n", address); +#endif + switch (address) + { + case 0x1: /*9346CR*/ + ne2000->_9346cr = value & 0xfe; + break; + + case 0x5: /*CONFIG2*/ + ne2000->config2 = value & 0xe0; + break; + + case 0x6: /*CONFIG3*/ + ne2000->config3 = value & 0x46; + break; + + case 0x9: /*HLTCLK*/ + break; + + default: + pclog("reserved write - page 3, 0x%02x\n", address); + break; + } + 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 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}; + +#ifdef NE2000_DEBUG + if(io_len != 60) + pclog("rx_frame with length %d\n", io_len); +#endif + //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); + + // 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 + ) + { +#ifdef NE2000_DEBUG + pclog("no space\n"); +#endif + return; + } + + if ((io_len < 40/*60*/) && !ne2000->RCR.runts_ok) + { +#ifdef NE2000_DEBUG + pclog("rejected small packet, length %d\n", io_len); +#endif + 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; + } +#ifdef NE2000_DEBUG + 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]); +#endif + 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"); + ne2000_raise_irq(ne2000); + //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; + +#ifdef NE2000_DEBUG + pclog("tx_timer\n"); +#endif + 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"); + ne2000_raise_irq(ne2000); + //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_pci_add(ne2000_t *ne2000) +{ + io_sethandler(ne2000->base_addr, 0x0010, ne2000_read, NULL, NULL, ne2000_write, NULL, NULL, ne2000); + io_sethandler(ne2000->base_addr+0x10, 0x000f, ne2000_asic_read_b, ne2000_asic_read_w, NULL, ne2000_asic_write_b, ne2000_asic_write_w, NULL, ne2000); + io_sethandler(ne2000->base_addr+0x1f, 0x0001, ne2000_reset_read, NULL, NULL, ne2000_reset_write, NULL, NULL, ne2000); +} + +static void ne2000_pci_remove(ne2000_t *ne2000) +{ + io_removehandler(ne2000->base_addr, 0x0010, ne2000_read, NULL, NULL, ne2000_write, NULL, NULL, ne2000); + io_removehandler(ne2000->base_addr+0x10, 0x000f, ne2000_asic_read_b, ne2000_asic_read_w, NULL, ne2000_asic_write_b, ne2000_asic_write_w, NULL, ne2000); + io_removehandler(ne2000->base_addr+0x1f, 0x0001, ne2000_reset_read, NULL, NULL, ne2000_reset_write, NULL, NULL, ne2000); +} + +static uint8_t rtl8029_pci_read(int func, int addr, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + if (func) + return 0; + +// pclog("RTL8029 PCI read %08X PC=%08x\n", addr, cpu_state.pc); + + switch (addr) + { + case 0x00: return 0xec; /*Realtek*/ + case 0x01: return 0x10; + + case 0x02: return 0x29; /*RTL8029AS*/ + case 0x03: return 0x80; + + case 0x04: return ne2000->pci_command; + + case 0x07: return 0x02; + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + case 0x0a: return 0; /*Ethernet controller*/ + case 0x0b: return 0x02; /*Network controller*/ + + case 0x10: return 0x01 | (ne2000->base_addr & 0xe0); /*memBaseAddr*/ + case 0x11: return ne2000->base_addr >> 8; + case 0x12: return ne2000->base_addr >> 16; + case 0x13: return ne2000->base_addr >> 24; + + case 0x2c: return 0xec; /*Subsystem vendor - Realtek*/ + case 0x2d: return 0x10; + + case 0x2e: return 0x29; /*Subsystem ID - RTL8029AS*/ + case 0x2f: return 0x80; + + case 0x3c: return ne2000->int_line; + case 0x3d: return 0x01; /*INTA*/ + } + return 0; +} + +static void rtl8029_pci_write(int func, int addr, uint8_t val, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + if (func) + return; + +// pclog("RTL8029 PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc); + + switch (addr) + { + case 0x04: + if (ne2000->pci_command & PCI_COMMAND_IO) + ne2000_pci_remove(ne2000); + ne2000->pci_command = val & 3; + if (ne2000->pci_command & PCI_COMMAND_IO) + ne2000_pci_add(ne2000); + break; + + case 0x10: + if (ne2000->pci_command & PCI_COMMAND_IO) + ne2000_pci_remove(ne2000); + ne2000->base_addr = (ne2000->base_addr & 0xffffff00) | (val & 0xe0); + if (ne2000->pci_command & PCI_COMMAND_IO) + ne2000_pci_add(ne2000); + break; + case 0x11: + if (ne2000->pci_command & PCI_COMMAND_IO) + ne2000_pci_remove(ne2000); + ne2000->base_addr = (ne2000->base_addr & 0xffff00e0) | (val << 8); + if (ne2000->pci_command & PCI_COMMAND_IO) + ne2000_pci_add(ne2000); + break; + case 0x12: + ne2000->base_addr = (ne2000->base_addr & 0xff00ffe0) | (val << 16); + break; + case 0x13: + ne2000->base_addr = (ne2000->base_addr & 0x00ffffe0) | (val << 24); + break; + + case 0x3c: + ne2000->int_line = val; + break; + } +} + + +static void ne2000_poller(void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + struct queuepacket *qp; + const unsigned char *data; +#ifdef _WIN32 + struct pcap_pkthdr h; +#endif + 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); +#ifdef NE2000_DEBUG + pclog("ne2000 inQ:%d got a %dbyte packet @%d\n",QueuePeek(slirpq),qp->len,qp); +#endif + free(qp); + } + fizz++; + if(fizz > 1200) + { + fizz=0; + slirp_tic(); + } + }//end slirp +#ifdef _WIN32 + if (net_is_pcap && net_pcap!=NULL) + { + data = _pcap_next(net_pcap,&h); + if (data == 0x0) + return; + 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; + +#ifdef NE2000_DEBUG + pclog("ne2000 pcap received a frame %d bytes\n",h.caplen); +#endif + ne2000_rx_frame(ne2000,data,h.caplen); + } + } +#endif +} + + +void *ne2000_common_init() +{ + struct in_addr myaddr; + int rc; + unsigned int macint[6]; + char *macstring; + + ne2000_t *ne2000 = malloc(sizeof(ne2000_t)); + memset(ne2000, 0, sizeof(ne2000_t)); + + macstring = config_get_string(CFG_MACHINE, NULL, "macaddr", ""); + + if (sscanf(macstring, "%02x:%02x:%02x:%02x:%02x:%02x", + &macint[0],&macint[1],&macint[2],&macint[3],&macint[4],&macint[5]) != 6) + { + maclocal[0] = 0xac; + maclocal[1] = 0xde; + maclocal[2] = 0x48; + maclocal[3] = 0x88; + maclocal[4] = 0xbb; + maclocal[5] = 0xaa; + pclog("ne2000: Using default MAC address (AC:DE:48:88:BB:AA)\n"); + } + else + { + maclocal[0] = macint[0]; + maclocal[1] = macint[1]; + maclocal[2] = macint[2]; + maclocal[3] = macint[3]; + maclocal[4] = macint[4]; + maclocal[5] = macint[5]; + pclog("ne2000: Using MAC address from pcem.cfg: %s\n", macstring); + } + + //net_type + //0 pcap + //1 slirp + // +#ifdef _WIN32 + net_is_slirp = (config_get_int(CFG_GLOBAL, NULL, "net_type", NET_SLIRP) == NET_SLIRP) ? 1 : 0; + pclog("ne2000 pcap device %s\n",config_get_string(CFG_GLOBAL, NULL,"pcap_device","nothing")); + + //Check that we have a string setup, otherwise turn pcap off + if (!strcmp("nothing",config_get_string(CFG_GLOBAL, NULL,"pcap_device","nothing"))) + net_is_pcap = 0; + else if (net_is_slirp == 0) + net_is_pcap = 1; +#else + net_is_slirp = 1; + net_is_pcap = 0; +#endif + + memcpy(ne2000->physaddr, maclocal, 6); + + ne2000_reset(BX_RESET_HARDWARE, ne2000); + vlan_handler(ne2000_poller, ne2000); + + pclog("ne2000 init\tslirp is %d net_is_pcap is %d\n",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; + } + } +#ifdef _WIN32 + 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; + } + _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(config_get_string(CFG_GLOBAL, NULL,"pcap_device","nothing"),1518,1,15,errbuf))==0) + { + pclog("ne2000 pcap_open_live error on %s!\n",config_get_string(CFG_GLOBAL, 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) + { + 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; + } + } + 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) + { + 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"); + } + else + { + pclog("...!\n"); + } + } + pclog("ne2000 Using filter\t[%s]\n",filter_exp); + } + 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 +#endif + pclog("ne2000 is_slirp %d is_pcap %d\n",net_is_slirp,net_is_pcap); + + return ne2000; +} + +void *ne2000_init() +{ + ne2000_t *ne2000 = ne2000_common_init(); + uint16_t addr; + + ne2000->type = NE2000_NE2000; + + ne2000_setirq(ne2000, device_get_config_int("irq")); + + addr = device_get_config_int("addr"); + 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); + + return ne2000; +} + +void *rtl8029_init() +{ + ne2000_t *ne2000 = ne2000_common_init(); + + ne2000->is_pci = 1; + ne2000->type = NE2000_RTL8029AS; + + ne2000->card = pci_add(rtl8029_pci_read, rtl8029_pci_write, ne2000); + + ne2000_setirq(ne2000, NE2000_PCI_IRQ); + + return ne2000; +} + +void ne2000_close(void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + free(ne2000); + if(net_is_slirp) + { + QueueDestroy(slirpq); + slirp_exit(0); + net_slirp_inited=0; + pclog("ne2000 exiting slirp\n"); + } +#ifdef _WIN32 + if(net_is_pcap && net_pcap!=NULL) + { + _pcap_close(net_pcap); + FreeLibrary(net_hLib); + pclog("ne2000 closing pcap\n"); + } +#endif + 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 = "IRQ 12", + .value = 12 + }, + { + .description = "" + } + }, + .default_int = 10 + }, + { + .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", + DEVICE_PCI, + rtl8029_init, + ne2000_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + + +//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); +#ifdef NE2000_DEBUG + pclog("ne2000 slirp_output %d @%d\n",pkt_len,p); +#endif +} + +// 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 0000000..e413877 --- /dev/null +++ b/src/ne2000.h @@ -0,0 +1,2 @@ +extern device_t ne2000_device; +extern device_t rtl8029as_device; diff --git a/src/nethandler.c b/src/nethandler.c new file mode 100644 index 0000000..f06ef46 --- /dev/null +++ b/src/nethandler.c @@ -0,0 +1,120 @@ +#ifdef _WIN32 +#include +#include +#endif +#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]; + char internal_name[24]; + device_t *device; +} NETWORK_CARD; + +static NETWORK_CARD network_cards[] = +{ + {"None", "", NULL}, + {"Novell NE2000", "ne2000", &ne2000_device}, + {"Realtek RTL8029AS", "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; +} + +char *network_card_get_internal_name(int card) +{ + return network_cards[card].internal_name; +} + +int network_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(network_cards[c].name)) + { + if (!strcmp(network_cards[c].internal_name, s)) + return c; + c++; + } + + return 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 pc_timer_t vlan_poller_timer; + +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; + + timer_advance_u64(&vlan_poller_timer, (uint64_t)((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_timer, vlan_poller, NULL, 1); + + vlan_handlers_num = 0; +} diff --git a/src/nethandler.h b/src/nethandler.h new file mode 100644 index 0000000..3dde87c --- /dev/null +++ b/src/nethandler.h @@ -0,0 +1,26 @@ +#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(); + +char *network_card_get_internal_name(int card); +int network_card_get_from_internal_name(char *s); + +void initpcap(); +void closepcap(); + +void vlan_reset(); + +enum +{ + NET_SLIRP = 0, + NET_PCAP = 1 +}; diff --git a/src/nvr.c b/src/nvr.c index 419e7b9..edbd35b 100644 --- a/src/nvr.c +++ b/src/nvr.c @@ -1,10 +1,19 @@ #include +#include #include "ibm.h" +#include "device.h" #include "io.h" #include "nvr.h" +#include "nvr_tc8521.h" #include "pic.h" #include "timer.h" #include "rtc.h" +#include "paths.h" +#include "config.h" +#include "model.h" +#include "nmi.h" +#include "t1000.h" +#include "x86.h" int oldromset; int nvrmask=63; @@ -13,42 +22,85 @@ int nvraddr; int nvr_dosave = 0; -static int nvr_onesec_time = 0, nvr_onesec_cnt = 0; +typedef struct nvr_t +{ + pc_timer_t rtc_timer; + pc_timer_t onesec_timer; + pc_timer_t update_end_timer; -static int rtctime; + int onesec_cnt; +} nvr_t; + +FILE *nvrfopen(char *fn, char *mode) +{ + char s[512]; + FILE *f; + + strcpy(s, nvr_path); + put_backslash(s); + strcat(s, config_name); + strcat(s, "."); + strcat(s, fn); + pclog("NVR try opening %s\n", s); + f = fopen(s, mode); + if (f) + return f; + + if (mode[0] == 'r') + { + snprintf(s, 512, "%s%s", nvr_default_path, fn); + return fopen(s, mode); + } + else + { + pclog("Failed to open file '%s' for write\n", s); + return NULL; + } +} void getnvrtime() { time_get(nvrram); } -void nvr_recalc() +static void nvr_speed_changed(void *p) { - int c; - int newrtctime; - c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1); - newrtctime=(int)(RTCCONST * c * (1 << TIMER_SHIFT)); - if (rtctime>newrtctime) rtctime=newrtctime; -} + nvr_t *nvr = (nvr_t *)p; -void nvr_rtc(void *p) -{ - int c; if (!(nvrram[RTC_REGA] & RTC_RS)) { - rtctime=0x7fffffff; + timer_disable(&nvr->rtc_timer); return; } - c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1); - rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); -// pclog("RTCtime now %f\n",rtctime); - nvrram[RTC_REGC] |= RTC_PF; - if (nvrram[RTC_REGB] & RTC_PIE) + else { - nvrram[RTC_REGC] |= RTC_IRQF; - if (AMSTRAD) picint(2); - else picint(0x100); -// pclog("RTC int\n"); + int c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1); + timer_set_delay_u64(&nvr->rtc_timer, (uint64_t)(RTCCONST * c)); + } +} + +static void nvr_rtc(void *p) +{ + nvr_t *nvr = (nvr_t *)p; + + if (!(nvrram[RTC_REGA] & RTC_RS)) + { + timer_disable(&nvr->rtc_timer); + return; + } + else + { + int c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 1); + timer_advance_u64(&nvr->rtc_timer, (uint64_t)(RTCCONST * c)); +// pclog("RTCtime now %f\n",rtctime); + nvrram[RTC_REGC] |= RTC_PF; + if (nvrram[RTC_REGB] & RTC_PIE) + { + nvrram[RTC_REGC] |= RTC_IRQF; + if (AMSTRAD) picint(2); + else picint(0x100); +// pclog("RTC int\n"); + } } } @@ -61,10 +113,11 @@ int nvr_check_alarm(int nvraddr) return (nvrram[nvraddr + 1] == nvrram[nvraddr] || (nvrram[nvraddr + 1] & ALARM_DONTCARE) == ALARM_DONTCARE); } -int nvr_update_end_count = 0; -void nvr_update_end(void *p) +static void nvr_update_end(void *p) { +// nvr_t *nvr = (nvr_t *)p; + if (!(nvrram[RTC_REGB] & RTC_SET)) { getnvrtime(); @@ -93,30 +146,33 @@ void nvr_update_end(void *p) } // pclog("RTC onesec\n"); - - nvr_update_end_count = 0; } -void nvr_onesec(void *p) +static void nvr_onesec(void *p) { - nvr_onesec_cnt++; - if (nvr_onesec_cnt >= 100) + nvr_t *nvr = (nvr_t *)p; + + nvr->onesec_cnt++; + if (nvr->onesec_cnt >= 100) { if (!(nvrram[RTC_REGB] & RTC_SET)) { nvr_update_status = RTC_UIP; rtc_tick(); - nvr_update_end_count = (int)((244.0 + 1984.0) * TIMER_USEC); + timer_set_delay_u64(&nvr->update_end_timer, (uint64_t)((244.0 + 1984.0) * TIMER_USEC)); } - nvr_onesec_cnt = 0; + nvr->onesec_cnt = 0; } - nvr_onesec_time += (int)(10000 * TIMER_USEC); + timer_advance_u64(&nvr->onesec_timer, (uint64_t)(10000 * TIMER_USEC)); } -void writenvr(uint16_t addr, uint8_t val, void *priv) +static void writenvr(uint16_t addr, uint8_t val, void *p) { + nvr_t *nvr = (nvr_t *)p; int c, old; + + cycles -= ISA_CYCLES(8); // printf("Write NVR %03X %02X %02X %04X:%04X %i\n",addr,nvraddr,val,cs>>4,pc,ins); if (addr&1) { @@ -135,10 +191,10 @@ void writenvr(uint16_t addr, uint8_t val, void *priv) if (val & RTC_RS) { c = 1 << ((val & RTC_RS) - 1); - rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); + timer_set_delay_u64(&nvr->rtc_timer, (uint64_t)(RTCCONST * c)); } else - rtctime = 0x7fffffff; + timer_disable(&nvr->rtc_timer); } else { @@ -164,13 +220,32 @@ void writenvr(uint16_t addr, uint8_t val, void *priv) } } } - else nvraddr=val&nvrmask; + else + { + nvraddr=val&nvrmask; + /*PS/2 BIOSes will disable NMIs and expect the watchdog timer to still be able + to fire them. I suspect the watchdog is exempt from NMI masking. Currently NMIs + are always enabled for PS/2 machines - this would mean that other peripherals + could fire NMIs regardless of the mask state, but as there aren't any emulated + MCA peripherals that do this it's currently a moot point.*/ + + /* Also don't update the NMI mask on Amstrad PCs - actually + * ought not to do it for any XT because their NMI mask + * register is at 0xA0. But particularly important on the + * PC200 and PPC because their video subsystem issues NMIs */ + if (!(models[model].flags & (MODEL_MCA | MODEL_AMSTRAD))) + { + nmi_mask = ~val & 0x80; + } + } } -uint8_t readnvr(uint16_t addr, void *priv) +uint8_t readnvr(uint16_t addr, void *p) { +// nvr_t *nvr = (nvr_t *)p; uint8_t temp; // printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc); + cycles -= ISA_CYCLES(8); if (addr&1) { if (nvraddr == RTC_REGA) @@ -195,43 +270,92 @@ uint8_t readnvr(uint16_t addr, void *priv) 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_IBMPS2_M30_286: f = romfopen("nvr/ibmps2_m30_286.nvr", "rb"); /*nvrmask = 127; */break; - case ROM_IBMPS2_M50: f = romfopen("nvr/ibmps2_m50.nvr", "rb"); break; - case ROM_IBMPS2_M55SX: f = romfopen("nvr/ibmps2_m55sx.nvr", "rb"); break; - case ROM_IBMPS2_M80: f = romfopen("nvr/ibmps2_m80.nvr", "rb"); 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_AMI386SX: 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_MR386DX_OPTI495: f = romfopen("nvr/mr386dx_opti495.nvr", "rb"); nvrmask = 127; break; - case ROM_AMI386DX_OPTI495: f = romfopen("nvr/ami386dx_opti495.nvr", "rb"); nvrmask = 127; break; + case ROM_PC1512: f = nvrfopen("pc1512.nvr", "rb"); break; + case ROM_PC1640: f = nvrfopen("pc1640.nvr", "rb"); break; + case ROM_PC200: f = nvrfopen("pc200.nvr", "rb"); break; + case ROM_PC2086: f = nvrfopen("pc2086.nvr", "rb"); break; + case ROM_PC3086: f = nvrfopen("pc3086.nvr", "rb"); break; + case ROM_PC5086: f = nvrfopen("pc5086.nvr", "rb"); break; + case ROM_PPC512: f = nvrfopen("ppc512.nvr", "rb"); break; + case ROM_IBMAT: f = nvrfopen("at.nvr", "rb"); break; + case ROM_IBMXT286: f = nvrfopen("ibmxt286.nvr", "rb"); break; + case ROM_IBMPS1_2011: f = nvrfopen("ibmps1_2011.nvr", "rb"); /*nvrmask = 127; */break; + case ROM_IBMPS1_2121: f = nvrfopen("ibmps1_2121.nvr", "rb"); nvrmask = 127; break; + case ROM_IBMPS2_M30_286: f = nvrfopen("ibmps2_m30_286.nvr", "rb"); /*nvrmask = 127; */break; + case ROM_IBMPS2_M50: f = nvrfopen("ibmps2_m50.nvr", "rb"); break; + case ROM_IBMPS2_M55SX: f = nvrfopen("ibmps2_m55sx.nvr", "rb"); break; + case ROM_IBMPS2_M80: f = nvrfopen("ibmps2_m80.nvr", "rb"); break; + case ROM_CMDPC30: f = nvrfopen("cmdpc30.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI286: f = nvrfopen("ami286.nvr", "rb"); nvrmask = 127; break; + case ROM_TG286M: f = nvrfopen("tg286m.nvr", "rb"); nvrmask = 127; break; + case ROM_AWARD286: f = nvrfopen("award286.nvr", "rb"); nvrmask = 127; break; + case ROM_GDC212M: f = nvrfopen("gdc212m.nvr", "rb"); nvrmask = 127; break; + case ROM_HYUNDAI_SUPER286TR: f = nvrfopen("super286tr.nvr", "rb"); nvrmask = 127; break; + case ROM_GW286CT: f = nvrfopen("gw286ct.nvr", "rb"); nvrmask = 127; break; + case ROM_SPC4200P: f = nvrfopen("spc4200p.nvr", "rb"); nvrmask = 127; break; + case ROM_SPC4216P: f = nvrfopen("spc4216p.nvr", "rb"); nvrmask = 127; break; + case ROM_SPC4620P: f = nvrfopen("spc4620p.nvr", "rb"); nvrmask = 127; break; + case ROM_SPC6000A: f = nvrfopen("spc6000a.nvr", "rb"); nvrmask = 127; break; + case ROM_SPC6033P: f = nvrfopen("spc6033p.nvr", "rb"); nvrmask = 127; break; + case ROM_DELL200: f = nvrfopen("dell200.nvr", "rb"); nvrmask = 127; break; + case ROM_IBMAT386: f = nvrfopen("at386.nvr", "rb"); nvrmask = 127; break; + case ROM_DESKPRO_386: f = nvrfopen("deskpro386.nvr", "rb"); break; + case ROM_ACER386: f = nvrfopen("acer386.nvr", "rb"); nvrmask = 127; break; + case ROM_KMXC02: f = nvrfopen("kmxc02.nvr", "rb"); nvrmask = 127; break; + case ROM_MEGAPC: f = nvrfopen("megapc.nvr", "rb"); nvrmask = 127; break; + case ROM_AMA932J: f = nvrfopen("ama932j.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI386SX: f = nvrfopen("ami386.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI486: f = nvrfopen("ami486.nvr", "rb"); nvrmask = 127; break; + case ROM_WIN486: f = nvrfopen("win486.nvr", "rb"); nvrmask = 127; break; + case ROM_PCI486: f = nvrfopen("hot-433.nvr", "rb"); nvrmask = 127; break; + case ROM_SIS496: f = nvrfopen("sis496.nvr", "rb"); nvrmask = 127; break; + case ROM_P55VA: f = nvrfopen("p55va.nvr", "rb"); nvrmask = 127; break; + case ROM_P55TVP4: f = nvrfopen("p55tvp4.nvr", "rb"); nvrmask = 127; break; + case ROM_430VX: f = nvrfopen("430vx.nvr", "rb"); nvrmask = 127; break; + case ROM_REVENGE: f = nvrfopen("revenge.nvr", "rb"); nvrmask = 127; break; + case ROM_ENDEAVOR: f = nvrfopen("endeavor.nvr", "rb"); nvrmask = 127; break; + case ROM_P55T2P4: f = nvrfopen("p55t2p4.nvr", "rb"); nvrmask = 127; break; + case ROM_PX386: f = nvrfopen("px386.nvr", "rb"); nvrmask = 127; break; + case ROM_DTK386: f = nvrfopen("dtk386.nvr", "rb"); nvrmask = 127; break; + case ROM_MR386DX_OPTI495: f = nvrfopen("mr386dx_opti495.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI386DX_OPTI495: f = nvrfopen("ami386dx_opti495.nvr", "rb"); nvrmask = 127; break; + case ROM_EPSON_PCAX: f = nvrfopen("epson_pcax.nvr", "rb"); nvrmask = 127; break; + case ROM_EPSON_PCAX2E: f = nvrfopen("epson_pcax2e.nvr", "rb"); nvrmask = 127; break; + case ROM_PB_L300SX: f = nvrfopen("pb_l300sx.nvr", "rb"); nvrmask = 127; break; + case ROM_EPSON_PCAX3: f = nvrfopen("epson_pcax3.nvr", "rb"); nvrmask = 127; break; + case ROM_COMPAQ_PII: f = nvrfopen("compaq_pii.nvr", "rb"); break; + case ROM_T3100E: f = nvrfopen("t3100e.nvr", "rb"); break; + case ROM_T1000: tc8521_loadnvr(); + t1000_configsys_loadnvr(); + t1000_emsboard_loadnvr(); + return; + case ROM_T1200: tc8521_loadnvr(); + t1200_state_loadnvr(); + t1000_emsboard_loadnvr(); + return; + case ROM_ELX_PC425X: f = nvrfopen("elx_pc425.nvr", "rb"); nvrmask = 127; break; + case ROM_PB570: f = nvrfopen("pb570.nvr", "rb"); nvrmask = 127; break; + case ROM_ZAPPA: f = nvrfopen("zappa.nvr", "rb"); nvrmask = 127; break; + case ROM_ITAUTEC_INFOWAYM: f = nvrfopen("infowaym.nvr", "rb"); nvrmask = 127; break; + case ROM_PB520R: f = nvrfopen("pb520r.nvr", "rb"); nvrmask = 127; break; + case ROM_XI8088: f = nvrfopen("xi8088.nvr", "rb"); nvrmask = 127; break; + case ROM_IBMPS2_M70_TYPE3: f = nvrfopen("ibmps2_m70_type3.nvr","rb"); break; + case ROM_IBMPS2_M70_TYPE4: f = nvrfopen("ibmps2_m70_type4.nvr","rb"); break; + case ROM_TULIP_TC7: f = nvrfopen("tulip_tc7.nvr", "rb"); break; + case ROM_PB410A: f = nvrfopen("pb410a.nvr", "rb"); nvrmask = 127; break; + case ROM_BULL_MICRAL_45: f = nvrfopen("bull_micral_45.nvr", "rb"); break; + case ROM_FIC_VA503P: f = nvrfopen("fic_va503p.nvr", "rb"); nvrmask = 127; break; + case ROM_CBM_SL386SX25: f = nvrfopen("cbm_sl386sx25.nvr", "rb"); nvrmask = 127; break; + case ROM_IBMPS1_2133_451: f = nvrfopen("ibmps1_2133.nvr", "rb"); nvrmask = 127; break; + case ROM_ECS_386_32: f = nvrfopen("ecs_386_32.nvr", "rb"); nvrmask = 127; break; + case ROM_VS440FX: f = nvrfopen("vs440fx.nvr", "rb"); nvrmask = 127; break; + case ROM_GA686BX: f = nvrfopen("ga686bx.nvr", "rb"); nvrmask = 127; break; + default: return; } if (!f) @@ -255,57 +379,128 @@ void loadnvr() fclose(f); nvrram[RTC_REGA] = 6; nvrram[RTC_REGB] = RTC_2412; - c = 1 << ((nvrram[RTC_REGA] & RTC_RS) - 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_IBMPS2_M30_286: f = romfopen("nvr/ibmps2_m30_286.nvr", "wb"); break; - case ROM_IBMPS2_M50: f = romfopen("nvr/ibmps2_m50.nvr", "wb"); break; - case ROM_IBMPS2_M55SX: f = romfopen("nvr/ibmps2_m55sx.nvr", "wb"); break; - case ROM_IBMPS2_M80: f = romfopen("nvr/ibmps2_m80.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_AMI386SX: 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_MR386DX_OPTI495: f = romfopen("nvr/mr386dx_opti495.nvr", "wb"); break; - case ROM_AMI386DX_OPTI495: f = romfopen("nvr/ami386dx_opti495.nvr", "wb"); break; + case ROM_PC1512: f = nvrfopen("pc1512.nvr", "wb"); break; + case ROM_PC1640: f = nvrfopen("pc1640.nvr", "wb"); break; + case ROM_PC200: f = nvrfopen("pc200.nvr", "wb"); break; + case ROM_PC2086: f = nvrfopen("pc2086.nvr", "wb"); break; + case ROM_PC3086: f = nvrfopen("pc3086.nvr", "wb"); break; + case ROM_PC5086: f = nvrfopen("pc5086.nvr", "wb"); break; + case ROM_PPC512: f = nvrfopen("ppc512.nvr", "wb"); break; + case ROM_IBMAT: f = nvrfopen("at.nvr", "wb"); break; + case ROM_IBMXT286: f = nvrfopen("ibmxt286.nvr", "wb"); break; + case ROM_IBMPS1_2011: f = nvrfopen("ibmps1_2011.nvr", "wb"); break; + case ROM_IBMPS1_2121: f = nvrfopen("ibmps1_2121.nvr", "wb"); break; + case ROM_IBMPS2_M30_286: f = nvrfopen("ibmps2_m30_286.nvr", "wb"); break; + case ROM_IBMPS2_M50: f = nvrfopen("ibmps2_m50.nvr", "wb"); break; + case ROM_IBMPS2_M55SX: f = nvrfopen("ibmps2_m55sx.nvr", "wb"); break; + case ROM_IBMPS2_M80: f = nvrfopen("ibmps2_m80.nvr", "wb"); break; + case ROM_CMDPC30: f = nvrfopen("cmdpc30.nvr", "wb"); break; + case ROM_AMI286: f = nvrfopen("ami286.nvr", "wb"); break; + case ROM_TG286M: f = nvrfopen("tg286m.nvr", "wb"); break; + case ROM_AWARD286: f = nvrfopen("award286.nvr", "wb"); break; + case ROM_GDC212M: f = nvrfopen("gdc212m.nvr", "wb"); break; + case ROM_HYUNDAI_SUPER286TR: f = nvrfopen("super286tr.nvr", "wb"); break; + case ROM_GW286CT: f = nvrfopen("gw286ct.nvr", "wb"); break; + case ROM_SPC4200P: f = nvrfopen("spc4200p.nvr", "wb"); break; + case ROM_SPC4216P: f = nvrfopen("spc4216p.nvr", "wb"); break; + case ROM_SPC4620P: f = nvrfopen("spc4620p.nvr", "wb"); break; + case ROM_SPC6000A: f = nvrfopen("spc6000a.nvr", "wb"); break; + case ROM_SPC6033P: f = nvrfopen("spc6033p.nvr", "wb"); break; + case ROM_DELL200: f = nvrfopen("dell200.nvr", "wb"); break; + case ROM_IBMAT386: f = nvrfopen("at386.nvr", "wb"); break; + case ROM_DESKPRO_386: f = nvrfopen("deskpro386.nvr", "wb"); break; + case ROM_ACER386: f = nvrfopen("acer386.nvr", "wb"); break; + case ROM_KMXC02: f = nvrfopen("kmxc02.nvr", "wb"); break; + case ROM_MEGAPC: f = nvrfopen("megapc.nvr", "wb"); break; + case ROM_AMA932J: f = nvrfopen("ama932j.nvr", "wb"); break; + case ROM_AMI386SX: f = nvrfopen("ami386.nvr", "wb"); break; + case ROM_AMI486: f = nvrfopen("ami486.nvr", "wb"); break; + case ROM_WIN486: f = nvrfopen("win486.nvr", "wb"); break; + case ROM_PCI486: f = nvrfopen("hot-433.nvr", "wb"); break; + case ROM_SIS496: f = nvrfopen("sis496.nvr", "wb"); break; + case ROM_P55VA: f = nvrfopen("p55va.nvr", "wb"); break; + case ROM_P55TVP4: f = nvrfopen("p55tvp4.nvr", "wb"); break; + case ROM_430VX: f = nvrfopen("430vx.nvr", "wb"); break; + case ROM_REVENGE: f = nvrfopen("revenge.nvr", "wb"); break; + case ROM_ENDEAVOR: f = nvrfopen("endeavor.nvr", "wb"); break; + case ROM_P55T2P4: f = nvrfopen("p55t2p4.nvr", "wb"); break; + case ROM_PX386: f = nvrfopen("px386.nvr", "wb"); break; + case ROM_DTK386: f = nvrfopen("dtk386.nvr", "wb"); break; + case ROM_MR386DX_OPTI495: f = nvrfopen("mr386dx_opti495.nvr", "wb"); break; + case ROM_AMI386DX_OPTI495: f = nvrfopen("ami386dx_opti495.nvr", "wb"); break; + case ROM_EPSON_PCAX: f = nvrfopen("epson_pcax.nvr", "wb"); break; + case ROM_EPSON_PCAX2E: f = nvrfopen("epson_pcax2e.nvr", "wb"); break; + case ROM_EPSON_PCAX3: f = nvrfopen("epson_pcax3.nvr", "wb"); break; + case ROM_COMPAQ_PII: f = nvrfopen("compaq_pii.nvr", "wb"); break; + case ROM_PB_L300SX: f = nvrfopen("pb_l300sx.nvr", "wb"); break; + case ROM_T3100E: f = nvrfopen("t3100e.nvr", "wb"); break; + case ROM_T1000: tc8521_savenvr(); + t1000_configsys_savenvr(); + t1000_emsboard_savenvr(); + return; + case ROM_T1200: tc8521_savenvr(); + t1200_state_savenvr(); + t1000_emsboard_savenvr(); + return; + case ROM_ELX_PC425X: f = nvrfopen("elx_pc425.nvr", "wb"); break; + case ROM_PB570: f = nvrfopen("pb570.nvr", "wb"); break; + case ROM_ZAPPA: f = nvrfopen("zappa.nvr", "wb"); break; + case ROM_ITAUTEC_INFOWAYM: f = nvrfopen("infowaym.nvr", "wb"); break; + case ROM_PB520R: f = nvrfopen("pb520r.nvr", "wb"); break; + case ROM_XI8088: f = nvrfopen("xi8088.nvr", "wb"); break; + case ROM_IBMPS2_M70_TYPE3: f = nvrfopen("ibmps2_m70_type3.nvr","wb"); break; + case ROM_IBMPS2_M70_TYPE4: f = nvrfopen("ibmps2_m70_type4.nvr","wb"); break; + case ROM_TULIP_TC7: f = nvrfopen("tulip_tc7.nvr", "wb"); break; + case ROM_PB410A: f = nvrfopen("pb410a.nvr", "wb"); break; + case ROM_BULL_MICRAL_45: f = nvrfopen("bull_micral_45.nvr", "wb"); break; + case ROM_FIC_VA503P: f = nvrfopen("fic_va503p.nvr", "wb"); break; + case ROM_CBM_SL386SX25: f = nvrfopen("cbm_sl386sx25.nvr", "wb"); break; + case ROM_IBMPS1_2133_451: f = nvrfopen("ibmps1_2133.nvr", "wb"); break; + case ROM_ECS_386_32: f = nvrfopen("ecs_386_32.nvr", "wb"); break; + case ROM_VS440FX: f = nvrfopen("vs440fx.nvr", "wb"); break; + case ROM_GA686BX: f = nvrfopen("ga686bx.nvr", "wb"); break; + default: return; } fwrite(nvrram,128,1,f); fclose(f); } -void nvr_init() +static 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); - timer_add(nvr_update_end, &nvr_update_end_count, &nvr_update_end_count, NULL); + nvr_t *nvr = (nvr_t *)malloc(sizeof(nvr_t)); + memset(nvr, 0, sizeof(nvr_t)); + io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL, nvr); + timer_add(&nvr->rtc_timer, nvr_rtc, nvr, 1); + timer_add(&nvr->onesec_timer, nvr_onesec, nvr, 1); + timer_add(&nvr->update_end_timer, nvr_update_end, nvr, 0); + + return nvr; } + +static void nvr_close(void *p) +{ + nvr_t *nvr = (nvr_t *)p; + + free(nvr); +} + +device_t nvr_device = +{ + "Motorola MC146818 RTC", + 0, + nvr_init, + nvr_close, + NULL, + nvr_speed_changed, + NULL, + NULL, + NULL +}; diff --git a/src/nvr.h b/src/nvr.h index c04289f..b01d7df 100644 --- a/src/nvr.h +++ b/src/nvr.h @@ -1,4 +1,6 @@ -void nvr_init(); +#include "device.h" + +extern device_t nvr_device; extern int enable_sync; @@ -7,4 +9,8 @@ extern int nvr_dosave; void loadnvr(); void savenvr(); -void nvr_recalc(); +FILE *nvrfopen(char *fn, char *mode); + +extern uint8_t nvrram[128]; +extern int nvrmask; +extern int oldromset; diff --git a/src/nvr_tc8521.c b/src/nvr_tc8521.c new file mode 100644 index 0000000..6396d30 --- /dev/null +++ b/src/nvr_tc8521.c @@ -0,0 +1,101 @@ +#include +#include "ibm.h" +#include "io.h" +#include "nvr.h" +#include "nvr_tc8521.h" +#include "rtc_tc8521.h" +#include "pic.h" +#include "timer.h" +#include "rtc.h" +#include "paths.h" +#include "config.h" +#include "nmi.h" + +static pc_timer_t nvr_onesec_timer; +static int nvr_onesec_cnt = 0; + +static void tc8521_onesec(void *p) +{ + nvr_onesec_cnt++; + if (nvr_onesec_cnt >= 100) + { + tc8521_tick(); + nvr_onesec_cnt = 0; + } + timer_advance_u64(&nvr_onesec_timer, 10000 * TIMER_USEC); +} + +void write_tc8521(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t page = nvrram[0x0D] & 3; + + addr &= 0x0F; + if (addr < 0x0D) addr += 16 * page; + + if (addr >= 0x10 && nvrram[addr] != val) + nvr_dosave = 1; + + nvrram[addr] = val; +} + + +uint8_t read_tc8521(uint16_t addr, void *priv) +{ + uint8_t page = nvrram[0x0D] & 3; + + addr &= 0x0F; + if (addr < 0x0D) addr += 16 * page; + + return nvrram[addr]; +} + + +void tc8521_loadnvr() +{ + FILE *f; + + nvrmask=63; + oldromset=romset; + switch (romset) + { + case ROM_T1000: f = nvrfopen("t1000.nvr", "rb"); break; + case ROM_T1200: f = nvrfopen("t1200.nvr", "rb"); break; + default: return; + } + if (!f) + { + memset(nvrram,0xFF,64); + nvrram[0x0E] = 0; /* Test register */ + if (!enable_sync) + { + memset(nvrram, 0, 16); + } + return; + } + fread(nvrram,64,1,f); + if (enable_sync) + tc8521_internal_sync(nvrram); + else + tc8521_internal_set_nvrram(nvrram); /* Update the internal clock state based on the NVR registers. */ + fclose(f); +} + + +void tc8521_savenvr() +{ + FILE *f; + switch (oldromset) + { + case ROM_T1000: f = nvrfopen("t1000.nvr", "wb"); break; + case ROM_T1200: f = nvrfopen("t1200.nvr", "wb"); break; + default: return; + } + fwrite(nvrram,64,1,f); + fclose(f); +} + +void nvr_tc8521_init() +{ + io_sethandler(0x2C0, 0x10, read_tc8521, NULL, NULL, write_tc8521, NULL, NULL, NULL); + timer_add(&nvr_onesec_timer, tc8521_onesec, NULL, 1); +} diff --git a/src/nvr_tc8521.h b/src/nvr_tc8521.h new file mode 100644 index 0000000..c8edce6 --- /dev/null +++ b/src/nvr_tc8521.h @@ -0,0 +1,12 @@ +void nvr_tc8521_init(); + +extern int enable_sync; + +extern int nvr_dosave; + +void tc8521_loadnvr(); +void tc8521_savenvr(); + +void tc8521_nvr_recalc(); + +FILE *nvrfopen(char *fn, char *mode); diff --git a/src/opti495.c b/src/opti495.c index 1faef5a..ebf8e2b 100644 --- a/src/opti495.c +++ b/src/opti495.c @@ -27,15 +27,10 @@ static void opti495_write(uint16_t addr, uint8_t val, void *p) } if (optireg == 0x22) { - shadowbios = !(val & 0x80); - shadowbios_write = val & 0x80; - //pclog("shadowbios %i %02x\n", shadowbios, val); - if (shadowbios) + if (!(val & 0x80)) 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); -// if (shadowbios) -// fatal("Here\n"); } } break; diff --git a/src/paths.c b/src/paths.c new file mode 100644 index 0000000..15d9963 --- /dev/null +++ b/src/paths.c @@ -0,0 +1,238 @@ +#include "paths.h" +#include "config.h" +#include +#include "ibm.h" + +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + +char default_roms_paths[4096]; +char default_nvr_path[512]; +char default_configs_path[512]; +char default_logs_path[512]; +char default_screenshots_path[512]; + +/* the number of roms paths */ +int num_roms_paths; +char roms_paths[4096]; +/* this is where pcem.cfg is */ +char pcem_path[512]; +/* this is where nvr-files as stored */ +char nvr_path[512]; +/* this is where configs as stored */ +char configs_path[512]; +/* this is where log-files as stored */ +char logs_path[512]; +/* this is where screenshots as stored */ +char screenshots_path[512]; + +char nvr_default_path[512]; + +char get_path_separator() +{ +#ifdef _WIN32 + return ';'; +#else + return ':'; +#endif +} + +int get_roms_path(int pos, char *s, int size) +{ + int j, i, z, len; + char path_separator; + + path_separator = get_path_separator(); + len = strlen(roms_paths); + j = 0; + for (i = 0; i < len; i++) + { + if (roms_paths[i] == path_separator || i == len-1) + { + if ((pos--) == 0) + { + z = (i-j) + ((i == len-1) ? 1 : 0); + safe_strncpy(s, roms_paths+j, size); + s[(size-1 < z) ? size-1 : z] = 0; + return 1; + } + j = i+1; + } + } + return 0; +} + +void set_roms_paths(char *path) +{ + char s[512]; + int j, i, z, len; + char path_separator[2]; + + roms_paths[0] = 0; + path_separator[0] = get_path_separator(); + path_separator[1] = 0; + len = strlen(path); + j = 0; + num_roms_paths = 0; + for (i = 0; i < len; i++) + { + if (path[i] == path_separator[0] || i == len-1) + { + z = (i-j) + ((i == len-1) ? 1 : 0) + 1; + safe_strncpy(s, path+j, z); + s[(511 < z) ? 511 : z] = 0; + append_slash(s, 512); + if (dir_exists(s)) + { + if (num_roms_paths > 0) + strcat(roms_paths, path_separator); + strcat(roms_paths, s); + num_roms_paths++; + } + j = i+1; + } + } +} + +void set_nvr_path(char *s) +{ + safe_strncpy(nvr_path, s, 512); + append_slash(nvr_path, 512); +} + +void set_logs_path(char *s) +{ + safe_strncpy(logs_path, s, 512); + append_slash(logs_path, 512); +} + +void set_configs_path(char *s) +{ + safe_strncpy(configs_path, s, 512); + append_slash(configs_path, 512); +} + +void set_screenshots_path(char *s) +{ + safe_strncpy(screenshots_path, s, 512); + append_slash(screenshots_path, 512); +} + +/* set the default roms paths, this makes them permanent */ +void set_default_roms_paths(char *s) +{ + safe_strncpy(default_roms_paths, s, 4096); + set_roms_paths(s); +} + +/* set the default nvr path, this makes it permanent */ +void set_default_nvr_path(char *s) +{ + safe_strncpy(default_nvr_path, s, 512); + set_nvr_path(s); +} + +static void set_default_nvr_default_path(char *s) +{ + safe_strncpy(nvr_default_path, s, 512); +} + +/* set the default logs path, this makes it permanent */ +void set_default_logs_path(char *s) +{ + safe_strncpy(default_logs_path, s, 512); + set_logs_path(s); +} + +/* set the default configs path, this makes it permanent */ +void set_default_configs_path(char *s) +{ + safe_strncpy(default_configs_path, s, 512); + set_configs_path(s); +} + +/* set the default screenshots path, this makes it permanent */ +void set_default_screenshots_path(char *s) +{ + safe_strncpy(default_screenshots_path, s, 512); + set_screenshots_path(s); +} + +void paths_loadconfig() +{ + char *cfg_roms_paths = config_get_string(CFG_GLOBAL, "Paths", "roms_paths", 0); + char *cfg_nvr_path = config_get_string(CFG_GLOBAL, "Paths", "nvr_path", 0); + char *cfg_configs_path = config_get_string(CFG_GLOBAL, "Paths", "configs_path", 0); + char *cfg_logs_path = config_get_string(CFG_GLOBAL, "Paths", "logs_path", 0); + char *cfg_screenshots_path = config_get_string(CFG_GLOBAL, "Paths", "screenshots_path", 0); + + if (cfg_roms_paths) + safe_strncpy(default_roms_paths, cfg_roms_paths, 4096); + if (cfg_nvr_path) + safe_strncpy(default_nvr_path, cfg_nvr_path, 512); + if (cfg_configs_path) + safe_strncpy(default_configs_path, cfg_configs_path, 512); + if (cfg_logs_path) + safe_strncpy(default_logs_path, cfg_logs_path, 512); + if (cfg_screenshots_path) + safe_strncpy(default_screenshots_path, cfg_screenshots_path, 512); +} + +void paths_saveconfig() +{ + config_set_string(CFG_GLOBAL, "Paths", "roms_paths", default_roms_paths); + config_set_string(CFG_GLOBAL, "Paths", "nvr_path", default_nvr_path); + config_set_string(CFG_GLOBAL, "Paths", "configs_path", default_configs_path); + config_set_string(CFG_GLOBAL, "Paths", "logs_path", default_logs_path); + config_set_string(CFG_GLOBAL, "Paths", "screenshots_path", default_screenshots_path); +} + +void paths_onconfigloaded() +{ + if (strlen(default_roms_paths) > 0) + set_roms_paths(default_roms_paths); + + if (strlen(default_nvr_path) > 0) + set_nvr_path(default_nvr_path); + + if (strlen(default_configs_path) > 0) + set_configs_path(default_configs_path); + + if (strlen(default_logs_path) > 0) + set_logs_path(default_logs_path); + + if (strlen(default_screenshots_path) > 0) + set_screenshots_path(default_screenshots_path); + + pclog("path = %s\n", pcem_path); +} + +/* initialize default paths */ +void paths_init() +{ + char s[512]; + char base_path[512]; + char *p; + + get_pcem_path(pcem_path, 512); + /* pcem_path may be path to executable */ + p=get_filename(pcem_path); + *p=0; + + /* set up default paths for this session */ + append_filename(s, pcem_path, "roms/", 512); + set_roms_paths(s); + append_filename(s, pcem_path, "nvr/", 512); + set_nvr_path(s); + append_filename(s, pcem_path, "configs/", 512); + set_configs_path(s); + append_filename(s, pcem_path, "screenshots/", 512); + set_screenshots_path(s); + set_logs_path(pcem_path); + + get_pcem_base_path(base_path, 512); + append_filename(s, base_path, "nvr/default/", 512); + set_default_nvr_default_path(s); + + add_config_callback(paths_loadconfig, paths_saveconfig, paths_onconfigloaded); + +} diff --git a/src/paths.h b/src/paths.h new file mode 100644 index 0000000..bf18630 --- /dev/null +++ b/src/paths.h @@ -0,0 +1,29 @@ +extern int num_roms_paths; +extern char pcem_path[512]; +extern char configs_path[512]; +extern char nvr_path[512]; +extern char logs_path[512]; +extern char screenshots_path[512]; +extern char nvr_default_path[512]; + +void get_pcem_path(char *s, int size); +void get_pcem_base_path(char *s, int size); +char get_path_separator(); +void paths_init(); +int dir_exists(char* path); + +int get_roms_path(int p, char* s, int size); + +/* set the default paths to make them permanent */ +void set_default_roms_paths(char *s); +void set_default_nvr_path(char *s); +void set_default_logs_path(char *s); +void set_default_configs_path(char *s); +void set_default_screenshots_path(char *s); + +/* set the paths temporarily for this session */ +void set_roms_paths(char* path); +void set_nvr_path(char *s); +void set_logs_path(char *s); +void set_configs_path(char *s); +void set_screenshots_path(char *s); diff --git a/src/pc.c b/src/pc.c index 2c38c83..dbe1633 100644 --- a/src/pc.c +++ b/src/pc.c @@ -1,12 +1,20 @@ #include #include #include +#ifdef __APPLE__ +#include +#include +#ifdef __aarch64__ +#include +#endif +#endif #include "ibm.h" #include "device.h" #include "ali1429.h" #include "cdrom-ioctl.h" -#include "cdrom-iso.h" +#include "cdrom-image.h" +#include "cpu.h" #include "disc.h" #include "disc_img.h" #include "mem.h" @@ -22,8 +30,10 @@ #include "gameport.h" #include "sound_gus.h" #include "ide.h" +#include "io.h" #include "keyboard.h" #include "keyboard_at.h" +#include "lpt.h" #include "model.h" #include "mouse.h" #include "nvr.h" @@ -33,9 +43,12 @@ #include "plat-keyboard.h" #include "plat-midi.h" #include "plat-mouse.h" +#include "scsi_cd.h" +#include "scsi_zip.h" #include "serial.h" #include "sound.h" #include "sound_cms.h" +#include "sound_dbopl.h" #include "sound_opl.h" #include "sound_sb.h" #include "sound_speaker.h" @@ -46,20 +59,27 @@ #include "amstrad.h" #include "hdd.h" #include "x86.h" +#include "paths.h" + +#ifdef USE_NETWORKING +#include "nethandler.h" +#define NE2000 1 +uint8_t ethif; +int inum; +#endif int window_w, window_h, window_x, window_y, window_remember; int start_in_fullscreen = 0; -int cdrom_enabled; -int CPUID; +static int override_drive_a = 0, override_drive_b = 0; + int vid_resize, vid_api; int cycles_lost = 0; int config_override = 0; -int clockrate; int insc=0; float mips,flops; extern int mmuflush; @@ -68,7 +88,6 @@ void fullspeed(); int framecount,fps; -int output; int atfullspeed; void saveconfig(char *fn); @@ -78,37 +97,47 @@ FILE *pclogf; void pclog(const char *format, ...) { #ifndef RELEASE_BUILD - char buf[1024]; - //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); + char buf[1024]; + //return; + if (!pclogf) + { + strcpy(buf, logs_path); + put_backslash(buf); + strcat(buf, "pcem.log"); + pclogf=fopen(buf, "wt"); + } + //return; + va_list ap; + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + fputs(buf,pclogf); +// fflush(pclogf); #endif } void fatal(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); - savenvr(); - dumppic(); - dumpregs(); - exit(-1); + char buf[256]; + // return; + if (!pclogf) + { + strcpy(buf, logs_path); + put_backslash(buf); + strcat(buf, "pcem.log"); + pclogf=fopen(buf, "wt"); + } + //return; + va_list ap; + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + fputs(buf,pclogf); + fflush(pclogf); + savenvr(); + dumppic(); + dumpregs(); + exit(-1); } uint8_t cgastat; @@ -180,12 +209,13 @@ void onesec() { fps=framecount; framecount=0; + video_refresh_rate = video_frames; + video_frames = 0; win_title_update=1; } void pc_reset() { - cpu_set(); resetx86(); //timer_reset(); dma_reset(); @@ -204,23 +234,13 @@ void pc_reset() // video_init(); } #undef printf -void getpath() -{ - char *p; - - get_executable_name(pcempath,511); - pclog("executable_name = %s\n", pcempath); - p=get_filename(pcempath); - *p=0; - pclog("path = %s\n", pcempath); -} + void initpc(int argc, char *argv[]) { //char *p; // char *config_file = NULL; int c; -// allegro_init(); for (c = 1; c < argc; c++) { @@ -229,6 +249,8 @@ void initpc(int argc, char *argv[]) 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"); + printf("--load_drive_a file.img - load drive A: with the given disc image\n"); + printf("--load_drive_b file.img - load drive B: with the given disc image\n"); exit(-1); } else if (!strcasecmp(argv[c], "--fullscreen")) @@ -237,15 +259,44 @@ void initpc(int argc, char *argv[]) } else if (!strcasecmp(argv[c], "--config")) { + char *ext; + if ((c+1) == argc) break; strncpy(config_file_default, argv[c+1], 256); + strcpy(config_name, get_filename(config_file_default)); + + ext = get_extension(config_name); + if (ext && ext[0]) + { + ext--; + *ext = 0; + } + config_override = 1; c++; } + else if (!strcasecmp(argv[c], "--load_drive_a")) + { + if ((c+1) == argc) + break; + + strncpy(discfns[0], argv[c+1], 256); + c++; + override_drive_a = 1; + } + else if (!strcasecmp(argv[c], "--load_drive_b")) + { + if ((c+1) == argc) + break; + + strncpy(discfns[1], argv[c+1], 256); + c++; + override_drive_b = 1; + } } -// append_filename(config_file_default, pcempath, "pcem.cfg", 511); +// append_filename(config_file_default, pcempath, "pcem.cfg", 511); loadconfig(NULL); pclog("Config loaded\n"); @@ -261,20 +312,30 @@ void initpc(int argc, char *argv[]) initvideo(); mem_init(); loadbios(); - mem_add_bios(); + + // this is now done per-model + //mem_add_bios(); +#if defined(__APPLE__) && defined(__aarch64__) + pthread_jit_write_protect_np(0); +#endif codegen_init(); +#if defined(__APPLE__) && defined(__aarch64__) + pthread_jit_write_protect_np(1); +#endif timer_reset(); sound_reset(); + io_init(); fdc_init(); disc_init(); fdi_init(); img_init(); +#ifdef USE_NETWORKING + vlan_reset(); //NETWORK + network_card_init(network_card_current); +#endif - disc_load(0, discfns[0]); - disc_load(1, discfns[1]); - //loadfont(); loadnvr(); resetide(); @@ -284,13 +345,13 @@ void initpc(int argc, char *argv[]) else #endif { - if (cdrom_drive == CDROM_ISO) + if (cdrom_drive == CDROM_IMAGE) { - FILE *ff = fopen(iso_path, "rb"); + FILE *ff = fopen(image_path, "rb"); if (ff) { fclose(ff); - iso_open(iso_path); + image_open(image_path); } else { @@ -313,17 +374,16 @@ void initpc(int argc, char *argv[]) ali1429_reset(); // CPUID=(is486 && (cpuspeed==7 || cpuspeed>=9)); // pclog("Init - CPUID %i %i\n",CPUID,cpuspeed); - shadowbios=0; - + #if __unix if (cdrom_drive == -1) cdrom_null_reset(); else #endif { - if (cdrom_drive == CDROM_ISO) + if (cdrom_drive == CDROM_IMAGE) { - iso_reset(); + image_reset(); } else { @@ -334,21 +394,22 @@ void initpc(int argc, char *argv[]) void resetpc() { + cpu_set(); pc_reset(); + cpu_set_turbo(1); // cpuspeed2=(AT)?2:1; // atfullspeed=0; ///* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); - shadowbios=0; } void resetpc_cad() { - keyboard_send(29); /* Ctrl key pressed */ - keyboard_send(56); /* Alt key pressed */ - keyboard_send(83); /* Delete key pressed */ - keyboard_send(157); /* Ctrl key released */ - keyboard_send(184); /* Alt key released */ - keyboard_send(211); /* Delete key released */ + keyboard_send_scancode(29, 0); /* Ctrl key pressed */ + keyboard_send_scancode(56, 0); /* Alt key pressed */ + keyboard_send_scancode(83, 0); /* Delete key pressed */ + keyboard_send_scancode(29, 1); /* Ctrl key released */ + keyboard_send_scancode(56, 1); /* Alt key released */ + keyboard_send_scancode(83, 1); /* Delete key released */ } void resetpchard() @@ -357,19 +418,29 @@ void resetpchard() mouse_emu_close(); device_init(); - midi_close(); - midi_init(); - timer_reset(); sound_reset(); - mem_resize(); + io_init(); + cpu_set(); + mem_alloc(); fdc_init(); disc_reset(); - + disc_load(0, discfns[0]); + disc_load(1, discfns[1]); + + if (!AT && models[model].max_ram > 640 && models[model].max_ram <= 768 && !video_is_ega_vga()) + mem_set_704kb(); model_init(); mouse_emu_init(); video_init(); - speaker_init(); + speaker_init(); + lpt1_device_init(); + +#ifdef USE_NETWORKING + vlan_reset(); //NETWORK + network_card_init(network_card_current); +#endif + sound_card_init(sound_card_current); if (GUS) device_add(&gus_device); @@ -390,7 +461,6 @@ void resetpchard() // atfullspeed = 0; // setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); - shadowbios = 0; ali1429_reset(); keyboard_at_reset(); @@ -399,21 +469,43 @@ void resetpchard() // output=3; + image_close(); #if __unix if (cdrom_drive == -1) cdrom_null_reset(); else #endif { - if (cdrom_drive == CDROM_ISO) + if (cdrom_drive == CDROM_IMAGE) { - iso_reset(); + FILE *ff = fopen(image_path, "rb"); + if (ff) + { + fclose(ff); + image_open(image_path); + } + else + { +#if __unix + cdrom_drive = -1; + cdrom_null_open(cdrom_drive); +#else + cdrom_drive = 0; + ioctl_set_drive(cdrom_drive); +#endif + } } else { + ioctl_set_drive(cdrom_drive); ioctl_reset(); } } + + sound_update_buf_length(); + cpu_set_turbo(1); + + cycles = cycles_main = 0; } 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"}; @@ -433,86 +525,97 @@ int serial_fifo_read, serial_fifo_write; int emu_fps = 0; +#ifdef __APPLE__ +static void _set_window_title(void *s) +{ + set_window_title((const char *)s); + free(s); +} +#endif + void runpc() { char s[200]; int done=0; + int cycles_to_run = cpu_get_speed() / 100; + + override_drive_a = override_drive_b = 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); + exec386_dynarec(cycles_to_run); else - exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + exec386(cycles_to_run); } else if (AT) - exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + exec386(cycles_to_run); else - execx86(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + execx86(cycles_to_run); - keyboard_poll_host(); - keyboard_process(); -// checkkeys(); - pollmouse(); - joystick_poll(); + 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; + 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_state.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_state.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; + cpu_recomp_blocks_latched = cpu_recomp_blocks; + cpu_recomp_ins_latched = cpu_state.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; - updatestatus=1; - readlnum=writelnum=0; - egareads=egawrites=0; - cycles_lost = 0; - mmuflush=0; - emu_fps = frames; - frames = 0; - } - if (win_title_update) - { - win_title_update=0; - sprintf(s, "PCem v12 - %i%% - %s - %s - %s", fps, model_getname(), models[model].cpu[cpu_manufacturer].cpus[cpu].name, (!mousecapture) ? "Click to capture mouse" : ((mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON) ? "Press CTRL-END to release mouse" : "Press CTRL-END or middle button to release mouse")); - set_window_title(s); - } - done++; + cpu_recomp_blocks = 0; + cpu_state.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; + + updatestatus=1; + readlnum=writelnum=0; + egareads=egawrites=0; + cycles_lost = 0; + mmuflush=0; + emu_fps = frames; + frames = 0; + } + if (win_title_update) + { + win_title_update=0; + sprintf(s, "PCem " PCEM_VERSION_STRING " - %i%% - %s - %s - %s", fps, model_getname(), models[model].cpu[cpu_manufacturer].cpus[cpu].name, (!mousecapture) ? "Click to capture mouse" : ((mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON) ? "Press CTRL-END to release mouse" : "Press CTRL-END or middle button to release mouse")); +#ifdef __APPLE__ + // Needed due to modifying the UI on the non-main thread is a big no-no. + dispatch_async_f(dispatch_get_main_queue(), strdup(s), _set_window_title); +#else + set_window_title(s); +#endif + } + done++; } void fullspeed() @@ -520,7 +623,7 @@ void fullspeed() cpuspeed2=cpuspeed; if (!atfullspeed) { - printf("Set fullspeed - %i %i %i\n",is386,AT,cpuspeed2); + pclog("Set fullspeed - %i %i %i\n",is386,AT,cpuspeed2); if (AT) setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); else @@ -529,7 +632,6 @@ void fullspeed() // else setpitclock(clocks[AT?1:0][cpuspeed2][0]); } atfullspeed=1; - nvr_recalc(); } void speedchanged() @@ -538,11 +640,11 @@ void speedchanged() setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); else setpitclock(14318184.0); - nvr_recalc(); } void closepc() { + codegen_close(); atapi->exit(); // ioctl_close(); dumppic(); @@ -553,8 +655,10 @@ void closepc() disc_close(1); dumpregs(); closevideo(); + lpt1_device_close(); mouse_emu_close(); device_close_all(); + zip_eject(); } /*int main() @@ -570,6 +674,22 @@ void closepc() END_OF_MAIN();*/ +typedef struct config_callback_t +{ + void(*loadconfig)(); + void(*saveconfig)(); + void(*onloaded)(); +} config_callback_t; +config_callback_t config_callbacks[10]; +int num_config_callbacks = 0; + +void add_config_callback(void(*loadconfig)(), void(*saveconfig)(), void(*onloaded)()) +{ + config_callbacks[num_config_callbacks].loadconfig = loadconfig; + config_callbacks[num_config_callbacks].saveconfig = saveconfig; + config_callbacks[num_config_callbacks].onloaded = onloaded; + num_config_callbacks++; +} void loadconfig(char *fn) { @@ -578,7 +698,7 @@ void loadconfig(char *fn) char global_config_file[512]; char *p; - append_filename(global_config_file, pcempath, "pcem.cfg", 511); + append_filename(global_config_file, pcem_path, "pcem.cfg", 511); config_load(CFG_GLOBAL, global_config_file); @@ -599,6 +719,9 @@ void loadconfig(char *fn) window_x = config_get_int(CFG_GLOBAL, NULL, "window_x", 0); window_y = config_get_int(CFG_GLOBAL, NULL, "window_y", 0); window_remember = config_get_int(CFG_GLOBAL, NULL, "window_remember", 0); + + sound_buf_len = config_get_int(CFG_GLOBAL, NULL, "sound_buf_len", 200); + sound_gain = config_get_int(CFG_GLOBAL, NULL, "sound_gain", 0); GAMEBLASTER = config_get_int(CFG_MACHINE, NULL, "gameblaster", 0); GUS = config_get_int(CFG_MACHINE, NULL, "gus", 0); @@ -617,6 +740,8 @@ void loadconfig(char *fn) romset = model_getromset(); cpu_manufacturer = config_get_int(CFG_MACHINE, NULL, "cpu_manufacturer", 0); cpu = config_get_int(CFG_MACHINE, NULL, "cpu", 0); + p = (char *)config_get_string(CFG_MACHINE, NULL, "fpu", "none"); + fpu_type = fpu_get_type(model, cpu_manufacturer, cpu, p); cpu_use_dynarec = config_get_int(CFG_MACHINE, NULL, "cpu_use_dynarec", 0); cpu_waitstates = config_get_int(CFG_MACHINE, NULL, "cpu_waitstates", 0); @@ -625,20 +750,26 @@ void loadconfig(char *fn) gfxcard = video_get_video_from_internal_name(p); else gfxcard = 0; - video_speed = config_get_int(CFG_MACHINE, NULL, "video_speed", 3); + video_speed = config_get_int(CFG_MACHINE, NULL, "video_speed", -1); p = (char *)config_get_string(CFG_MACHINE, NULL, "sndcard", ""); if (p) sound_card_current = sound_card_get_from_internal_name(p); else sound_card_current = 0; - p = (char *)config_get_string(CFG_MACHINE, NULL, "disc_a", ""); - if (p) strcpy(discfns[0], p); - else strcpy(discfns[0], ""); + if (!override_drive_a) + { + p = (char *)config_get_string(CFG_MACHINE, NULL, "disc_a", ""); + if (p) strcpy(discfns[0], p); + else strcpy(discfns[0], ""); + } - p = (char *)config_get_string(CFG_MACHINE, NULL, "disc_b", ""); - if (p) strcpy(discfns[1], p); - else strcpy(discfns[1], ""); + if (!override_drive_b) + { + p = (char *)config_get_string(CFG_MACHINE, NULL, "disc_b", ""); + if (p) strcpy(discfns[1], p); + else strcpy(discfns[1], ""); + } p = (char *)config_get_string(CFG_MACHINE, NULL, "hdd_controller", ""); if (p) @@ -647,16 +778,17 @@ void loadconfig(char *fn) strncpy(hdd_controller_name, "none", sizeof(hdd_controller_name)-1); mem_size = config_get_int(CFG_MACHINE, NULL, "mem_size", 4096); - if (mem_size < ((models[model].flags & MODEL_AT) ? models[model].min_ram*1024 : models[model].min_ram)) - mem_size = ((models[model].flags & MODEL_AT) ? models[model].min_ram*1024 : models[model].min_ram); + if (mem_size < (((models[model].flags & MODEL_AT) && models[model].ram_granularity < 128) ? models[model].min_ram*1024 : models[model].min_ram)) + mem_size = (((models[model].flags & MODEL_AT) && models[model].ram_granularity < 128) ? models[model].min_ram*1024 : models[model].min_ram); cdrom_drive = config_get_int(CFG_MACHINE, NULL, "cdrom_drive", 0); - cdrom_enabled = config_get_int(CFG_MACHINE, NULL, "cdrom_enabled", 0); cdrom_channel = config_get_int(CFG_MACHINE, NULL, "cdrom_channel", 2); + zip_channel = config_get_int(CFG_MACHINE, NULL, "zip_channel", -1); + p = (char *)config_get_string(CFG_MACHINE, NULL, "cdrom_path", ""); - if (p) strcpy(iso_path, p); - else strcpy(iso_path, ""); + if (p) strcpy(image_path, p); + else strcpy(image_path, ""); hdc[0].spt = config_get_int(CFG_MACHINE, NULL, "hdc_sectors", 0); hdc[0].hpc = config_get_int(CFG_MACHINE, NULL, "hdc_heads", 0); @@ -682,11 +814,32 @@ void loadconfig(char *fn) p = (char *)config_get_string(CFG_MACHINE, NULL, "hdf_fn", ""); if (p) strcpy(ide_fn[3], p); else strcpy(ide_fn[3], ""); + hdc[4].spt = config_get_int(CFG_MACHINE, NULL, "hdg_sectors", 0); + hdc[4].hpc = config_get_int(CFG_MACHINE, NULL, "hdg_heads", 0); + hdc[4].tracks = config_get_int(CFG_MACHINE, NULL, "hdg_cylinders", 0); + p = (char *)config_get_string(CFG_MACHINE, NULL, "hdg_fn", ""); + if (p) strcpy(ide_fn[4], p); + else strcpy(ide_fn[4], ""); + hdc[5].spt = config_get_int(CFG_MACHINE, NULL, "hdh_sectors", 0); + hdc[5].hpc = config_get_int(CFG_MACHINE, NULL, "hdh_heads", 0); + hdc[5].tracks = config_get_int(CFG_MACHINE, NULL, "hdh_cylinders", 0); + p = (char *)config_get_string(CFG_MACHINE, NULL, "hdh_fn", ""); + if (p) strcpy(ide_fn[5], p); + else strcpy(ide_fn[5], ""); + hdc[6].spt = config_get_int(CFG_MACHINE, NULL, "hdi_sectors", 0); + hdc[6].hpc = config_get_int(CFG_MACHINE, NULL, "hdi_heads", 0); + hdc[6].tracks = config_get_int(CFG_MACHINE, NULL, "hdi_cylinders", 0); + p = (char *)config_get_string(CFG_MACHINE, NULL, "hdi_fn", ""); + if (p) strcpy(ide_fn[6], p); + else strcpy(ide_fn[6], ""); fdd_set_type(0, config_get_int(CFG_MACHINE, NULL, "drive_a_type", 7)); fdd_set_type(1, config_get_int(CFG_MACHINE, NULL, "drive_b_type", 7)); bpb_disable = config_get_int(CFG_MACHINE, NULL, "bpb_disable", 0); + cd_speed = config_get_int(CFG_MACHINE, NULL, "cd_speed", 24); + cd_model = cd_model_from_config((char *)config_get_string(CFG_MACHINE, NULL, "cd_model", cd_get_config_model(0))); + joystick_type = config_get_int(CFG_MACHINE, NULL, "joystick_type", 0); mouse_type = config_get_int(CFG_MACHINE, NULL, "mouse_type", 0); @@ -718,6 +871,35 @@ void loadconfig(char *fn) } enable_sync = config_get_int(CFG_MACHINE, NULL, "enable_sync", 1); + + p = (char *)config_get_string(CFG_MACHINE, NULL, "lpt1_device", ""); + if (p) strcpy(lpt1_device_name, p); + else strcpy(lpt1_device_name, ""); + +#ifdef USE_NETWORKING + //network + ethif = config_get_int(CFG_GLOBAL, NULL, "netinterface", 1); + if (ethif >= inum) + inum = ethif + 1; + + p = (char *)config_get_string(CFG_MACHINE, NULL, "netcard", ""); + if (p) + network_card_current = network_card_get_from_internal_name(p); + else + network_card_current = 0; +#endif + + for (d = 0; d < num_config_callbacks; ++d) + if (config_callbacks[d].loadconfig) + config_callbacks[d].loadconfig(); + + + for (d = 0; d < num_config_callbacks; ++d) + if (config_callbacks[d].onloaded) + config_callbacks[d].onloaded(); + + config_dump(CFG_GLOBAL); + config_dump(CFG_MACHINE); } void saveconfig(char *fn) @@ -725,7 +907,7 @@ void saveconfig(char *fn) int c, d; char global_config_file[512]; - append_filename(global_config_file, pcempath, "pcem.cfg", 511); + append_filename(global_config_file, pcem_path, "pcem.cfg", 511); config_set_int(CFG_GLOBAL, NULL, "vid_resize", vid_resize); config_set_int(CFG_GLOBAL, NULL, "vid_force_aspect_ratio", video_force_aspect_ration); @@ -739,6 +921,9 @@ void saveconfig(char *fn) config_set_int(CFG_GLOBAL, NULL, "window_x", window_x); config_set_int(CFG_GLOBAL, NULL, "window_y", window_y); config_set_int(CFG_GLOBAL, NULL, "window_remember", window_remember); + + config_set_int(CFG_GLOBAL, NULL, "sound_buf_len", sound_buf_len); + config_set_int(CFG_GLOBAL, NULL, "sound_gain", sound_gain); config_set_int(CFG_MACHINE, NULL, "gameblaster", GAMEBLASTER); config_set_int(CFG_MACHINE, NULL, "gus", GUS); @@ -748,6 +933,7 @@ void saveconfig(char *fn) config_set_string(CFG_MACHINE, NULL, "model", model_get_internal_name()); config_set_int(CFG_MACHINE, NULL, "cpu_manufacturer", cpu_manufacturer); config_set_int(CFG_MACHINE, NULL, "cpu", cpu); + config_set_string(CFG_MACHINE, NULL, "fpu", (char *)fpu_get_internal_name(model, cpu_manufacturer, cpu, fpu_type)); config_set_int(CFG_MACHINE, NULL, "cpu_use_dynarec", cpu_use_dynarec); config_set_int(CFG_MACHINE, NULL, "cpu_waitstates", cpu_waitstates); @@ -755,17 +941,17 @@ void saveconfig(char *fn) config_set_int(CFG_MACHINE, NULL, "video_speed", video_speed); config_set_string(CFG_MACHINE, NULL, "sndcard", sound_card_get_internal_name(sound_card_current)); config_set_int(CFG_MACHINE, NULL, "cpu_speed", cpuspeed); - config_set_int(CFG_MACHINE, NULL, "has_fpu", hasfpu); config_set_string(CFG_MACHINE, NULL, "disc_a", discfns[0]); config_set_string(CFG_MACHINE, NULL, "disc_b", discfns[1]); config_set_string(CFG_MACHINE, NULL, "hdd_controller", hdd_controller_name); config_set_int(CFG_MACHINE, NULL, "mem_size", mem_size); config_set_int(CFG_MACHINE, NULL, "cdrom_drive", cdrom_drive); - config_set_int(CFG_MACHINE, NULL, "cdrom_enabled", cdrom_enabled); config_set_int(CFG_MACHINE, NULL, "cdrom_channel", cdrom_channel); - config_set_string(CFG_MACHINE, NULL, "cdrom_path", iso_path); - + config_set_string(CFG_MACHINE, NULL, "cdrom_path", image_path); + + config_set_int(CFG_MACHINE, NULL, "zip_channel", zip_channel); + config_set_int(CFG_MACHINE, NULL, "hdc_sectors", hdc[0].spt); config_set_int(CFG_MACHINE, NULL, "hdc_heads", hdc[0].hpc); config_set_int(CFG_MACHINE, NULL, "hdc_cylinders", hdc[0].tracks); @@ -782,11 +968,26 @@ void saveconfig(char *fn) config_set_int(CFG_MACHINE, NULL, "hdf_heads", hdc[3].hpc); config_set_int(CFG_MACHINE, NULL, "hdf_cylinders", hdc[3].tracks); config_set_string(CFG_MACHINE, NULL, "hdf_fn", ide_fn[3]); + config_set_int(CFG_MACHINE, NULL, "hdg_sectors", hdc[4].spt); + config_set_int(CFG_MACHINE, NULL, "hdg_heads", hdc[4].hpc); + config_set_int(CFG_MACHINE, NULL, "hdg_cylinders", hdc[4].tracks); + config_set_string(CFG_MACHINE, NULL, "hdg_fn", ide_fn[4]); + config_set_int(CFG_MACHINE, NULL, "hdh_sectors", hdc[5].spt); + config_set_int(CFG_MACHINE, NULL, "hdh_heads", hdc[5].hpc); + config_set_int(CFG_MACHINE, NULL, "hdh_cylinders", hdc[5].tracks); + config_set_string(CFG_MACHINE, NULL, "hdh_fn", ide_fn[5]); + config_set_int(CFG_MACHINE, NULL, "hdi_sectors", hdc[6].spt); + config_set_int(CFG_MACHINE, NULL, "hdi_heads", hdc[6].hpc); + config_set_int(CFG_MACHINE, NULL, "hdi_cylinders", hdc[6].tracks); + config_set_string(CFG_MACHINE, NULL, "hdi_fn", ide_fn[6]); config_set_int(CFG_MACHINE, NULL, "drive_a_type", fdd_get_type(0)); config_set_int(CFG_MACHINE, NULL, "drive_b_type", fdd_get_type(1)); config_set_int(CFG_MACHINE, NULL, "bpb_disable", bpb_disable); + config_set_int(CFG_MACHINE, NULL, "cd_speed", cd_speed); + config_set_string(CFG_MACHINE, NULL, "cd_model", cd_model_to_config(cd_model)); + config_set_int(CFG_MACHINE, NULL, "joystick_type", joystick_type); config_set_int(CFG_MACHINE, NULL, "mouse_type", mouse_type); @@ -821,11 +1022,31 @@ void saveconfig(char *fn) config_set_int(CFG_MACHINE, NULL, "enable_sync", enable_sync); +#ifdef USE_NETWORKING + config_set_int(CFG_GLOBAL, NULL, "netinterface", ethif); + config_set_string(CFG_MACHINE, NULL, "netcard", network_card_get_internal_name(network_card_current)); +#endif + + config_set_string(CFG_MACHINE, NULL, "lpt1_device", lpt1_device_name); + + for (d = 0; d < num_config_callbacks; ++d) + if (config_callbacks[d].saveconfig) + config_callbacks[d].saveconfig(); + pclog("config_save(%s)\n", config_file_default); if (fn) config_save(CFG_MACHINE, fn); - else + else if (strlen(config_file_default)) config_save(CFG_MACHINE, config_file_default); config_save(CFG_GLOBAL, global_config_file); } + +void saveconfig_global_only() +{ + char global_config_file[512]; + + append_filename(global_config_file, pcem_path, "pcem.cfg", 511); + + config_save(CFG_GLOBAL, global_config_file); +} diff --git a/src/pc.rc b/src/pc.rc index 0c3ab71..b011d54 100644 --- a/src/pc.rc +++ b/src/pc.rc @@ -24,6 +24,11 @@ BEGIN MENUITEM SEPARATOR MENUITEM "&Configure hard discs...",IDM_HDCONF END + POPUP "C&assette" + BEGIN + MENUITEM "&Load tapefile...", IDM_CASSETTE_LOAD + MENUITEM "&Eject tape", IDM_CASSETTE_EJECT + END POPUP "&Settings" BEGIN MENUITEM "&Configure...", IDM_CONFIG @@ -31,12 +36,12 @@ BEGIN BEGIN MENUITEM "&Disabled", IDM_CDROM_DISABLED MENUITEM "&Empty",IDM_CDROM_EMPTY - MENUITEM "&ISO...",IDM_CDROM_ISO + MENUITEM "&Image...",IDM_CDROM_IMAGE END POPUP "&Video" BEGIN MENUITEM "&Resizeable window",IDM_VID_RESIZE - MENUITEM "Force 4:3 &aspect ration",IDM_VID_ASPECT + MENUITEM "Force 4:3 &aspect ratio",IDM_VID_ASPECT MENUITEM "Remember size && position",IDM_VID_REMEMBER MENUITEM SEPARATOR MENUITEM "&DirectDraw", IDM_VID_DDRAW @@ -53,6 +58,15 @@ BEGIN MENUITEM SEPARATOR MENUITEM "Disc activity indicator", IDM_VID_DISC END + POPUP "&Sound" + BEGIN + POPUP "&Buffer length" + BEGIN + MENUITEM "&100ms", IDM_BUF_100MS + MENUITEM "&200ms", IDM_BUF_200MS + MENUITEM "&400ms", IDM_BUF_400MS + END + END END POPUP "&Misc" BEGIN @@ -60,13 +74,22 @@ BEGIN END END +#ifdef USE_NETWORKING +ConfigureDlg DIALOGEX 0, 0, 292, 432 +#else ConfigureDlg DIALOGEX 0, 0, 292, 412 +#endif STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Configure PCem" FONT 8, "MS Sans Serif" BEGIN +#ifdef USE_NETWORKING + DEFPUSHBUTTON "OK",IDOK,64,408,50,14, WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,128,408,50,14, WS_TABSTOP +#else DEFPUSHBUTTON "OK",IDOK,64,388,50,14, WS_TABSTOP PUSHBUTTON "Cancel",IDCANCEL,128,388,50,14, WS_TABSTOP +#endif COMBOBOX IDC_COMBO1,62,16,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Configure", IDC_CONFIGUREMOD, 224, 16, 40, 14, WS_TABSTOP COMBOBOX IDC_COMBOVID,62,36,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP @@ -81,12 +104,6 @@ BEGIN EDITTEXT IDC_MEMTEXT, 62, 172, 36, 14, ES_AUTOHSCROLL | ES_NUMBER CONTROL "", IDC_MEMSPIN, UPDOWN_CLASS, UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_SETBUDDYINT, 98, 172, 12, 14 LTEXT "MB", IDC_TEXT_MB, 98, 172, 40, 10 - CONTROL "CMS / Game Blaster",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,312,118,10 - CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,328,118,10 - CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,344,118,10 - CONTROL "Synchronise time to host clock",IDC_CHECKSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,360,118,10 - CONTROL "Voodoo Graphics",IDC_CHECKVOODOO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,376,118,10 - PUSHBUTTON "Configure", IDC_CONFIGUREVOODOO, 224, 376, 40, 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 @@ -101,6 +118,28 @@ BEGIN LTEXT "Drive B: :",IDC_STATIC,15,236,40,10 COMBOBOX IDC_COMBODRA,62,216,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP COMBOBOX IDC_COMBODRB,62,236,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + +#ifdef USE_NETWORKING + LTEXT "Network card:",IDC_STATIC,15,256,45,10 + COMBOBOX IDC_COMBONETCARD,62,256,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure", IDC_CONFIGURENETCARD, 224, 256, 40, 14, WS_TABSTOP + + LTEXT "Mouse :",IDC_STATIC,15,276,40,10 + COMBOBOX IDC_COMBOMOUSE,62,276,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + LTEXT "Joystick :",IDC_STATIC,15,296,40,10 + COMBOBOX IDC_COMBOJOY,62,296,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "Joystick 1...",IDC_JOY1,16,312,50,14, WS_TABSTOP + PUSHBUTTON "Joystick 2...",IDC_JOY2,80,312,50,14, WS_TABSTOP + DEFPUSHBUTTON "Joystick 3...",IDC_JOY3,144,312,50,14, WS_TABSTOP + PUSHBUTTON "Joystick 4...",IDC_JOY4,208,312,50,14, WS_TABSTOP + + CONTROL "CMS / Game Blaster",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,332,118,10 + CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,348,118,10 + CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,364,118,10 + CONTROL "Synchronise time to host clock",IDC_CHECKSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,380,118,10 + CONTROL "Voodoo Graphics",IDC_CHECKVOODOO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,396,118,10 + PUSHBUTTON "Configure", IDC_CONFIGUREVOODOO, 224, 396, 40, 14, WS_TABSTOP +#else LTEXT "Mouse :",IDC_STATIC,15,256,40,10 COMBOBOX IDC_COMBOMOUSE,62,256,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP LTEXT "Joystick :",IDC_STATIC,15,276,40,10 @@ -109,6 +148,14 @@ BEGIN PUSHBUTTON "Joystick 2...",IDC_JOY2,80,292,50,14, WS_TABSTOP DEFPUSHBUTTON "Joystick 3...",IDC_JOY3,144,292,50,14, WS_TABSTOP PUSHBUTTON "Joystick 4...",IDC_JOY4,208,292,50,14, WS_TABSTOP + + CONTROL "CMS / Game Blaster",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,312,118,10 + CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,328,118,10 + CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,344,118,10 + CONTROL "Synchronise time to host clock",IDC_CHECKSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,360,118,10 + CONTROL "Voodoo Graphics",IDC_CHECKVOODOO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,376,118,10 + PUSHBUTTON "Configure", IDC_CONFIGUREVOODOO, 224, 376, 40, 14, WS_TABSTOP +#endif END HdConfDlg DIALOGEX 0, 0, 210, 312+4*16 @@ -325,6 +372,23 @@ BEGIN DEFPUSHBUTTON "New...", IDC_NEW, 200-54,40, 50, 14, WS_TABSTOP DEFPUSHBUTTON "Configuration...", IDC_CONFIG, 200-54,58, 50, 14, WS_TABSTOP DEFPUSHBUTTON "HDD...", IDC_HDCONF, 200-54,76, 50, 14, WS_TABSTOP - - LISTBOX IDC_LIST, 4, 4,140,142, WS_TABSTOP +#ifdef USE_NETWORKING + DEFPUSHBUTTON "Network...",IDC_NETWORK, 200-54,104,50, 14, WS_TABSTOP +#endif + LISTBOX IDC_LIST, 4, 4,140,142, WS_TABSTOP|WS_VSCROLL +END + +NetworkConfDlg DIALOGEX 0, 0, 400, 80 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configure Network" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,64,56,50,14, WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,128,56,50,14, WS_TABSTOP + + COMBOBOX IDC_COMBONETTYPE,62,16,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBONETDEVICE,62,36,327,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + + LTEXT "Type :",IDC_STATIC,15,16,40,10 + LTEXT "Device :",IDC_STATIC,15,36,34,10 END diff --git a/src/pc.xrc b/src/pc.xrc new file mode 100644 index 0000000..88e234c --- /dev/null +++ b/src/pc.xrc @@ -0,0 +1,3834 @@ + + + + icons/16x16/drive.png + icons/16x16/diskette.png + icons/16x16/cd.png + + + + icons/24x24/play.png + + + + icons/24x24/pause.png + + + + icons/24x24/stop.png + + + + icons/24x24/refresh.png + + + + + + + + + + + + + + + + + + + + + 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 + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + Configure PCem + 1 + + + 0 + 1 + 0 + 0 + + + + + wxALL|wxEXPAND + 5 + + + + 1 + icons/32x32/motherboard.png + + + + 0 + 3 + 0 + 0 + 1 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxALL + 5 + + icons/16x16/setting_tools.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 120,-1 + + + + + + + wxALL + 5 + + + 220,-1 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 120,-1 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 0 + 0 + 10 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + + + 0 + icons/32x32/video_mode.png + + + + 0 + 3 + 0 + 0 + 1 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxALL + 5 + + icons/16x16/setting_tools.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxALL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 0 + + + + + + + wxALL + 5 + + icons/16x16/setting_tools.png + 0 + + + + + + + 0 + icons/32x32/sound.png + + + + 0 + 3 + 0 + 0 + 1 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxALL + 5 + + icons/16x16/setting_tools.png + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + + + 0 + icons/32x32/drive.png + + + + 0 + 1 + 0 + 0 + 0 + + + + wxEXPAND + 0 + + 0 + 3 + 0 + 0 + 1 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxALL + 5 + + icons/16x16/setting_tools.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + wxEXPAND | wxALL + 5 + + + + + + + wxEXPAND | wxALL + 5 + + + + + + + + + 0 + icons/32x32/mouse_pc.png + + + + 0 + 2 + 0 + 0 + 1 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + + + 0 + icons/32x32/joystick.png + + + + 2 + 0 + 0 + 0 + + + + + 0 + 4 + 0 + 0 + 1 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + + + + + 0 + 4 + + + wxALL + 5 + + + 1 + + + + + wxALL + 5 + + + 1 + + + + + wxALL + 5 + + + 1 + + + + + wxALL + 5 + + + 1 + + + + + + + + + + 0 + icons/32x32/network_ethernet.png + + + + 0 + 2 + 0 + 0 + 1 + + + + wxALL + 5 + + 80,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + wxALL + 5 + + + icons/16x16/setting_tools.png + 0 + + + + + + + + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + + 1 + + + + + wxALL + 5 + + + 0 + + + + + + + + + + + 0 + 3 + 0 + 0 + 2 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 75,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + New + icons/16x16/drive_add.png + 0 + + + + + + + wxALL + 5 + + Browse + icons/16x16/folder.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL|wxEXPAND + 5 + + + 350,-1 + + + + + + wxALL + 5 + + icons/16x16/control_eject.png + Eject + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + 1,3 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + + 0 + 3 + 0 + 0 + 2 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 75,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + New + icons/16x16/drive_add.png + 0 + + + + + + + wxALL + 5 + + Browse + icons/16x16/folder.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL|wxEXPAND + 5 + + + 350,-1 + + + + + + wxALL + 5 + + icons/16x16/control_eject.png + Eject + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + 1,3 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + + 0 + 3 + 0 + 0 + 2 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 75,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + New + icons/16x16/drive_add.png + 0 + + + + + + + wxALL + 5 + + Browse + icons/16x16/folder.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL|wxEXPAND + 5 + + + 350,-1 + + + + + + wxALL + 5 + + icons/16x16/control_eject.png + Eject + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + 1,3 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + + 0 + 3 + 0 + 0 + 2 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 75,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + New + icons/16x16/drive_add.png + 0 + + + + + + + wxALL + 5 + + Browse + icons/16x16/folder.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL|wxEXPAND + 5 + + + 350,-1 + + + + + + wxALL + 5 + + icons/16x16/control_eject.png + Eject + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + 1,3 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + + 0 + 3 + 0 + 0 + 2 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 75,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + New + icons/16x16/drive_add.png + 0 + + + + + + + wxALL + 5 + + Browse + icons/16x16/folder.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL|wxEXPAND + 5 + + + 350,-1 + + + + + + wxALL + 5 + + icons/16x16/control_eject.png + Eject + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + 1,3 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + + 0 + 3 + 0 + 0 + 2 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 75,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + New + icons/16x16/drive_add.png + 0 + + + + + + + wxALL + 5 + + Browse + icons/16x16/folder.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL|wxEXPAND + 5 + + + 350,-1 + + + + + + wxALL + 5 + + icons/16x16/control_eject.png + Eject + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + 1,3 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + + 0 + 3 + 0 + 0 + 2 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + 75,-1 + + -1 + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + New + icons/16x16/drive_add.png + 0 + + + + + + + wxALL + 5 + + Browse + icons/16x16/folder.png + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL|wxEXPAND + 5 + + + 350,-1 + + + + + + wxALL + 5 + + icons/16x16/control_eject.png + Eject + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + 1,3 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + + New Hard Disc + 1 + + + 0 + 1 + 0 + 0 + + + + + wxEXPAND + 5 + + 0 + 3 + 0 + 0 + 1 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + 80,-1 + + -1 + + + + + wxALL + 5 + + 350,-1 + + + + + + wxALL + 5 + + + icons/16x16/folder.png + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + + 1 + + + + + wxALL + 5 + + + 0 + + + + + + + + + + Hard Disc Parameters + 1 + + + 0 + 1 + 0 + 0 + + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxEXPAND + 5 + + 0 + 3 + 0 + 0 + 1 + + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + 0 + 4 + 0 + 0 + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL | wxALIGN_CENTER_VERTICAL + 5 + + + -1 + + + + + wxALL + 5 + + + 350,-1 + + + + + + + wxEXPAND + 5 + 0,0 + + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + + 1 + + + + + wxALL + 5 + + + 0 + + + + + + + + + + PCem Configuration Manager + 1 + + 1 + 1 + 0 + 0 + 0 + 0 + + + wxALL|wxEXPAND + 5 + + 2 + 2 + 0 + 0 + 0 + 0 + + + wxEXPAND + 5 + + wxVERTICAL + + + wxALL|wxEXPAND + 5 + + + 250,300 + + + + + + + + wxEXPAND + 5 + + wxVERTICAL + + + wxALL + 5 + + + Load + icons/32x32/control_play_blue.png + 1 + + + + + wxALL + 5 + + + Configure + icons/32x32/setting_tools.png + 0 + + + + + wxEXPAND + 5 + 0,0 + + + + wxALL + 5 + + + Configure Host + icons/32x32/widescreen.png + 0 + + + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + New + icons/32x32/computer_add.png + 0 + + + + + wxALL + 5 + + + Rename + icons/32x32/computer_edit.png + 0 + + + + + wxALL + 5 + + + Copy + icons/32x32/computer_go.png + 0 + + + + + wxALL + 5 + + + Delete + icons/32x32/computer_delete.png + 0 + + + + + + + wxALL + 5 + + + Quit + icons/32x32/door_in.png + 0 + + + + + + + + + + PCem Shader Manager + 1 + + + + wxALL + 5 + + wxHORIZONTAL + + wxALL + 0 + + + 300,350 + + + + wxEXPAND + 0 + + wxVERTICAL + + + wxALL + 0 + + + + + + + wxALL + 0 + + + + + + + + wxEXPAND + + + + wxALL + 0 + + + + + + + wxALL + 0 + + + + + + + wxALL + 0 + + + + + + + + wxEXPAND + + + + wxALL + 0 + + + + + + wxALL + 0 + + + 1 + + + + wxALL + 0 + + + + + + + + + + + + + + + PCem + 1 + + + wxVERTICAL + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + + + + + wxALIGN_CENTER|wxALL + 5 + + + -1 + + + + + + + wxALL + 5 + + + 0 + + + + + wxEXPAND + 5 + + + wxALIGN_CENTER_HORIZONTAL|wxALL + 5 + + + 1 + + + + wxALIGN_CENTER_HORIZONTAL|wxALL + 5 + + + + + + + + + + + + + Custom resolution + 1 + + + wxVERTICAL + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxALL + 5 + + + 640 + 1 + 16384 + + + + + wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + 480 + 1 + 16384 + + + + + + + wxEXPAND | wxALL + 5 + + + + + + + wxEXPAND + 5 + + + wxALIGN_CENTER_HORIZONTAL|wxALL + 5 + + + 1 + + + + wxALIGN_CENTER_HORIZONTAL|wxALL + 5 + + + + + + + + + + + + + + 1 + + + wxVERTICAL + + + wxALL + 5 + + + -1 + + + + + wxEXPAND | wxALL + 5 + + + + + + + wxALL + 5 + + + 1 + + + + + + + + + 499,175 + Host Configuration + 1 + + wxVERTICAL + + + wxEXPAND | wxALL + 5 + + + + 0 + 1 + 0 + 0 + + + + + wxEXPAND | wxALL + 5 + + + + 0 + icons/32x32/network_ethernet.png + + + + 0 + 2 + 0 + 0 + + + + + wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + 550,-1 + + + + + + + wxALL + 5 + + + -1 + + + + + wxALL + 5 + + + 550,-1 + Combo! + + + + + + + + + + + wxEXPAND + 5 + + wxHORIZONTAL + + + wxEXPAND + 5 + 0,0 + + + + wxEXPAND + 5 + + + wxALIGN_CENTER_HORIZONTAL|wxALL + 5 + + + + + + wxALIGN_CENTER_HORIZONTAL|wxALL + 5 + + + + + + + + + + + + + + diff --git a/src/pc87306.c b/src/pc87306.c new file mode 100644 index 0000000..91b95e0 --- /dev/null +++ b/src/pc87306.c @@ -0,0 +1,205 @@ +#include "ibm.h" +#include "fdc.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" + +#include "pc87306.h" + +typedef struct pc87306_t +{ + int first_read; + int cur_addr; + + uint8_t regs[32]; + + uint8_t gpio_1, gpio_2; +} pc87306_t; + +static pc87306_t pc87306_global; + +#define REG_FER 0x00 +#define REG_FAR 0x01 +#define REG_GPBA 0x0f +#define REG_SCF0 0x12 +#define REG_PNP0 0x1b + +#define FER_LPT_ENA (1 << 0) +#define FER_COM1_ENA (1 << 1) +#define FER_COM2_ENA (1 << 2) +#define FER_FDC_ENA (1 << 3) + +static uint16_t get_com_addr(pc87306_t *pc87306, int reg) +{ + switch (reg) + { + case 0: + return 0x3f8; + case 1: + return 0x2f8; + case 2: + switch (pc87306->regs[REG_FAR] >> 6) + { + case 0: + return 0x3e8; + case 1: + return 0x338; + case 2: + return 0x2e8; + case 3: + return 0x220; + } + break; + case 3: + switch (pc87306->regs[REG_FAR] >> 6) + { + case 0: + return 0x2e8; + case 1: + return 0x238; + case 2: + return 0x2e0; + case 3: + return 0x228; + } + break; + } + fatal("get_com_addr invalid\n"); + return 0xff; +} + +static uint8_t pc87306_gpio_read(uint16_t port, void *p) +{ + pc87306_t *pc87306 = (pc87306_t *)p; + uint8_t temp; + + if (!(port & 1)) + temp = pc87306->gpio_1; + else + temp = pc87306->gpio_2; + +// pclog("Read GPIO %04x %02x\n", port, temp); + return temp; +} + +static void pc87306_gpio_write(uint16_t port, uint8_t val, void *p) +{ + pc87306_t *pc87306 = (pc87306_t *)p; + +// pclog("Write GPIO %04x %02x\n", port, val); + if (!(port & 1)) + pc87306->gpio_1 = val; +} + +static uint8_t pc87306_read(uint16_t port, void *p) +{ + pc87306_t *pc87306 = (pc87306_t *)p; + + if (!(port & 1)) + { + if (pc87306->first_read) + { + pc87306->first_read = 0; + return 0x88; /*ID*/ + } + return pc87306->cur_addr; + } + else + { + pc87306->regs[8] = 0x70; +// pclog("PC87306 read %02x %02x %04x:%04x\n", pc87306->cur_addr, pc87306->regs[pc87306->cur_addr], CS,cpu_state.pc); +// if (pc87306->cur_addr == 0) +// output = 3; + return pc87306->regs[pc87306->cur_addr]; + } +} + +static void pc87306_write(uint16_t port, uint8_t val, void *p) +{ + pc87306_t *pc87306 = (pc87306_t *)p; +//pclog("pc87306_write: port=%04x val=%02x %04x:%04x\n", port, val, CS,cpu_state.pc); + if (!(port & 1)) + pc87306->cur_addr = val & 0x1f; + else + { + uint16_t old_gpio_addr = pc87306_global.regs[REG_GPBA] << 2; + + pc87306->regs[pc87306->cur_addr] = val; + +// pclog("PC87306 write %02x %02x\n", pc87306->cur_addr, val); + + fdc_remove(); + if (pc87306->regs[REG_FER] & FER_FDC_ENA) + fdc_add(); + serial1_remove(); + if (pc87306->regs[REG_FER] & FER_COM1_ENA) + { + uint16_t addr = get_com_addr(pc87306, (pc87306->regs[REG_FAR] >> 2) & 3); + + switch ((pc87306->regs[REG_FAR] >> 2) & 3) + { + case 0: case 2: + serial1_set(addr, 4); + break; + case 1: case 3: + serial1_set(addr, 3); + break; + } + } + serial2_remove(); + if (pc87306->regs[REG_FER] & FER_COM2_ENA) + { + uint16_t addr = get_com_addr(pc87306, (pc87306->regs[REG_FAR] >> 4) & 3); + + switch ((pc87306->regs[REG_FAR] >> 4) & 3) + { + case 0: case 2: + serial2_set(addr, 4); + break; + case 1: case 3: + serial2_set(addr, 3); + break; + } + } + lpt1_remove(); + lpt2_remove(); + if (pc87306->regs[REG_FER] & FER_LPT_ENA) + { + int reg; + + reg = pc87306->regs[REG_FAR] & 3; + reg |= (pc87306->regs[REG_PNP0] & 0x30) >> 2; + + switch (reg) + { + case 0x0: case 0x8: + case 0x4: case 0x5: case 0x6: case 0x7: + lpt1_init(0x378); + break; + case 0x1: case 0x9: + lpt1_init(0x3bc); + break; + case 0x2: case 0xa: + case 0xc: case 0xd: case 0xe: case 0xf: + lpt1_init(0x278); + break; + } + } + io_removehandler(old_gpio_addr, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, &pc87306_global); + io_sethandler(pc87306_global.regs[REG_GPBA] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, &pc87306_global); + } +} + +void pc87306_init(uint16_t port) +{ + memset(&pc87306_global, 0, sizeof(pc87306_t)); + + pc87306_global.first_read = 1; + io_sethandler(port, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, &pc87306_global); + pc87306_global.regs[REG_FER] = 0; + pc87306_global.regs[REG_FAR] = 0x10; + pc87306_global.regs[REG_GPBA] = 0x78 >> 2; + pc87306_global.regs[REG_SCF0] = 0x30; + pc87306_global.gpio_2 = 0xff; // this is a mask only, output will be defined by zappa_brdconfig and endeavor_brdconfig in intel.c + io_sethandler(0x0078, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, &pc87306_global); +} diff --git a/src/pc87306.h b/src/pc87306.h new file mode 100644 index 0000000..17fdc59 --- /dev/null +++ b/src/pc87306.h @@ -0,0 +1 @@ +void pc87306_init(uint16_t addr); diff --git a/src/pc87307.c b/src/pc87307.c new file mode 100644 index 0000000..e4f8ed4 --- /dev/null +++ b/src/pc87307.c @@ -0,0 +1,151 @@ +#include "ibm.h" + +#include "fdc.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" +#include "pc87307.h" + +typedef struct pc87307_t +{ + int cur_reg; + int cur_device; + + uint8_t superio_cfg1, superio_cfg2; + + struct + { + int enable; + uint16_t addr; + int irq; + int dma; + } dev[9]; +} pc87307_t; + +static pc87307_t pc87307_global; + +#define DEV_KBC 0 +#define DEV_MOUSE 1 +#define DEV_RTC 2 +#define DEV_FDC 3 +#define DEV_LPT 4 +#define DEV_COM2 5 +#define DEV_COM1 6 +#define DEV_GPIO 7 +#define DEV_POWER 8 + +#define REG_DEVICE 0x07 +#define REG_SID 0x20 +#define REG_SUPERIO_CFG1 0x21 +#define REG_SUPERIO_CFG2 0x22 +#define REG_ENABLE 0x30 +#define REG_ADDRHI 0x60 +#define REG_ADDRLO 0x61 +#define REG_IRQ 0x70 +#define REG_DMA 0x74 + +void pc87307_write(uint16_t port, uint8_t val, void *p) +{ + pc87307_t *pc87307 = (pc87307_t *)p; + + if (port == 0x2e) + pc87307->cur_reg = val; + else + { + if (pc87307->cur_reg == REG_DEVICE) + pc87307->cur_device = val & 0xf; + else + { +// pclog("Write pc87307 %02x [%02x] %02x\n", pc87307->cur_reg, pc87307->cur_device, val); + switch (pc87307->cur_reg) + { + case REG_ENABLE: + if (pc87307->cur_device <= DEV_POWER) + pc87307->dev[pc87307->cur_device].enable = val; + break; + case REG_ADDRLO: + if (pc87307->cur_device <= DEV_POWER) + pc87307->dev[pc87307->cur_device].addr = (pc87307->dev[pc87307->cur_device].addr & 0xff00) | val; + break; + case REG_ADDRHI: + if (pc87307->cur_device <= DEV_POWER) + pc87307->dev[pc87307->cur_device].addr = (pc87307->dev[pc87307->cur_device].addr & 0x00ff) | (val << 8); + break; + case REG_IRQ: + if (pc87307->cur_device <= DEV_POWER) + pc87307->dev[pc87307->cur_device].irq = val; + break; + case REG_DMA: + if (pc87307->cur_device <= DEV_POWER) + pc87307->dev[pc87307->cur_device].dma = val; + break; + } + + switch (pc87307->cur_device) + { + case DEV_FDC: + fdc_remove(); + if (pc87307->dev[DEV_FDC].enable & 1) + fdc_add(); + break; + case DEV_COM1: + serial1_remove(); + if (pc87307->dev[DEV_COM1].enable & 1) + serial1_set(pc87307->dev[DEV_COM1].addr, pc87307->dev[DEV_COM1].irq); + break; + case DEV_COM2: + serial2_remove(); + if (pc87307->dev[DEV_COM2].enable & 1) + serial2_set(pc87307->dev[DEV_COM2].addr, pc87307->dev[DEV_COM2].irq); + break; + case DEV_LPT: + lpt1_remove(); + lpt2_remove(); + if (pc87307->dev[DEV_LPT].enable & 1) + lpt1_init(pc87307->dev[DEV_LPT].addr); + break; + } + } + } +} + +uint8_t pc87307_read(uint16_t port, void *p) +{ + pc87307_t *pc87307 = (pc87307_t *)p; + +// pclog("Read pc87307 %02x\n", pc87307->cur_reg); + + switch (pc87307->cur_reg) + { + case REG_DEVICE: + return pc87307->cur_device; + case REG_SID: + return 0x20; /*PC87307*/ + case REG_SUPERIO_CFG1: + return pc87307->superio_cfg1; + case REG_SUPERIO_CFG2: + return pc87307->superio_cfg2; + case REG_ENABLE: + return pc87307->dev[pc87307->cur_device].enable; + case REG_ADDRLO: + return pc87307->dev[pc87307->cur_device].addr & 0xff; + case REG_ADDRHI: + return pc87307->dev[pc87307->cur_device].addr >> 8; + case REG_IRQ: + return pc87307->dev[pc87307->cur_device].irq; + case REG_DMA: + return pc87307->dev[pc87307->cur_device].dma; + } + + return 0xff; +} + +void pc87307_init(uint16_t base) +{ + memset(&pc87307_global, 0, sizeof(pc87307_t)); + + pc87307_global.superio_cfg1 = 0x04; + pc87307_global.superio_cfg2 = 0x03; + + io_sethandler(base, 0x0002, pc87307_read, NULL, NULL, pc87307_write, NULL, NULL, &pc87307_global); +} diff --git a/src/pc87307.h b/src/pc87307.h new file mode 100644 index 0000000..e28ae8a --- /dev/null +++ b/src/pc87307.h @@ -0,0 +1 @@ +void pc87307_init(uint16_t addr); diff --git a/src/pci.c b/src/pci.c index 73b455a..0775965 100644 --- a/src/pci.c +++ b/src/pci.c @@ -1,14 +1,20 @@ #include "ibm.h" +#include "device.h" #include "io.h" #include "mem.h" +#include "pic.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_irq_routing[32]; +static int pci_irq_active[32]; +static int pci_irqs[4]; +static int pci_card_valid[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) @@ -116,8 +122,46 @@ uint8_t pci_type2_read(uint16_t port, void *priv) } return 0xff; } - -void pci_init(int type, int min_card, int max_card) + +void pci_set_irq_routing(int pci_int, int irq) +{ + pci_irqs[pci_int - 1] = irq; +// pclog("pci_set_irq_routing: pci_int=%i irq=%i\n", pci_int, irq); +} + +void pci_set_card_routing(int card, int pci_int) +{ + pci_irq_routing[card] = pci_int; +// pclog("pci_irq_routing: card=%i pci_int=%i\n", card, pci_int); +} + +void pci_set_irq(int card, int pci_int) +{ +// pclog("pci_set_irq: card=%i irq_routing=%i\n", card, pci_irq_routing[card]); + if (pci_irq_routing[card]) + { + int irq = ((pci_int - PCI_INTA) + (pci_irq_routing[card] - PCI_INTA)) & 3; +// pclog(" irq=%i pci_irqs=%i active=%i\n", irq, pci_irqs[irq], pci_irq_active[card]); + if (pci_irqs[irq] != PCI_IRQ_DISABLED && !pci_irq_active[card]) + picint(1 << pci_irqs[irq]); + pci_irq_active[card] = 1; + } +} + +void pci_clear_irq(int card, int pci_int) +{ +// pclog("pci_clear_irq: card=%i irq_routing=%i\n", card, pci_irq_routing[card]); + if (pci_irq_routing[card]) + { + int irq = ((pci_int - PCI_INTA) + (pci_irq_routing[card] - PCI_INTA)) & 3; +// pclog(" irq=%i pci_irqs=%i active=%i\n", irq, pci_irqs[irq], pci_irq_active[card]); + if (pci_irqs[irq] != PCI_IRQ_DISABLED && pci_irq_active[card]) + picintc(1 << pci_irqs[irq]); + pci_irq_active[card] = 0; + } +} + +void pci_init(int type) { int c; @@ -139,10 +183,18 @@ void pci_init(int type, int min_card, int max_card) pci_card_read[c] = NULL; pci_card_write[c] = NULL; pci_priv[c] = NULL; + pci_irq_routing[c] = 0; + pci_irq_active[c] = 0; + pci_card_valid[c] = 0; } - pci_min_card = min_card; - pci_max_card = max_card; + for (c = 0; c < 4; c++) + pci_irqs[c] = PCI_IRQ_DISABLED; +} + +void pci_slot(int card) +{ + pci_card_valid[card] = 1; } 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) @@ -152,18 +204,27 @@ void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), 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 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) + return -1; + + for (c = 0; c < 32; c++) { - if (!pci_card_read[c] && !pci_card_write[c]) + if (pci_card_valid[c] && !pci_card_read[c] && !pci_card_write[c]) { pci_card_read[c] = read; pci_card_write[c] = write; pci_priv[c] = priv; - return; + return c; } } + + if (current_device_name) + warning("Failed to initialise PCI device '%s' due to insufficient available slots", current_device_name); + else + warning("Failed to initialise PCI device due to insufficient available slots"); + return -1; } diff --git a/src/pci.h b/src/pci.h index f248c36..142b793 100644 --- a/src/pci.h +++ b/src/pci.h @@ -1,6 +1,11 @@ -void pci_init(int type, int min_card, int max_card); +void pci_init(int type); +void pci_slot(int 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); +int pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); +void pci_set_irq_routing(int card, int irq); +void pci_set_card_routing(int card, int pci_int); +void pci_set_irq(int card, int pci_int); +void pci_clear_irq(int card, int pci_int); #define PCI_REG_COMMAND 0x04 @@ -10,4 +15,11 @@ void pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int #define PCI_CONFIG_TYPE_1 1 #define PCI_CONFIG_TYPE_2 2 +#define PCI_INTA 1 +#define PCI_INTB 2 +#define PCI_INTC 3 +#define PCI_INTD 4 + +#define PCI_IRQ_DISABLED -1 + extern int pci_burst_time, pci_nonburst_time; diff --git a/src/pgc_palettes.h b/src/pgc_palettes.h new file mode 100644 index 0000000..2d3d0dd --- /dev/null +++ b/src/pgc_palettes.h @@ -0,0 +1,1554 @@ +/* Palette 0: Default */ + { + makecol(0x00,0x00,0x00), + makecol(0x11,0x11,0x11), + makecol(0x22,0x22,0x22), + makecol(0x33,0x33,0x33), + makecol(0x44,0x44,0x44), + makecol(0x55,0x55,0x55), + makecol(0x66,0x66,0x66), + makecol(0x77,0x77,0x77), + makecol(0x88,0x88,0x88), + makecol(0x99,0x99,0x99), + makecol(0xaa,0xaa,0xaa), + makecol(0xbb,0xbb,0xbb), + makecol(0xcc,0xcc,0xcc), + makecol(0xdd,0xdd,0xdd), + makecol(0xee,0xee,0xee), + makecol(0xff,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x22,0x00), + makecol(0x00,0x44,0x00), + makecol(0x00,0x66,0x00), + makecol(0x00,0x88,0x00), + makecol(0x00,0xaa,0x00), + makecol(0x00,0xcc,0x00), + makecol(0x00,0xee,0x00), + makecol(0x00,0xff,0x00), + makecol(0x22,0xff,0x22), + makecol(0x44,0xff,0x44), + makecol(0x66,0xff,0x66), + makecol(0x88,0xff,0x88), + makecol(0xaa,0xff,0xaa), + makecol(0xcc,0xff,0xcc), + makecol(0xee,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x00,0x22,0x11), + makecol(0x00,0x44,0x22), + makecol(0x00,0x66,0x33), + makecol(0x00,0x88,0x44), + makecol(0x00,0xaa,0x55), + makecol(0x00,0xcc,0x66), + makecol(0x00,0xee,0x77), + makecol(0x00,0xff,0x88), + makecol(0x22,0xff,0x99), + makecol(0x44,0xff,0xaa), + makecol(0x66,0xff,0xbb), + makecol(0x88,0xff,0xcc), + makecol(0xaa,0xff,0xdd), + makecol(0xcc,0xff,0xee), + makecol(0xee,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x22,0x22), + makecol(0x00,0x44,0x44), + makecol(0x00,0x66,0x66), + makecol(0x00,0x88,0x88), + makecol(0x00,0xaa,0xaa), + makecol(0x00,0xcc,0xcc), + makecol(0x00,0xee,0xee), + makecol(0x00,0xff,0xff), + makecol(0x22,0xff,0xff), + makecol(0x44,0xff,0xff), + makecol(0x66,0xff,0xff), + makecol(0x88,0xff,0xff), + makecol(0xaa,0xff,0xff), + makecol(0xcc,0xff,0xff), + makecol(0xee,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x11,0x22), + makecol(0x00,0x22,0x44), + makecol(0x00,0x33,0x66), + makecol(0x00,0x44,0x88), + makecol(0x00,0x55,0xaa), + makecol(0x00,0x66,0xcc), + makecol(0x00,0x77,0xee), + makecol(0x00,0x88,0xff), + makecol(0x22,0x99,0xff), + makecol(0x44,0xaa,0xff), + makecol(0x66,0xbb,0xff), + makecol(0x88,0xcc,0xff), + makecol(0xaa,0xdd,0xff), + makecol(0xcc,0xee,0xff), + makecol(0xee,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x22), + makecol(0x00,0x00,0x44), + makecol(0x00,0x00,0x66), + makecol(0x00,0x00,0x88), + makecol(0x00,0x00,0xaa), + makecol(0x00,0x00,0xcc), + makecol(0x00,0x00,0xee), + makecol(0x00,0x00,0xff), + makecol(0x22,0x22,0xff), + makecol(0x44,0x44,0xff), + makecol(0x66,0x66,0xff), + makecol(0x88,0x88,0xff), + makecol(0xaa,0xaa,0xff), + makecol(0xcc,0xcc,0xff), + makecol(0xee,0xee,0xff), + makecol(0x00,0x00,0x00), + makecol(0x11,0x00,0x22), + makecol(0x22,0x00,0x44), + makecol(0x33,0x00,0x66), + makecol(0x44,0x00,0x88), + makecol(0x55,0x00,0xaa), + makecol(0x66,0x00,0xcc), + makecol(0x77,0x00,0xee), + makecol(0x88,0x00,0xff), + makecol(0x99,0x22,0xff), + makecol(0xaa,0x44,0xff), + makecol(0xbb,0x66,0xff), + makecol(0xcc,0x88,0xff), + makecol(0xdd,0xaa,0xff), + makecol(0xee,0xcc,0xff), + makecol(0xff,0xee,0xff), + makecol(0x00,0x00,0x00), + makecol(0x22,0x00,0x22), + makecol(0x44,0x00,0x44), + makecol(0x66,0x00,0x66), + makecol(0x88,0x00,0x88), + makecol(0xaa,0x00,0xaa), + makecol(0xcc,0x00,0xcc), + makecol(0xee,0x00,0xee), + makecol(0xff,0x00,0xff), + makecol(0xff,0x22,0xff), + makecol(0xff,0x44,0xff), + makecol(0xff,0x66,0xff), + makecol(0xff,0x88,0xff), + makecol(0xff,0xaa,0xff), + makecol(0xff,0xcc,0xff), + makecol(0xff,0xee,0xff), + makecol(0x00,0x00,0x00), + makecol(0x22,0x00,0x11), + makecol(0x44,0x00,0x22), + makecol(0x66,0x00,0x33), + makecol(0x88,0x00,0x44), + makecol(0xaa,0x00,0x55), + makecol(0xcc,0x00,0x66), + makecol(0xee,0x00,0x77), + makecol(0xff,0x00,0x88), + makecol(0xff,0x22,0x99), + makecol(0xff,0x44,0xaa), + makecol(0xff,0x66,0xbb), + makecol(0xff,0x88,0xcc), + makecol(0xff,0xaa,0xdd), + makecol(0xff,0xcc,0xee), + makecol(0xff,0xee,0xff), + makecol(0x00,0x00,0x00), + makecol(0x22,0x00,0x00), + makecol(0x44,0x00,0x00), + makecol(0x66,0x00,0x00), + makecol(0x88,0x00,0x00), + makecol(0xaa,0x00,0x00), + makecol(0xcc,0x00,0x00), + makecol(0xee,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x22,0x22), + makecol(0xff,0x44,0x44), + makecol(0xff,0x66,0x66), + makecol(0xff,0x88,0x88), + makecol(0xff,0xaa,0xaa), + makecol(0xff,0xcc,0xcc), + makecol(0xff,0xee,0xee), + makecol(0x00,0x00,0x00), + makecol(0x22,0x11,0x00), + makecol(0x44,0x22,0x00), + makecol(0x66,0x33,0x00), + makecol(0x88,0x44,0x00), + makecol(0xaa,0x55,0x00), + makecol(0xcc,0x66,0x00), + makecol(0xee,0x77,0x00), + makecol(0xff,0x88,0x00), + makecol(0xff,0x99,0x22), + makecol(0xff,0xaa,0x44), + makecol(0xff,0xbb,0x66), + makecol(0xff,0xcc,0x88), + makecol(0xff,0xdd,0xaa), + makecol(0xff,0xee,0xcc), + makecol(0xff,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x22,0x22,0x00), + makecol(0x44,0x44,0x00), + makecol(0x66,0x66,0x00), + makecol(0x88,0x88,0x00), + makecol(0xaa,0xaa,0x00), + makecol(0xcc,0xcc,0x00), + makecol(0xee,0xee,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x22), + makecol(0xff,0xff,0x44), + makecol(0xff,0xff,0x66), + makecol(0xff,0xff,0x88), + makecol(0xff,0xff,0xaa), + makecol(0xff,0xff,0xcc), + makecol(0xff,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x11,0x22,0x00), + makecol(0x22,0x44,0x00), + makecol(0x33,0x66,0x00), + makecol(0x44,0x88,0x00), + makecol(0x55,0xaa,0x00), + makecol(0x66,0xcc,0x00), + makecol(0x77,0xee,0x00), + makecol(0x88,0xff,0x00), + makecol(0x99,0xff,0x22), + makecol(0xaa,0xff,0x44), + makecol(0xbb,0xff,0x66), + makecol(0xcc,0xff,0x88), + makecol(0xdd,0xff,0xaa), + makecol(0xee,0xff,0xcc), + makecol(0xff,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x00,0x11,0x00), + makecol(0x11,0x33,0x11), + makecol(0x11,0x44,0x11), + makecol(0x22,0x66,0x22), + makecol(0x22,0x77,0x22), + makecol(0x33,0x99,0x33), + makecol(0x33,0xaa,0x33), + makecol(0x44,0xcc,0x44), + makecol(0x55,0xcc,0x55), + makecol(0x77,0xdd,0x77), + makecol(0x88,0xdd,0x88), + makecol(0xaa,0xee,0xaa), + makecol(0xbb,0xee,0xbb), + makecol(0xdd,0xff,0xdd), + makecol(0xee,0xff,0xee), + makecol(0x00,0x00,0x00), + makecol(0x11,0x00,0x00), + makecol(0x33,0x11,0x11), + makecol(0x44,0x11,0x11), + makecol(0x66,0x22,0x22), + makecol(0x77,0x22,0x22), + makecol(0x99,0x33,0x33), + makecol(0xaa,0x33,0x33), + makecol(0xcc,0x44,0x44), + makecol(0xcc,0x55,0x55), + makecol(0xdd,0x77,0x77), + makecol(0xdd,0x88,0x88), + makecol(0xee,0xaa,0xaa), + makecol(0xee,0xbb,0xbb), + makecol(0xff,0xdd,0xdd), + makecol(0xff,0xee,0xee), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x11), + makecol(0x11,0x11,0x33), + makecol(0x11,0x11,0x44), + makecol(0x22,0x22,0x66), + makecol(0x22,0x22,0x77), + makecol(0x33,0x33,0x99), + makecol(0x33,0x33,0xaa), + makecol(0x44,0x44,0xcc), + makecol(0x55,0x55,0xcc), + makecol(0x77,0x77,0xdd), + makecol(0x88,0x88,0xdd), + makecol(0xaa,0xaa,0xee), + makecol(0xbb,0xbb,0xee), + makecol(0xdd,0xdd,0xff), + makecol(0xee,0xee,0xff), + }, +/* Palette 1: 16-colour palette */ + { + makecol(0x88,0x66,0xdd), + makecol(0x00,0x00,0x00), + makecol(0x44,0x77,0x22), + makecol(0x77,0xaa,0x44), + makecol(0x00,0x77,0x00), + makecol(0x00,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x99,0xee,0x66), + makecol(0x77,0x77,0x77), + makecol(0xff,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x44,0x77,0x22), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x77,0xaa,0x44), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x77), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x99,0xee,0x66), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0x77,0x77,0x77), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + makecol(0xff,0xff,0xff), + }, +/* Palette 2: 2-3-3 truecolour */ + { + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x33), + makecol(0x00,0x00,0x55), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x99), + makecol(0x00,0x00,0xbb), + makecol(0x00,0x00,0xdd), + makecol(0x00,0x00,0xff), + makecol(0x33,0x00,0x00), + makecol(0x33,0x00,0x33), + makecol(0x33,0x00,0x55), + makecol(0x33,0x00,0x77), + makecol(0x33,0x00,0x99), + makecol(0x33,0x00,0xbb), + makecol(0x33,0x00,0xdd), + makecol(0x33,0x00,0xff), + makecol(0x55,0x00,0x00), + makecol(0x55,0x00,0x33), + makecol(0x55,0x00,0x55), + makecol(0x55,0x00,0x77), + makecol(0x55,0x00,0x99), + makecol(0x55,0x00,0xbb), + makecol(0x55,0x00,0xdd), + makecol(0x55,0x00,0xff), + makecol(0x77,0x00,0x00), + makecol(0x77,0x00,0x33), + makecol(0x77,0x00,0x55), + makecol(0x77,0x00,0x77), + makecol(0x77,0x00,0x99), + makecol(0x77,0x00,0xbb), + makecol(0x77,0x00,0xdd), + makecol(0x77,0x00,0xff), + makecol(0x99,0x00,0x00), + makecol(0x99,0x00,0x33), + makecol(0x99,0x00,0x55), + makecol(0x99,0x00,0x77), + makecol(0x99,0x00,0x99), + makecol(0x99,0x00,0xbb), + makecol(0x99,0x00,0xdd), + makecol(0x99,0x00,0xff), + makecol(0xbb,0x00,0x00), + makecol(0xbb,0x00,0x33), + makecol(0xbb,0x00,0x55), + makecol(0xbb,0x00,0x77), + makecol(0xbb,0x00,0x99), + makecol(0xbb,0x00,0xbb), + makecol(0xbb,0x00,0xdd), + makecol(0xbb,0x00,0xff), + makecol(0xdd,0x00,0x00), + makecol(0xdd,0x00,0x33), + makecol(0xdd,0x00,0x55), + makecol(0xdd,0x00,0x77), + makecol(0xdd,0x00,0x99), + makecol(0xdd,0x00,0xbb), + makecol(0xdd,0x00,0xdd), + makecol(0xdd,0x00,0xff), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x33), + makecol(0xff,0x00,0x55), + makecol(0xff,0x00,0x77), + makecol(0xff,0x00,0x99), + makecol(0xff,0x00,0xbb), + makecol(0xff,0x00,0xdd), + makecol(0xff,0x00,0xff), + makecol(0x00,0x55,0x00), + makecol(0x00,0x55,0x33), + makecol(0x00,0x55,0x55), + makecol(0x00,0x55,0x77), + makecol(0x00,0x55,0x99), + makecol(0x00,0x55,0xbb), + makecol(0x00,0x55,0xdd), + makecol(0x00,0x55,0xff), + makecol(0x33,0x55,0x00), + makecol(0x33,0x55,0x33), + makecol(0x33,0x55,0x55), + makecol(0x33,0x55,0x77), + makecol(0x33,0x55,0x99), + makecol(0x33,0x55,0xbb), + makecol(0x33,0x55,0xdd), + makecol(0x33,0x55,0xff), + makecol(0x55,0x55,0x00), + makecol(0x55,0x55,0x33), + makecol(0x55,0x55,0x55), + makecol(0x55,0x55,0x77), + makecol(0x55,0x55,0x99), + makecol(0x55,0x55,0xbb), + makecol(0x55,0x55,0xdd), + makecol(0x55,0x55,0xff), + makecol(0x77,0x55,0x00), + makecol(0x77,0x55,0x33), + makecol(0x77,0x55,0x55), + makecol(0x77,0x55,0x77), + makecol(0x77,0x55,0x99), + makecol(0x77,0x55,0xbb), + makecol(0x77,0x55,0xdd), + makecol(0x77,0x55,0xff), + makecol(0x99,0x55,0x00), + makecol(0x99,0x55,0x33), + makecol(0x99,0x55,0x55), + makecol(0x99,0x55,0x77), + makecol(0x99,0x55,0x99), + makecol(0x99,0x55,0xbb), + makecol(0x99,0x55,0xdd), + makecol(0x99,0x55,0xff), + makecol(0xbb,0x55,0x00), + makecol(0xbb,0x55,0x33), + makecol(0xbb,0x55,0x55), + makecol(0xbb,0x55,0x77), + makecol(0xbb,0x55,0x99), + makecol(0xbb,0x55,0xbb), + makecol(0xbb,0x55,0xdd), + makecol(0xbb,0x55,0xff), + makecol(0xdd,0x55,0x00), + makecol(0xdd,0x55,0x33), + makecol(0xdd,0x55,0x55), + makecol(0xdd,0x55,0x77), + makecol(0xdd,0x55,0x99), + makecol(0xdd,0x55,0xbb), + makecol(0xdd,0x55,0xdd), + makecol(0xdd,0x55,0xff), + makecol(0xff,0x55,0x00), + makecol(0xff,0x55,0x33), + makecol(0xff,0x55,0x55), + makecol(0xff,0x55,0x77), + makecol(0xff,0x55,0x99), + makecol(0xff,0x55,0xbb), + makecol(0xff,0x55,0xdd), + makecol(0xff,0x55,0xff), + makecol(0x00,0xaa,0x00), + makecol(0x00,0xaa,0x33), + makecol(0x00,0xaa,0x55), + makecol(0x00,0xaa,0x77), + makecol(0x00,0xaa,0x99), + makecol(0x00,0xaa,0xbb), + makecol(0x00,0xaa,0xdd), + makecol(0x00,0xaa,0xff), + makecol(0x33,0xaa,0x00), + makecol(0x33,0xaa,0x33), + makecol(0x33,0xaa,0x55), + makecol(0x33,0xaa,0x77), + makecol(0x33,0xaa,0x99), + makecol(0x33,0xaa,0xbb), + makecol(0x33,0xaa,0xdd), + makecol(0x33,0xaa,0xff), + makecol(0x55,0xaa,0x00), + makecol(0x55,0xaa,0x33), + makecol(0x55,0xaa,0x55), + makecol(0x55,0xaa,0x77), + makecol(0x55,0xaa,0x99), + makecol(0x55,0xaa,0xbb), + makecol(0x55,0xaa,0xdd), + makecol(0x55,0xaa,0xff), + makecol(0x77,0xaa,0x00), + makecol(0x77,0xaa,0x33), + makecol(0x77,0xaa,0x55), + makecol(0x77,0xaa,0x77), + makecol(0x77,0xaa,0x99), + makecol(0x77,0xaa,0xbb), + makecol(0x77,0xaa,0xdd), + makecol(0x77,0xaa,0xff), + makecol(0x99,0xaa,0x00), + makecol(0x99,0xaa,0x33), + makecol(0x99,0xaa,0x55), + makecol(0x99,0xaa,0x77), + makecol(0x99,0xaa,0x99), + makecol(0x99,0xaa,0xbb), + makecol(0x99,0xaa,0xdd), + makecol(0x99,0xaa,0xff), + makecol(0xbb,0xaa,0x00), + makecol(0xbb,0xaa,0x33), + makecol(0xbb,0xaa,0x55), + makecol(0xbb,0xaa,0x77), + makecol(0xbb,0xaa,0x99), + makecol(0xbb,0xaa,0xbb), + makecol(0xbb,0xaa,0xdd), + makecol(0xbb,0xaa,0xff), + makecol(0xdd,0xaa,0x00), + makecol(0xdd,0xaa,0x33), + makecol(0xdd,0xaa,0x55), + makecol(0xdd,0xaa,0x77), + makecol(0xdd,0xaa,0x99), + makecol(0xdd,0xaa,0xbb), + makecol(0xdd,0xaa,0xdd), + makecol(0xdd,0xaa,0xff), + makecol(0xff,0xaa,0x00), + makecol(0xff,0xaa,0x33), + makecol(0xff,0xaa,0x55), + makecol(0xff,0xaa,0x77), + makecol(0xff,0xaa,0x99), + makecol(0xff,0xaa,0xbb), + makecol(0xff,0xaa,0xdd), + makecol(0xff,0xaa,0xee), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x33), + makecol(0x00,0xff,0x55), + makecol(0x00,0xff,0x77), + makecol(0x00,0xff,0x99), + makecol(0x00,0xff,0xbb), + makecol(0x00,0xff,0xdd), + makecol(0x00,0xff,0xff), + makecol(0x33,0xff,0x00), + makecol(0x33,0xff,0x33), + makecol(0x33,0xff,0x55), + makecol(0x33,0xff,0x77), + makecol(0x33,0xff,0x99), + makecol(0x33,0xff,0xbb), + makecol(0x33,0xff,0xdd), + makecol(0x33,0xff,0xff), + makecol(0x55,0xff,0x00), + makecol(0x55,0xff,0x33), + makecol(0x55,0xff,0x55), + makecol(0x55,0xff,0x77), + makecol(0x55,0xff,0x99), + makecol(0x55,0xff,0xbb), + makecol(0x55,0xff,0xdd), + makecol(0x55,0xff,0xff), + makecol(0x77,0xff,0x00), + makecol(0x77,0xff,0x33), + makecol(0x77,0xff,0x55), + makecol(0x77,0xff,0x77), + makecol(0x77,0xff,0x99), + makecol(0x77,0xff,0xbb), + makecol(0x77,0xff,0xdd), + makecol(0x77,0xff,0xff), + makecol(0x99,0xff,0x00), + makecol(0x99,0xff,0x33), + makecol(0x99,0xff,0x55), + makecol(0x99,0xff,0x77), + makecol(0x99,0xff,0x99), + makecol(0x99,0xff,0xbb), + makecol(0x99,0xff,0xdd), + makecol(0x99,0xff,0xff), + makecol(0xbb,0xff,0x00), + makecol(0xbb,0xff,0x33), + makecol(0xbb,0xff,0x55), + makecol(0xbb,0xff,0x77), + makecol(0xbb,0xff,0x99), + makecol(0xbb,0xff,0xbb), + makecol(0xbb,0xff,0xdd), + makecol(0xbb,0xff,0xff), + makecol(0xdd,0xff,0x00), + makecol(0xdd,0xff,0x33), + makecol(0xdd,0xff,0x55), + makecol(0xdd,0xff,0x77), + makecol(0xdd,0xff,0x99), + makecol(0xdd,0xff,0xbb), + makecol(0xdd,0xff,0xdd), + makecol(0xdd,0xff,0xff), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x33), + makecol(0xff,0xff,0x55), + makecol(0xff,0xff,0x77), + makecol(0xff,0xff,0x99), + makecol(0xff,0xff,0xbb), + makecol(0xff,0xff,0xdd), + makecol(0xff,0xff,0xff), + }, +/* Palette 3: 3-2-3 truecolour */ + { + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x33), + makecol(0x00,0x00,0x55), + makecol(0x00,0x00,0x77), + makecol(0x00,0x00,0x99), + makecol(0x00,0x00,0xbb), + makecol(0x00,0x00,0xdd), + makecol(0x00,0x00,0xff), + makecol(0x55,0x00,0x00), + makecol(0x55,0x00,0x33), + makecol(0x55,0x00,0x55), + makecol(0x55,0x00,0x77), + makecol(0x55,0x00,0x99), + makecol(0x55,0x00,0xbb), + makecol(0x55,0x00,0xdd), + makecol(0x55,0x00,0xff), + makecol(0xaa,0x00,0x00), + makecol(0xaa,0x00,0x33), + makecol(0xaa,0x00,0x55), + makecol(0xaa,0x00,0x77), + makecol(0xaa,0x00,0x99), + makecol(0xaa,0x00,0xbb), + makecol(0xaa,0x00,0xdd), + makecol(0xaa,0x00,0xff), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x33), + makecol(0xff,0x00,0x55), + makecol(0xff,0x00,0x77), + makecol(0xff,0x00,0x99), + makecol(0xff,0x00,0xbb), + makecol(0xff,0x00,0xdd), + makecol(0xff,0x00,0xff), + makecol(0x00,0x33,0x00), + makecol(0x00,0x33,0x33), + makecol(0x00,0x33,0x55), + makecol(0x00,0x33,0x77), + makecol(0x00,0x33,0x99), + makecol(0x00,0x33,0xbb), + makecol(0x00,0x33,0xdd), + makecol(0x00,0x33,0xff), + makecol(0x55,0x33,0x00), + makecol(0x55,0x33,0x33), + makecol(0x55,0x33,0x55), + makecol(0x55,0x33,0x77), + makecol(0x55,0x33,0x99), + makecol(0x55,0x33,0xbb), + makecol(0x55,0x33,0xdd), + makecol(0x55,0x33,0xff), + makecol(0xaa,0x33,0x00), + makecol(0xaa,0x33,0x33), + makecol(0xaa,0x33,0x55), + makecol(0xaa,0x33,0x77), + makecol(0xaa,0x33,0x99), + makecol(0xaa,0x33,0xbb), + makecol(0xaa,0x33,0xdd), + makecol(0xaa,0x33,0xff), + makecol(0xff,0x33,0x00), + makecol(0xff,0x33,0x33), + makecol(0xff,0x33,0x55), + makecol(0xff,0x33,0x77), + makecol(0xff,0x33,0x99), + makecol(0xff,0x33,0xbb), + makecol(0xff,0x33,0xdd), + makecol(0xff,0x33,0xff), + makecol(0x00,0x55,0x00), + makecol(0x00,0x55,0x33), + makecol(0x00,0x55,0x55), + makecol(0x00,0x55,0x77), + makecol(0x00,0x55,0x99), + makecol(0x00,0x55,0xbb), + makecol(0x00,0x55,0xdd), + makecol(0x00,0x55,0xff), + makecol(0x55,0x55,0x00), + makecol(0x55,0x55,0x33), + makecol(0x55,0x55,0x55), + makecol(0x55,0x55,0x77), + makecol(0x55,0x55,0x99), + makecol(0x55,0x55,0xbb), + makecol(0x55,0x55,0xdd), + makecol(0x55,0x55,0xff), + makecol(0xaa,0x55,0x00), + makecol(0xaa,0x55,0x33), + makecol(0xaa,0x55,0x55), + makecol(0xaa,0x55,0x77), + makecol(0xaa,0x55,0x99), + makecol(0xaa,0x55,0xbb), + makecol(0xaa,0x55,0xdd), + makecol(0xaa,0x55,0xff), + makecol(0xff,0x55,0x00), + makecol(0xff,0x55,0x33), + makecol(0xff,0x55,0x55), + makecol(0xff,0x55,0x77), + makecol(0xff,0x55,0x99), + makecol(0xff,0x55,0xbb), + makecol(0xff,0x55,0xdd), + makecol(0xff,0x55,0xff), + makecol(0x00,0x77,0x00), + makecol(0x00,0x77,0x33), + makecol(0x00,0x77,0x55), + makecol(0x00,0x77,0x77), + makecol(0x00,0x77,0x99), + makecol(0x00,0x77,0xbb), + makecol(0x00,0x77,0xdd), + makecol(0x00,0x77,0xff), + makecol(0x55,0x77,0x00), + makecol(0x55,0x77,0x33), + makecol(0x55,0x77,0x55), + makecol(0x55,0x77,0x77), + makecol(0x55,0x77,0x99), + makecol(0x55,0x77,0xbb), + makecol(0x55,0x77,0xdd), + makecol(0x55,0x77,0xff), + makecol(0xaa,0x77,0x00), + makecol(0xaa,0x77,0x33), + makecol(0xaa,0x77,0x55), + makecol(0xaa,0x77,0x77), + makecol(0xaa,0x77,0x99), + makecol(0xaa,0x77,0xbb), + makecol(0xaa,0x77,0xdd), + makecol(0xaa,0x77,0xff), + makecol(0xff,0x77,0x00), + makecol(0xff,0x77,0x33), + makecol(0xff,0x77,0x55), + makecol(0xff,0x77,0x77), + makecol(0xff,0x77,0x99), + makecol(0xff,0x77,0xbb), + makecol(0xff,0x77,0xdd), + makecol(0xff,0x77,0xff), + makecol(0x00,0x99,0x00), + makecol(0x00,0x99,0x33), + makecol(0x00,0x99,0x55), + makecol(0x00,0x99,0x77), + makecol(0x00,0x99,0x99), + makecol(0x00,0x99,0xbb), + makecol(0x00,0x99,0xdd), + makecol(0x00,0x99,0xff), + makecol(0x55,0x99,0x00), + makecol(0x55,0x99,0x33), + makecol(0x55,0x99,0x55), + makecol(0x55,0x99,0x77), + makecol(0x55,0x99,0x99), + makecol(0x55,0x99,0xbb), + makecol(0x55,0x99,0xdd), + makecol(0x55,0x99,0xff), + makecol(0xaa,0x99,0x00), + makecol(0xaa,0x99,0x33), + makecol(0xaa,0x99,0x55), + makecol(0xaa,0x99,0x77), + makecol(0xaa,0x99,0x99), + makecol(0xaa,0x99,0xbb), + makecol(0xaa,0x99,0xdd), + makecol(0xaa,0x99,0xff), + makecol(0xff,0x99,0x00), + makecol(0xff,0x99,0x33), + makecol(0xff,0x99,0x55), + makecol(0xff,0x99,0x77), + makecol(0xff,0x99,0x99), + makecol(0xff,0x99,0xbb), + makecol(0xff,0x99,0xdd), + makecol(0xff,0x99,0xff), + makecol(0x00,0xbb,0x00), + makecol(0x00,0xbb,0x33), + makecol(0x00,0xbb,0x55), + makecol(0x00,0xbb,0x77), + makecol(0x00,0xbb,0x99), + makecol(0x00,0xbb,0xbb), + makecol(0x00,0xbb,0xdd), + makecol(0x00,0xbb,0xff), + makecol(0x55,0xbb,0x00), + makecol(0x55,0xbb,0x33), + makecol(0x55,0xbb,0x55), + makecol(0x55,0xbb,0x77), + makecol(0x55,0xbb,0x99), + makecol(0x55,0xbb,0xbb), + makecol(0x55,0xbb,0xdd), + makecol(0x55,0xbb,0xff), + makecol(0xaa,0xbb,0x00), + makecol(0xaa,0xbb,0x33), + makecol(0xaa,0xbb,0x55), + makecol(0xaa,0xbb,0x77), + makecol(0xaa,0xbb,0x99), + makecol(0xaa,0xbb,0xbb), + makecol(0xaa,0xbb,0xdd), + makecol(0xaa,0xbb,0xff), + makecol(0xff,0xbb,0x00), + makecol(0xff,0xbb,0x33), + makecol(0xff,0xbb,0x55), + makecol(0xff,0xbb,0x77), + makecol(0xff,0xbb,0x99), + makecol(0xff,0xbb,0xbb), + makecol(0xff,0xbb,0xdd), + makecol(0xff,0xbb,0xff), + makecol(0x00,0xdd,0x00), + makecol(0x00,0xdd,0x33), + makecol(0x00,0xdd,0x55), + makecol(0x00,0xdd,0x77), + makecol(0x00,0xdd,0x99), + makecol(0x00,0xdd,0xbb), + makecol(0x00,0xdd,0xdd), + makecol(0x00,0xdd,0xff), + makecol(0x55,0xdd,0x00), + makecol(0x55,0xdd,0x33), + makecol(0x55,0xdd,0x55), + makecol(0x55,0xdd,0x77), + makecol(0x55,0xdd,0x99), + makecol(0x55,0xdd,0xbb), + makecol(0x55,0xdd,0xdd), + makecol(0x55,0xdd,0xff), + makecol(0xaa,0xdd,0x00), + makecol(0xaa,0xdd,0x33), + makecol(0xaa,0xdd,0x55), + makecol(0xaa,0xdd,0x77), + makecol(0xaa,0xdd,0x99), + makecol(0xaa,0xdd,0xbb), + makecol(0xaa,0xdd,0xdd), + makecol(0xaa,0xdd,0xff), + makecol(0xff,0xdd,0x00), + makecol(0xff,0xdd,0x33), + makecol(0xff,0xdd,0x55), + makecol(0xff,0xdd,0x77), + makecol(0xff,0xdd,0x99), + makecol(0xff,0xdd,0xbb), + makecol(0xff,0xdd,0xdd), + makecol(0xff,0xdd,0xff), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x33), + makecol(0x00,0xff,0x55), + makecol(0x00,0xff,0x77), + makecol(0x00,0xff,0x99), + makecol(0x00,0xff,0xbb), + makecol(0x00,0xff,0xdd), + makecol(0x00,0xff,0xff), + makecol(0x55,0xff,0x00), + makecol(0x55,0xff,0x33), + makecol(0x55,0xff,0x55), + makecol(0x55,0xff,0x77), + makecol(0x55,0xff,0x99), + makecol(0x55,0xff,0xbb), + makecol(0x55,0xff,0xdd), + makecol(0x55,0xff,0xff), + makecol(0xaa,0xff,0x00), + makecol(0xaa,0xff,0x33), + makecol(0xaa,0xff,0x55), + makecol(0xaa,0xff,0x77), + makecol(0xaa,0xff,0x99), + makecol(0xaa,0xff,0xbb), + makecol(0xaa,0xff,0xdd), + makecol(0xaa,0xff,0xff), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x33), + makecol(0xff,0xff,0x55), + makecol(0xff,0xff,0x77), + makecol(0xff,0xff,0x99), + makecol(0xff,0xff,0xbb), + makecol(0xff,0xff,0xdd), + makecol(0xff,0xff,0xff), + }, +/* Palette 4: 3-3-2 truecolour */ + { + makecol(0x00, 0x00, 0x00), + makecol(0x00, 0x00, 0x55), + makecol(0x00, 0x00, 0xaa), + makecol(0x00, 0x00, 0xff), + makecol(0x00, 0x33, 0x00), + makecol(0x00, 0x33, 0x55), + makecol(0x00, 0x33, 0xaa), + makecol(0x00, 0x33, 0xff), + makecol(0x00, 0x55, 0x00), + makecol(0x00, 0x55, 0x55), + makecol(0x00, 0x55, 0xaa), + makecol(0x00, 0x55, 0xff), + makecol(0x00, 0x77, 0x00), + makecol(0x00, 0x77, 0x55), + makecol(0x00, 0x77, 0xaa), + makecol(0x00, 0x77, 0xff), + makecol(0x00, 0x99, 0x00), + makecol(0x00, 0x99, 0x55), + makecol(0x00, 0x99, 0xaa), + makecol(0x00, 0x99, 0xff), + makecol(0x00, 0xbb, 0x00), + makecol(0x00, 0xbb, 0x55), + makecol(0x00, 0xbb, 0xaa), + makecol(0x00, 0xbb, 0xff), + makecol(0x00, 0xdd, 0x00), + makecol(0x00, 0xdd, 0x55), + makecol(0x00, 0xdd, 0xaa), + makecol(0x00, 0xdd, 0xff), + makecol(0x00, 0xff, 0x00), + makecol(0x00, 0xff, 0x55), + makecol(0x00, 0xff, 0xaa), + makecol(0x00, 0xff, 0xff), + makecol(0x33, 0x00, 0x00), + makecol(0x33, 0x00, 0x55), + makecol(0x33, 0x00, 0xaa), + makecol(0x33, 0x00, 0xff), + makecol(0x33, 0x33, 0x00), + makecol(0x33, 0x33, 0x55), + makecol(0x33, 0x33, 0xaa), + makecol(0x33, 0x33, 0xff), + makecol(0x33, 0x55, 0x00), + makecol(0x33, 0x55, 0x55), + makecol(0x33, 0x55, 0xaa), + makecol(0x33, 0x55, 0xff), + makecol(0x33, 0x77, 0x00), + makecol(0x33, 0x77, 0x55), + makecol(0x33, 0x77, 0xaa), + makecol(0x33, 0x77, 0xff), + makecol(0x33, 0x99, 0x00), + makecol(0x33, 0x99, 0x55), + makecol(0x33, 0x99, 0xaa), + makecol(0x33, 0x99, 0xff), + makecol(0x33, 0xbb, 0x00), + makecol(0x33, 0xbb, 0x55), + makecol(0x33, 0xbb, 0xaa), + makecol(0x33, 0xbb, 0xff), + makecol(0x33, 0xdd, 0x00), + makecol(0x33, 0xdd, 0x55), + makecol(0x33, 0xdd, 0xaa), + makecol(0x33, 0xdd, 0xff), + makecol(0x33, 0xff, 0x00), + makecol(0x33, 0xff, 0x55), + makecol(0x33, 0xff, 0xaa), + makecol(0x33, 0xff, 0xff), + makecol(0x55, 0x00, 0x00), + makecol(0x55, 0x00, 0x55), + makecol(0x55, 0x00, 0xaa), + makecol(0x55, 0x00, 0xff), + makecol(0x55, 0x33, 0x00), + makecol(0x55, 0x33, 0x55), + makecol(0x55, 0x33, 0xaa), + makecol(0x55, 0x33, 0xff), + makecol(0x55, 0x55, 0x00), + makecol(0x55, 0x55, 0x55), + makecol(0x55, 0x55, 0xaa), + makecol(0x55, 0x55, 0xff), + makecol(0x55, 0x77, 0x00), + makecol(0x55, 0x77, 0x55), + makecol(0x55, 0x77, 0xaa), + makecol(0x55, 0x77, 0xff), + makecol(0x55, 0x99, 0x00), + makecol(0x55, 0x99, 0x55), + makecol(0x55, 0x99, 0xaa), + makecol(0x55, 0x99, 0xff), + makecol(0x55, 0xbb, 0x00), + makecol(0x55, 0xbb, 0x55), + makecol(0x55, 0xbb, 0xaa), + makecol(0x55, 0xbb, 0xff), + makecol(0x55, 0xdd, 0x00), + makecol(0x55, 0xdd, 0x55), + makecol(0x55, 0xdd, 0xaa), + makecol(0x55, 0xdd, 0xff), + makecol(0x55, 0xff, 0x00), + makecol(0x55, 0xff, 0x55), + makecol(0x55, 0xff, 0xaa), + makecol(0x55, 0xff, 0xff), + makecol(0x77, 0x00, 0x00), + makecol(0x77, 0x00, 0x55), + makecol(0x77, 0x00, 0xaa), + makecol(0x77, 0x00, 0xff), + makecol(0x77, 0x33, 0x00), + makecol(0x77, 0x33, 0x55), + makecol(0x77, 0x33, 0xaa), + makecol(0x77, 0x33, 0xff), + makecol(0x77, 0x55, 0x00), + makecol(0x77, 0x55, 0x55), + makecol(0x77, 0x55, 0xaa), + makecol(0x77, 0x55, 0xff), + makecol(0x77, 0x77, 0x00), + makecol(0x77, 0x77, 0x55), + makecol(0x77, 0x77, 0xaa), + makecol(0x77, 0x77, 0xff), + makecol(0x77, 0x99, 0x00), + makecol(0x77, 0x99, 0x55), + makecol(0x77, 0x99, 0xaa), + makecol(0x77, 0x99, 0xff), + makecol(0x77, 0xbb, 0x00), + makecol(0x77, 0xbb, 0x55), + makecol(0x77, 0xbb, 0xaa), + makecol(0x77, 0xbb, 0xff), + makecol(0x77, 0xdd, 0x00), + makecol(0x77, 0xdd, 0x55), + makecol(0x77, 0xdd, 0xaa), + makecol(0x77, 0xdd, 0xff), + makecol(0x77, 0xff, 0x00), + makecol(0x77, 0xff, 0x55), + makecol(0x77, 0xff, 0xaa), + makecol(0x77, 0xff, 0xff), + makecol(0x99, 0x00, 0x00), + makecol(0x99, 0x00, 0x55), + makecol(0x99, 0x00, 0xaa), + makecol(0x99, 0x00, 0xff), + makecol(0x99, 0x33, 0x00), + makecol(0x99, 0x33, 0x55), + makecol(0x99, 0x33, 0xaa), + makecol(0x99, 0x33, 0xff), + makecol(0x99, 0x55, 0x00), + makecol(0x99, 0x55, 0x55), + makecol(0x99, 0x55, 0xaa), + makecol(0x99, 0x55, 0xff), + makecol(0x99, 0x77, 0x00), + makecol(0x99, 0x77, 0x55), + makecol(0x99, 0x77, 0xaa), + makecol(0x99, 0x77, 0xff), + makecol(0x99, 0x99, 0x00), + makecol(0x99, 0x99, 0x55), + makecol(0x99, 0x99, 0xaa), + makecol(0x99, 0x99, 0xff), + makecol(0x99, 0xbb, 0x00), + makecol(0x99, 0xbb, 0x55), + makecol(0x99, 0xbb, 0xaa), + makecol(0x99, 0xbb, 0xff), + makecol(0x99, 0xdd, 0x00), + makecol(0x99, 0xdd, 0x55), + makecol(0x99, 0xdd, 0xaa), + makecol(0x99, 0xdd, 0xff), + makecol(0x99, 0xff, 0x00), + makecol(0x99, 0xff, 0x55), + makecol(0x99, 0xff, 0xaa), + makecol(0x99, 0xff, 0xff), + makecol(0xbb, 0x00, 0x00), + makecol(0xbb, 0x00, 0x55), + makecol(0xbb, 0x00, 0xaa), + makecol(0xbb, 0x00, 0xff), + makecol(0xbb, 0x33, 0x00), + makecol(0xbb, 0x33, 0x55), + makecol(0xbb, 0x33, 0xaa), + makecol(0xbb, 0x33, 0xff), + makecol(0xbb, 0x55, 0x00), + makecol(0xbb, 0x55, 0x55), + makecol(0xbb, 0x55, 0xaa), + makecol(0xbb, 0x55, 0xff), + makecol(0xbb, 0x77, 0x00), + makecol(0xbb, 0x77, 0x55), + makecol(0xbb, 0x77, 0xaa), + makecol(0xbb, 0x77, 0xff), + makecol(0xbb, 0x99, 0x00), + makecol(0xbb, 0x99, 0x55), + makecol(0xbb, 0x99, 0xaa), + makecol(0xbb, 0x99, 0xff), + makecol(0xbb, 0xbb, 0x00), + makecol(0xbb, 0xbb, 0x55), + makecol(0xbb, 0xbb, 0xaa), + makecol(0xbb, 0xbb, 0xff), + makecol(0xbb, 0xdd, 0x00), + makecol(0xbb, 0xdd, 0x55), + makecol(0xbb, 0xdd, 0xaa), + makecol(0xbb, 0xdd, 0xff), + makecol(0xbb, 0xff, 0x00), + makecol(0xbb, 0xff, 0x55), + makecol(0xbb, 0xff, 0xaa), + makecol(0xbb, 0xff, 0xff), + makecol(0xdd, 0x00, 0x00), + makecol(0xdd, 0x00, 0x55), + makecol(0xdd, 0x00, 0xaa), + makecol(0xdd, 0x00, 0xff), + makecol(0xdd, 0x33, 0x00), + makecol(0xdd, 0x33, 0x55), + makecol(0xdd, 0x33, 0xaa), + makecol(0xdd, 0x33, 0xff), + makecol(0xdd, 0x55, 0x00), + makecol(0xdd, 0x55, 0x55), + makecol(0xdd, 0x55, 0xaa), + makecol(0xdd, 0x55, 0xff), + makecol(0xdd, 0x77, 0x00), + makecol(0xdd, 0x77, 0x55), + makecol(0xdd, 0x77, 0xaa), + makecol(0xdd, 0x77, 0xff), + makecol(0xdd, 0x99, 0x00), + makecol(0xdd, 0x99, 0x55), + makecol(0xdd, 0x99, 0xaa), + makecol(0xdd, 0x99, 0xff), + makecol(0xdd, 0xbb, 0x00), + makecol(0xdd, 0xbb, 0x55), + makecol(0xdd, 0xbb, 0xaa), + makecol(0xdd, 0xbb, 0xff), + makecol(0xdd, 0xdd, 0x00), + makecol(0xdd, 0xdd, 0x55), + makecol(0xdd, 0xdd, 0xaa), + makecol(0xdd, 0xdd, 0xff), + makecol(0xdd, 0xff, 0x00), + makecol(0xdd, 0xff, 0x55), + makecol(0xdd, 0xff, 0xaa), + makecol(0xdd, 0xff, 0xff), + makecol(0xff, 0x00, 0x00), + makecol(0xff, 0x00, 0x55), + makecol(0xff, 0x00, 0xaa), + makecol(0xff, 0x00, 0xff), + makecol(0xff, 0x33, 0x00), + makecol(0xff, 0x33, 0x55), + makecol(0xff, 0x33, 0xaa), + makecol(0xff, 0x33, 0xff), + makecol(0xff, 0x55, 0x00), + makecol(0xff, 0x55, 0x55), + makecol(0xff, 0x55, 0xaa), + makecol(0xff, 0x55, 0xff), + makecol(0xff, 0x77, 0x00), + makecol(0xff, 0x77, 0x55), + makecol(0xff, 0x77, 0xaa), + makecol(0xff, 0x77, 0xff), + makecol(0xff, 0x99, 0x00), + makecol(0xff, 0x99, 0x55), + makecol(0xff, 0x99, 0xaa), + makecol(0xff, 0x99, 0xff), + makecol(0xff, 0xbb, 0x00), + makecol(0xff, 0xbb, 0x55), + makecol(0xff, 0xbb, 0xaa), + makecol(0xff, 0xbb, 0xff), + makecol(0xff, 0xdd, 0x00), + makecol(0xff, 0xdd, 0x55), + makecol(0xff, 0xdd, 0xaa), + makecol(0xff, 0xdd, 0xff), + makecol(0xff, 0xff, 0x00), + makecol(0xff, 0xff, 0x55), + makecol(0xff, 0xff, 0xaa), + makecol(0xff, 0xff, 0xff), + }, +/* Palette 5: 6x6x6 colour cube */ + { + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x33), + makecol(0x00,0x00,0x66), + makecol(0x00,0x00,0x99), + makecol(0x00,0x00,0xcc), + makecol(0x00,0x00,0xff), + makecol(0x33,0x00,0x00), + makecol(0x33,0x00,0x33), + makecol(0x33,0x00,0x66), + makecol(0x33,0x00,0x99), + makecol(0x33,0x00,0xcc), + makecol(0x33,0x00,0xff), + makecol(0x66,0x00,0x00), + makecol(0x66,0x00,0x33), + makecol(0x66,0x00,0x66), + makecol(0x66,0x00,0x99), + makecol(0x66,0x00,0xcc), + makecol(0x66,0x00,0xff), + makecol(0x99,0x00,0x00), + makecol(0x99,0x00,0x33), + makecol(0x99,0x00,0x66), + makecol(0x99,0x00,0x99), + makecol(0x99,0x00,0xcc), + makecol(0x99,0x00,0xff), + makecol(0xcc,0x00,0x00), + makecol(0xcc,0x00,0x33), + makecol(0xcc,0x00,0x66), + makecol(0xcc,0x00,0x99), + makecol(0xcc,0x00,0xcc), + makecol(0xcc,0x00,0xff), + makecol(0xff,0x00,0x00), + makecol(0xff,0x00,0x33), + makecol(0xff,0x00,0x66), + makecol(0xff,0x00,0x99), + makecol(0xff,0x00,0xcc), + makecol(0xff,0x00,0xff), + makecol(0x00,0x33,0x00), + makecol(0x00,0x33,0x33), + makecol(0x00,0x33,0x66), + makecol(0x00,0x33,0x99), + makecol(0x00,0x33,0xcc), + makecol(0x00,0x33,0xff), + makecol(0x33,0x33,0x00), + makecol(0x33,0x33,0x33), + makecol(0x33,0x33,0x66), + makecol(0x33,0x33,0x99), + makecol(0x33,0x33,0xcc), + makecol(0x33,0x33,0xff), + makecol(0x66,0x33,0x00), + makecol(0x66,0x33,0x33), + makecol(0x66,0x33,0x66), + makecol(0x66,0x33,0x99), + makecol(0x66,0x33,0xcc), + makecol(0x66,0x33,0xff), + makecol(0x99,0x33,0x00), + makecol(0x99,0x33,0x33), + makecol(0x99,0x33,0x66), + makecol(0x99,0x33,0x99), + makecol(0x99,0x33,0xcc), + makecol(0x99,0x33,0xff), + makecol(0xcc,0x33,0x00), + makecol(0xcc,0x33,0x33), + makecol(0xcc,0x33,0x66), + makecol(0xcc,0x33,0x99), + makecol(0xcc,0x33,0xcc), + makecol(0xcc,0x33,0xff), + makecol(0xff,0x33,0x00), + makecol(0xff,0x33,0x33), + makecol(0xff,0x33,0x66), + makecol(0xff,0x33,0x99), + makecol(0xff,0x33,0xcc), + makecol(0xff,0x33,0xff), + makecol(0x00,0x66,0x00), + makecol(0x00,0x66,0x33), + makecol(0x00,0x66,0x66), + makecol(0x00,0x66,0x99), + makecol(0x00,0x66,0xcc), + makecol(0x00,0x66,0xff), + makecol(0x33,0x66,0x00), + makecol(0x33,0x66,0x33), + makecol(0x33,0x66,0x66), + makecol(0x33,0x66,0x99), + makecol(0x33,0x66,0xcc), + makecol(0x33,0x66,0xff), + makecol(0x66,0x66,0x00), + makecol(0x66,0x66,0x33), + makecol(0x66,0x66,0x66), + makecol(0x66,0x66,0x99), + makecol(0x66,0x66,0xcc), + makecol(0x66,0x66,0xff), + makecol(0x99,0x66,0x00), + makecol(0x99,0x66,0x33), + makecol(0x99,0x66,0x66), + makecol(0x99,0x66,0x99), + makecol(0x99,0x66,0xcc), + makecol(0x99,0x66,0xff), + makecol(0xcc,0x66,0x00), + makecol(0xcc,0x66,0x33), + makecol(0xcc,0x66,0x66), + makecol(0xcc,0x66,0x99), + makecol(0xcc,0x66,0xcc), + makecol(0xcc,0x66,0xff), + makecol(0xff,0x66,0x00), + makecol(0xff,0x66,0x33), + makecol(0xff,0x66,0x66), + makecol(0xff,0x66,0x99), + makecol(0xff,0x66,0xcc), + makecol(0xff,0x66,0xff), + makecol(0x00,0x99,0x00), + makecol(0x00,0x99,0x33), + makecol(0x00,0x99,0x66), + makecol(0x00,0x99,0x99), + makecol(0x00,0x99,0xcc), + makecol(0x00,0x99,0xff), + makecol(0x33,0x99,0x00), + makecol(0x33,0x99,0x33), + makecol(0x33,0x99,0x66), + makecol(0x33,0x99,0x99), + makecol(0x33,0x99,0xcc), + makecol(0x33,0x99,0xff), + makecol(0x66,0x99,0x00), + makecol(0x66,0x99,0x33), + makecol(0x66,0x99,0x66), + makecol(0x66,0x99,0x99), + makecol(0x66,0x99,0xcc), + makecol(0x66,0x99,0xff), + makecol(0x99,0x99,0x00), + makecol(0x99,0x99,0x33), + makecol(0x99,0x99,0x66), + makecol(0x99,0x99,0x99), + makecol(0x99,0x99,0xcc), + makecol(0x99,0x99,0xff), + makecol(0xcc,0x99,0x00), + makecol(0xcc,0x99,0x33), + makecol(0xcc,0x99,0x66), + makecol(0xcc,0x99,0x99), + makecol(0xcc,0x99,0xcc), + makecol(0xcc,0x99,0xff), + makecol(0xff,0x99,0x00), + makecol(0xff,0x99,0x33), + makecol(0xff,0x99,0x66), + makecol(0xff,0x99,0x99), + makecol(0xff,0x99,0xcc), + makecol(0xff,0x99,0xff), + makecol(0x00,0xcc,0x00), + makecol(0x00,0xcc,0x33), + makecol(0x00,0xcc,0x66), + makecol(0x00,0xcc,0x99), + makecol(0x00,0xcc,0xcc), + makecol(0x00,0xcc,0xff), + makecol(0x33,0xcc,0x00), + makecol(0x33,0xcc,0x33), + makecol(0x33,0xcc,0x66), + makecol(0x33,0xcc,0x99), + makecol(0x33,0xcc,0xcc), + makecol(0x33,0xcc,0xff), + makecol(0x66,0xcc,0x00), + makecol(0x66,0xcc,0x33), + makecol(0x66,0xcc,0x66), + makecol(0x66,0xcc,0x99), + makecol(0x66,0xcc,0xcc), + makecol(0x66,0xcc,0xff), + makecol(0x99,0xcc,0x00), + makecol(0x99,0xcc,0x33), + makecol(0x99,0xcc,0x66), + makecol(0x99,0xcc,0x99), + makecol(0x99,0xcc,0xcc), + makecol(0x99,0xcc,0xff), + makecol(0xcc,0xcc,0x00), + makecol(0xcc,0xcc,0x33), + makecol(0xcc,0xcc,0x66), + makecol(0xcc,0xcc,0x99), + makecol(0xcc,0xcc,0xcc), + makecol(0xcc,0xcc,0xff), + makecol(0xff,0xcc,0x00), + makecol(0xff,0xcc,0x33), + makecol(0xff,0xcc,0x66), + makecol(0xff,0xcc,0x99), + makecol(0xff,0xcc,0xcc), + makecol(0xff,0xcc,0xff), + makecol(0x00,0xff,0x00), + makecol(0x00,0xff,0x33), + makecol(0x00,0xff,0x66), + makecol(0x00,0xff,0x99), + makecol(0x00,0xff,0xcc), + makecol(0x00,0xff,0xff), + makecol(0x33,0xff,0x00), + makecol(0x33,0xff,0x33), + makecol(0x33,0xff,0x66), + makecol(0x33,0xff,0x99), + makecol(0x33,0xff,0xcc), + makecol(0x33,0xff,0xff), + makecol(0x66,0xff,0x00), + makecol(0x66,0xff,0x33), + makecol(0x66,0xff,0x66), + makecol(0x66,0xff,0x99), + makecol(0x66,0xff,0xcc), + makecol(0x66,0xff,0xff), + makecol(0x99,0xff,0x00), + makecol(0x99,0xff,0x33), + makecol(0x99,0xff,0x66), + makecol(0x99,0xff,0x99), + makecol(0x99,0xff,0xcc), + makecol(0x99,0xff,0xff), + makecol(0xcc,0xff,0x00), + makecol(0xcc,0xff,0x33), + makecol(0xcc,0xff,0x66), + makecol(0xcc,0xff,0x99), + makecol(0xcc,0xff,0xcc), + makecol(0xcc,0xff,0xff), + makecol(0xff,0xff,0x00), + makecol(0xff,0xff,0x33), + makecol(0xff,0xff,0x66), + makecol(0xff,0xff,0x99), + makecol(0xff,0xff,0xcc), + makecol(0xff,0xff,0xff), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + makecol(0x00,0x00,0x00), + }, diff --git a/src/pic.c b/src/pic.c index 26918f3..c93def6 100644 --- a/src/pic.c +++ b/src/pic.c @@ -4,20 +4,25 @@ #include "pit.h" #include "video.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); + if (AT || romset == ROM_XI8088) + { + 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); + } 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); + pic_intpending = (pic.pend & ~pic.mask) & ~pic.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));*/ } @@ -36,6 +41,8 @@ void pic_reset() pic.mask2=0; pic2.pend=pic2.ins=0; pic_intpending = 0; + pic.level_sensitive = 0; + pic2.level_sensitive = 0; } void pic_update_mask(uint8_t *mask, uint8_t ins) @@ -63,7 +70,7 @@ static void pic_autoeoi() pic.ins&=~(1<0xFF) + if ((AT || romset == ROM_XI8088) && num>0xFF) { pic2.pend|=(num>>8); if ((pic2.pend&~pic2.mask)&~pic2.mask2) pic.pend |= (1 << 2); } - else + else if (num <= 0xff) { pic.pend|=num; } @@ -309,7 +350,7 @@ void picintlevel(uint16_t num) { int c = 0; while (!(num & (1 << c))) c++; - if (AT && c == 2) + if ((AT || romset == ROM_XI8088) && num == (1 << 2)) { c = 9; num = 1 << 9; @@ -335,7 +376,7 @@ void picintc(uint16_t num) if (!num) return; while (!(num & (1 << c))) c++; - if (AT && c == 2) + if ((AT || romset == ROM_XI8088) && num == (1 << 2)) { c = 9; num = 1 << 9; @@ -343,13 +384,13 @@ void picintc(uint16_t num) // pclog("INTC %04X %i\n", num, c); pic_current[c]=0; - if (num > 0xff) + if ((AT || romset == ROM_XI8088) && num > 0xff) { pic2.pend &= ~(num >> 8); if (!((pic2.pend&~pic2.mask)&~pic2.mask2)) pic.pend &= ~(1 << 2); } - else + else if(num <= 0xff) { pic.pend&=~num; } @@ -360,60 +401,44 @@ uint8_t picinterrupt() { uint8_t temp=pic.pend&~pic.mask; int c; - for (c = 0; c < 2; c++) + for (c = 0; c < 8; c++) { - if (temp & (1 << c)) + if ((AT || romset == ROM_XI8088) && (temp & (1 << 2))) { - pic.pend &= ~(1 << c); - pic.ins |= (1 << c); - pic_update_mask(&pic.mask2, pic.ins); - - pic_updatepending(); - if (!c) - pit_set_gate(&pit2, 0, 0); - - 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)) + uint8_t temp2 = pic2.pend & ~pic2.mask; + for (c = 0; c < 8; c++) { - pic2.pend &= ~(1 << c); - pic2.ins |= (1 << c); - pic_update_mask(&pic2.mask2, pic2.ins); + if (temp2 & (1 << c)) + { + if (!(pic2.level_sensitive & (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); + if (!(pic2.level_sensitive & (1 << c))) + pic.pend &= ~(1 << c); + pic.ins |= (1 << 2); /*Cascade IRQ*/ + pic_update_mask(&pic.mask2, pic.ins); - pic_updatepending(); + pic_updatepending(); - if (pic2.icw4 & 0x02) - pic2_autoeoi(); + if (pic2.icw4 & 0x02) + pic2_autoeoi(); - return c+pic2.vector; + return c+pic2.vector; + } } } - } - for (c = 3; c < 8; c++) - { - if (temp & (1 << c)) + else if (temp & (1 << c)) { - pic.pend &= ~(1 << c); + if (!(pic.level_sensitive & (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; } } diff --git a/src/pic.h b/src/pic.h index e386313..1e129f3 100644 --- a/src/pic.h +++ b/src/pic.h @@ -1,5 +1,6 @@ void pic_init(); void pic2_init(); +void pic_init_elcrx(); void pic_reset(); void picint(uint16_t num); diff --git a/src/piix.c b/src/piix.c index e51be18..4e76b26 100644 --- a/src/piix.c +++ b/src/piix.c @@ -7,21 +7,41 @@ #include "ibm.h" #include "ide.h" +#include "ide_sff8038i.h" +#include "keyboard_at.h" #include "io.h" #include "mem.h" #include "pci.h" - +#include "pic.h" #include "piix.h" +#include "piix_pm.h" -uint8_t piix_bus_master_read(uint16_t port, void *priv); -void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); +enum +{ + TYPE_PIIX = 0, + TYPE_PIIX3, + TYPE_PIIX4 +}; +static piix_t piix; static uint8_t card_piix[256], card_piix_ide[256]; +static sff_busmaster_t piix_busmaster[2]; +static uint8_t piix_rc = 0; +static void (*piix_nb_reset)(); + +#define REG_SMICNTL 0xa0 +#define REG_SMIEN 0xa2 +#define REG_SMIREQ 0xaa + +#define SMICNTL_CSMIGATE (1 << 0) +#define SMIEN_APMC (1 << 7) +#define SMIREQ_RAPMC (1 << 7) + 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) + if (func > ((piix.type == TYPE_PIIX4) ? 3 : 1)) return; if (func == 1) /*IDE*/ @@ -49,44 +69,99 @@ void piix_write(int func, int addr, uint8_t val, void *priv) 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; } 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); + io_removehandler(0, 0x10000, sff_bus_master_read, NULL, NULL, sff_bus_master_write, NULL, NULL, piix_busmaster); if (card_piix_ide[0x04] & 1) - io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + io_sethandler(base, 0x10, sff_bus_master_read, NULL, NULL, sff_bus_master_write, NULL, NULL, piix_busmaster); + } + if (addr == 4 || addr == 0x41 || addr == 0x43) + { + ide_pri_disable(); + ide_sec_disable(); + if (card_piix_ide[0x04] & 1) + { + if (card_piix_ide[0x41] & 0x80) + ide_pri_enable(); + if (card_piix_ide[0x43] & 0x80) + ide_sec_enable(); + } } // pclog("PIIX write %02X %02X\n", addr, val); } + else if (func == 2) /*USB*/ + { + /*Not implemented*/ + } + else if (func == 3) /*PM*/ + { + piix_pm_pci_write(addr, val, &piix); + } else { + if (addr >= 0x0f && addr < 0x4c) + return; + switch (addr) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0e: return; + + case 0x60: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x62: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x63: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + case REG_SMIREQ: + if (piix.type <= TYPE_PIIX3) + { + card_piix[addr] &= val; + return; + } + break; + case REG_SMIREQ+1: + if (piix.type <= TYPE_PIIX3) + { + card_piix[addr] &= val; + return; + } + break; + } card_piix[addr] = val; } @@ -95,226 +170,122 @@ void piix_write(int func, int addr, uint8_t val, void *priv) 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 > ((piix.type == TYPE_PIIX4) ? 3 : 1)) + return 0xff; if (func == 1) /*IDE*/ { // pclog("PIIX IDE read %02X %02X\n", addr, card_piix_ide[addr]); return card_piix_ide[addr]; } + else if (func == 2) /*USB*/ + return 0xff; /*Not implemented*/ + else if (func == 3) + return piix_pm_pci_read(addr, &piix); else - return card_piix[addr]; + 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) +uint8_t piix_rc_read(uint16_t port, void *p) { - piix_busmaster[channel].addr = (*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur])) & ~1; - 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); + return piix_rc; } -void piix_bus_master_write(uint16_t port, uint8_t val, void *priv) +void piix_rc_write(uint16_t port, uint8_t val, void *p) { - int channel = (port & 8) ? 1 : 0; -// pclog("PIIX Bus Master write %04X %02X %04x:%08x\n", port, val, CS, pc); - switch (port & 7) + if (val & 4) { - case 0: - if ((val & 1) && !(piix_busmaster[channel].command & 1)) /*Start*/ + if (val & 2) /*Hard reset*/ { - piix_busmaster[channel].ptr_cur = piix_busmaster[channel].ptr; - piix_bus_master_next_addr(channel); - piix_busmaster[channel].status |= 1; + piix_nb_reset(); + keyboard_at_reset(); /*Reset keyboard controller to reset system flag*/ + ide_reset_devices(); + piix.pm.timer_offset = tsc; + resetx86(); + piix.pm.apmc = piix.pm.apms = 0; } - 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; - break; - case 5: - piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffff00ff) | (val << 8); - break; - case 6: - piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xff00ffff) | (val << 16); - break; - case 7: - piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0x00ffffff) | (val << 24); - 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); - if (piix_busmaster[channel].addr < (mem_size * 1024)) - { - int count = piix_busmaster[channel].count; - if ((piix_busmaster[channel].addr + count) > (mem_size * 1024)) - count = (mem_size * 1024) - piix_busmaster[channel].addr; - memcpy(&ram[piix_busmaster[channel].addr], data + transferred, count); - } - transferred += piix_busmaster[channel].count; - piix_busmaster[channel].addr += piix_busmaster[channel].count; - piix_busmaster[channel].count = 0; - } else - { -// pclog("Transferring larger - %i bytes\n", 512 - transferred); - if (piix_busmaster[channel].addr < (mem_size * 1024)) - { - int count = 512 - transferred; - if ((piix_busmaster[channel].addr + count) > (mem_size * 1024)) - count = (mem_size * 1024) - piix_busmaster[channel].addr; - memcpy(&ram[piix_busmaster[channel].addr], data + transferred, count); - } - 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); - } + softresetx86(); } - 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) + piix_rc = val & ~4; +} + +static uint8_t piix_92_read(uint16_t port, void *p) +{ + return piix.port_92; +} +static void piix_92_write(uint16_t port, uint8_t val, void *p) +{ + if ((mem_a20_alt ^ val) & 2) { - 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); - if (piix_busmaster[channel].addr < (mem_size * 1024)) - { - int count = piix_busmaster[channel].count; - if ((piix_busmaster[channel].addr + count) > (mem_size * 1024)) - count = (mem_size * 1024) - piix_busmaster[channel].addr; - memcpy(data + transferred, &ram[piix_busmaster[channel].addr], count); - } - transferred += piix_busmaster[channel].count; - piix_busmaster[channel].addr += piix_busmaster[channel].count; - piix_busmaster[channel].count = 0; - } - else - { -// pclog("Transferring larger - %i bytes\n", 512 - transferred); - if (piix_busmaster[channel].addr < (mem_size * 1024)) - { - int count = 512 - transferred; - if ((piix_busmaster[channel].addr + count) > (mem_size * 1024)) - count = (mem_size * 1024) - piix_busmaster[channel].addr; - memcpy(data + transferred, &ram[piix_busmaster[channel].addr], count); - } - 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); - } + mem_a20_alt = val & 2; + mem_a20_recalc(); } - return 0; + if ((~piix.port_92 & val) & 1) + { + softresetx86(); + cpu_set_edx(); + } + piix.port_92 = val; } -void piix_bus_master_set_irq(int channel) +static uint8_t piix_apm_read(uint16_t port, void *p) { - piix_busmaster[channel].status |= 4; + piix_t *piix = (piix_t *)p; + uint8_t ret = 0xff; + + switch (port) + { + case 0xb2: + ret = piix->pm.apmc; + break; + + case 0xb3: + ret = piix->pm.apms; + break; + } +// pclog("piix_apm_read: port=%04x ret=%02x\n", port, ret); + return ret; } -void piix_init(int card) +static void piix_apm_write(uint16_t port, uint8_t val, void *p) { + piix_t *piix = (piix_t *)p; + +// pclog("piix_apm_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0xb2: + piix->pm.apmc = val; + if (card_piix[REG_SMIEN] & SMIEN_APMC) + { + card_piix[REG_SMIREQ] |= SMIREQ_RAPMC; +// pclog("APMC write causes SMI\n"); + if (card_piix[REG_SMICNTL] & SMICNTL_CSMIGATE) + x86_smi_trigger(); + } + break; + + case 0xb3: + piix->pm.apms = val; + break; + } +} + +static void piix_common_init(int card, int pci_a, int pci_b, int pci_c, int pci_d, void (*nb_reset)()) +{ + memset(&piix, 0, sizeof(piix_t)); + 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[0x06] = 0x80; 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*/ @@ -335,7 +306,7 @@ void piix_init(int card) 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[0x04] = 0x02; 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; @@ -344,6 +315,42 @@ void piix_init(int card) 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; + + sff_bus_master_init(piix_busmaster); - ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); + pci_set_card_routing(pci_a, PCI_INTA); + pci_set_card_routing(pci_b, PCI_INTB); + pci_set_card_routing(pci_c, PCI_INTC); + pci_set_card_routing(pci_d, PCI_INTD); + + ide_pri_disable(); + ide_sec_disable(); + + pic_init_elcrx(); + + io_sethandler(0x0cf9, 0x0001, piix_rc_read, NULL, NULL, piix_rc_write, NULL, NULL, NULL); + piix_nb_reset = nb_reset; + + piix.type = TYPE_PIIX3; +} + +void piix_init(int card, int pci_a, int pci_b, int pci_c, int pci_d, void (*nb_reset)()) +{ + piix_common_init(card, pci_a, pci_b, pci_c, pci_d, nb_reset); + + io_sethandler(0x00b2, 0x0002, piix_apm_read, NULL, NULL, piix_apm_write, NULL, NULL, &piix); +} + +void piix4_init(int card, int pci_a, int pci_b, int pci_c, int pci_d, void (*nb_reset)()) +{ + piix_init(card, pci_a, pci_b, pci_c, pci_d, nb_reset); + + piix.type = TYPE_PIIX4; + + card_piix[0x02] = 0x10; card_piix[0x03] = 0x71; /*82371EB (PIIX4)*/ + + card_piix_ide[0x02] = 0x11; card_piix_ide[0x03] = 0x71; /*82371EB (PIIX4)*/ + + io_sethandler(0x0092, 0x0001, piix_92_read, NULL, NULL, piix_92_write, NULL, NULL, NULL); + piix_pm_init(&piix); } diff --git a/src/piix.h b/src/piix.h index 0e85a27..1ac8884 100644 --- a/src/piix.h +++ b/src/piix.h @@ -1 +1,42 @@ -void piix_init(int card); +void piix_init(int card, int pci_a, int pci_b, int pci_c, int pci_d, void (*nb_reset)()); +void piix4_init(int card, int pci_a, int pci_b, int pci_c, int pci_d, void (*nb_reset)()); + +typedef struct piix_t +{ + int type; + + /*PIIX4*/ + uint8_t card_pm[256]; + + uint16_t pmba; + struct + { + uint8_t apmc, apms; + + uint64_t timer_offset; + + uint16_t pmsts; + uint16_t pmen; + uint16_t pmcntrl; + uint32_t devctl; + uint32_t devsts; + uint16_t glbsts; + uint16_t gpen; + uint16_t gpsts; + uint32_t pcntrl; + uint16_t glben; + uint32_t glbctl; + uint32_t gporeg; + + int dev13_enable; + uint16_t dev13_base, dev13_size; + } pm; + + uint16_t smbba; + struct + { + uint8_t host_ctrl; + } smbus; + + uint8_t port_92; +} piix_t; diff --git a/src/piix_pm.c b/src/piix_pm.c new file mode 100644 index 0000000..e55766f --- /dev/null +++ b/src/piix_pm.c @@ -0,0 +1,417 @@ +#include "ibm.h" +#include "io.h" +#include "piix.h" +#include "piix_pm.h" +#include "x86.h" + +#define DEVSTS_TRP_STS_DEV13 (1 << 29) + +#define DEVCTL_TRP_EN_DEV13 (1 << 25) + +#define GLBSTS_APM_STS (1 << 5) + +static uint8_t dev13_read(uint16_t addr, void *p) +{ + piix_t *piix = (piix_t *)p; + +// pclog("dev13_read: addr=%04x %08x\n", addr, piix.pm.devctl); + if (piix->pm.devctl & DEVCTL_TRP_EN_DEV13) + { + piix->pm.devsts |= DEVSTS_TRP_STS_DEV13; + x86_smi_trigger(); + } + return 0xff; +} +static void dev13_write(uint16_t addr, uint8_t val, void *p) +{ + piix_t *piix = (piix_t *)p; + +// pclog("dev13_write: addr=%04x val=%02x %08x\n", addr, val, piix.pm.devctl); + if (piix->pm.devctl & DEVCTL_TRP_EN_DEV13) + { + piix->pm.devsts |= DEVSTS_TRP_STS_DEV13; + x86_smi_trigger(); + } +} + +static void dev13_recalc(piix_t *piix) +{ + if (piix->pm.dev13_enable) + io_removehandler(piix->pm.dev13_base, piix->pm.dev13_size, + dev13_read, NULL, NULL, + dev13_write, NULL, NULL, piix); + piix->pm.dev13_base = piix->card_pm[0x70] | (piix->card_pm[0x71] << 8); + piix->pm.dev13_size = (piix->card_pm[0x72] & 0xf) + 1; + piix->pm.dev13_enable = piix->card_pm[0x72] & 0x10; + if (piix->pm.dev13_enable) + io_sethandler(piix->pm.dev13_base, piix->pm.dev13_size, + dev13_read, NULL, NULL, + dev13_write, NULL, NULL, piix); +} + +static void piix_pm_write(uint16_t port, uint8_t val, void *p) +{ + piix_t *piix = (piix_t *)p; + +// pclog("piix_pm_write: port=%04x val=%02x\n", port, val); + switch (port & 0x3f) + { + case 0x00: + piix->pm.pmsts &= ~(val & 0x31); + break; + case 0x01: + piix->pm.pmsts &= ~((val & 0x8d) << 8); + break; + + case 0x02: + piix->pm.pmen = (piix->pm.pmen & ~0xff) | (val & 0x21); + break; + case 0x03: + piix->pm.pmen = (piix->pm.pmen & ~0xff00) | ((val & 0x05) << 8); + break; + + case 0x04: + piix->pm.pmcntrl = (piix->pm.pmcntrl & ~0xff) | (val & 0x03); + break; + case 0x05: + pclog("PM reg 5 write %02x\n", val); + if (val & 0x20) + { + pclog("PIIX transition to power state %i\n", (val >> 2) & 7); + if (val == 0x20) + { + pclog("Power off\n"); + stop_emulation_now(); + } + } + piix->pm.pmcntrl = (piix->pm.pmcntrl & ~0xff00) | ((val & 0x1c) << 8); + break; + + case 0x0c: case 0x0d: + piix->pm.gpsts &= ~(val << ((port & 1) * 8)); + break; + + case 0x0e: + piix->pm.pmen = (piix->pm.pmen & ~0xff) | (val & 0x01); + break; + case 0x0f: + piix->pm.pmen = (piix->pm.pmen & ~0xff00) | ((val & 0x0f) << 8); + break; + + case 0x10: + piix->pm.pcntrl = (piix->pm.pcntrl & ~0xff) | (val & 0x1e); + break; + case 0x11: + piix->pm.pcntrl = (piix->pm.pcntrl & ~0xff00) | ((val & 0x3e) << 8); + break; + + case 0x18: + piix->pm.glbsts &= ~(val & 0x25); + break; + case 0x19: + piix->pm.glbsts &= ~((val & 0x0d) << 8); + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + piix->pm.devsts &= ~(val << ((port & 3) * 8)); + break; + + case 0x20: + piix->pm.glben = (piix->pm.glben & ~0xff) | (val & 0x01); + break; + case 0x21: + piix->pm.glben = (piix->pm.glben & ~0xff00) | ((val & 0x0f) << 8); + break; + + case 0x28: + piix->pm.glbctl = (piix->pm.glbctl & ~0xff) | (val & 0x05); + break; + case 0x29: + piix->pm.glbctl = (piix->pm.glbctl & ~0xff00) | ((val & 0xff) << 8); + break; + case 0x2a: + piix->pm.glbctl = (piix->pm.glbctl & ~0xff0000) | ((val & 0x01) << 16); + break; + case 0x2b: + piix->pm.glbctl = (piix->pm.glbctl & ~0xff000000) | ((val & 0x07) << 24); + break; + + case 0x2c: + piix->pm.devctl = (piix->pm.devctl & ~0xff) | val; + break; + case 0x2d: + piix->pm.devctl = (piix->pm.devctl & ~0xff00) | (val << 8); + break; + case 0x2e: + piix->pm.devctl = (piix->pm.devctl & ~0xff0000) | (val << 16); + break; + case 0x2f: + piix->pm.devctl = (piix->pm.devctl & ~0xff000000) | ((val & 0x0f) << 24); + break; + + case 0x34: + piix->pm.gporeg = (piix->pm.gporeg & ~0xff) | val; + break; + case 0x35: + piix->pm.gporeg = (piix->pm.gporeg & ~0xff00) | (val << 8); + break; + case 0x36: + piix->pm.gporeg = (piix->pm.gporeg & ~0xff0000) | (val << 16); + break; + case 0x37: + piix->pm.gporeg = (piix->pm.gporeg & ~0xff000000) | (val << 24); + break; + } +} +static uint8_t piix_pm_read(uint16_t port, void *p) +{ + piix_t *piix = (piix_t *)p; + uint8_t ret = 0xff; + + switch (port & 0x3f) + { + case 0x00: case 0x01: + ret = piix->pm.pmsts >> ((port & 1) * 8); + break; + + case 0x02: case 0x03: + ret = piix->pm.pmen >> ((port & 1) * 8); + break; + + case 0x04: case 0x05: + ret = piix->pm.pmcntrl >> ((port & 1) * 8); + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: + { + uint64_t timer = tsc - piix->pm.timer_offset; + uint32_t pm_timer = (timer * 3579545) / cpu_get_speed(); + + ret = pm_timer >> ((port & 3) * 8); + break; + } + + case 0x0c: case 0x0d: + ret = piix->pm.gpsts >> ((port & 1) * 8); + break; + + case 0x0e: case 0x0f: + ret = piix->pm.pmen >> ((port & 1) * 8); + break; + + case 0x10: case 0x11: case 0x12: case 0x13: + ret = piix->pm.pcntrl >> ((port & 3) * 8); + break; + + case 0x14: + ret = 0; + break; + case 0x15: + ret = 0; + break; + + case 0x18: case 0x19: + ret = piix->pm.glbsts >> ((port & 1) * 8); + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + ret = piix->pm.devsts >> ((port & 3) * 8); + break; + + case 0x20: case 0x21: + ret = piix->pm.glben >> ((port & 1) * 8); + break; + + case 0x28: case 0x29: case 0x2a: case 0x2b: + ret = piix->pm.glbctl >> ((port & 3) * 8); + break; + + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + ret = piix->pm.devctl >> ((port & 3) * 8); + break; + + case 0x30: + ret = 0x00; + break; + case 0x31: + ret = 0x00; + break; + case 0x32: + /*GA686BX - bit 1 = low battery*/ + ret = 0x00; + break; + + case 0x34: case 0x35: case 0x36: case 0x37: + ret = piix->pm.gporeg >> ((port & 3) * 8); + break; + +// default: +// fatal("piix_pm_read: unknown read %04x\n", port); + } + +// pclog("piix_pm_read: port=%04x val=%02x\n", port, ret); + return ret; +} + +static void piix_smbus_write(uint16_t port, uint8_t val, void *p) +{ + piix_t *piix = (piix_t *)p; +// pclog("piix_smbus_write: port=%04x val=%02x\n", port, val); + + switch (port & 0xf) + { + case 0x2: + piix->smbus.host_ctrl = (val & 0x5f) | (piix->smbus.host_ctrl & 0x40); + break; + } +} +static uint8_t piix_smbus_read(uint16_t port, void *p) +{ + piix_t *piix = (piix_t *)p; + uint8_t ret = 0xff; + + switch (port & 0x0f) + { + case 0x0: + ret = 0; + break; + + case 0x2: + ret = piix->smbus.host_ctrl; + break; + + case 0x5: + ret = 0; + break; + +// default: +// fatal("piix_smbus_read: unknown read %04x\n", port); + } + + return ret; +} + +static uint8_t piix4_apm_read(uint16_t port, void *p) +{ + piix_t *piix = (piix_t *)p; + uint8_t ret = 0xff; + + switch (port) + { + case 0xb2: + ret = piix->pm.apmc; + break; + + case 0xb3: + ret = piix->pm.apms; + break; + } +// pclog("piix_apm_read: port=%04x ret=%02x\n", port, ret); + return ret; +} +static void piix4_apm_write(uint16_t port, uint8_t val, void *p) +{ + piix_t *piix = (piix_t *)p; + +// pclog("piix_apm_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0xb2: + piix->pm.apmc = val; + if (piix->card_pm[0x5b] & (1 << 1)) + { + piix->pm.glbsts |= GLBSTS_APM_STS; +// pclog("APMC write causes SMI\n"); + x86_smi_trigger(); + } + break; + + case 0xb3: + piix->pm.apms = val; + break; + } +} + +static void pm_clear_io(piix_t *piix) +{ + io_removehandler(piix->pmba, 0x0040, piix_pm_read, NULL, NULL, piix_pm_write, NULL, NULL, piix); + io_removehandler(piix->smbba, 0x0010, piix_smbus_read, NULL, NULL, piix_smbus_write, NULL, NULL, piix); +} +static void pm_set_io(piix_t *piix) +{ +// pclog("pm_set_io: %02x %04x\n", piix.card_pm[0x04], piix.smbba); + if ((piix->card_pm[0x04] & 0x01) && piix->pmba) + { +// pclog("PMBA=%04x\n", piix.pmba); + io_sethandler(piix->pmba, 0x0040, piix_pm_read, NULL, NULL, piix_pm_write, NULL, NULL, piix); + } + if ((piix->card_pm[0x04] & 0x01) && piix->smbba) + { +// pclog("SMBBA=%04x\n", piix.smbba); + io_sethandler(piix->smbba, 0x0010, piix_smbus_read, NULL, NULL, piix_smbus_write, NULL, NULL, piix); + } +} + +void piix_pm_pci_write(int addr, uint8_t val, void *p) +{ + piix_t *piix = (piix_t *)p; + + switch (addr) + { + case 0x04: + pm_clear_io(piix); + piix->card_pm[0x04] = val & 1; + pm_set_io(piix); + break; + case 0x40: + pm_clear_io(piix); + piix->pmba = (piix->pmba & 0xff00) | (val & 0xc0); + pm_set_io(piix); + break; + case 0x41: + pm_clear_io(piix); + piix->pmba = (piix->pmba & 0xc0) | (val << 8); + pm_set_io(piix); + break; + case 0x58: case 0x59: case 0x5b: case 0x5c: + piix->card_pm[addr] = val; + break; + case 0x70: case 0x71: case 0x72: + piix->card_pm[addr] = val; + dev13_recalc(piix); + break; + case 0x90: + pm_clear_io(piix); + piix->smbba = (piix->smbba & 0xff00) | (val & 0xf0); + pm_set_io(piix); + break; + case 0x91: + pm_clear_io(piix); + piix->smbba = (piix->smbba & 0xf0) | (val << 8); + pm_set_io(piix); + break; + } +} +uint8_t piix_pm_pci_read(int addr, void *p) +{ + piix_t *piix = (piix_t *)p; + + return piix->card_pm[addr]; +} + +void piix_pm_init(piix_t *piix) +{ + memset(&piix->card_pm, 0, sizeof(piix->card_pm)); + piix->card_pm[0x00] = 0x86; piix->card_pm[0x01] = 0x80; /*Intel*/ + piix->card_pm[0x02] = 0x13; piix->card_pm[0x03] = 0x71; /*82371EB (PIIX4)*/ + piix->card_pm[0x06] = 0x80; piix->card_pm[0x07] = 0x02; + piix->card_pm[0x09] = 0x00; piix->card_pm[0x0a] = 0x80; piix->card_pm[0x0b] = 0x06; /*Bridge device*/ + piix->card_pm[0x3d] = 0x01; /*IRQA*/ + piix->card_pm[0x40] = 0x01; + piix->card_pm[0x90] = 0x01; + piix->pm.timer_offset = 0; + piix->pm.gporeg = 0x7fffbfff; + + io_sethandler(0x00b2, 0x0002, piix4_apm_read, NULL, NULL, piix4_apm_write, NULL, NULL, piix); +} diff --git a/src/piix_pm.h b/src/piix_pm.h new file mode 100644 index 0000000..dcc06f6 --- /dev/null +++ b/src/piix_pm.h @@ -0,0 +1,3 @@ +void piix_pm_init(piix_t *piix); +void piix_pm_pci_write(int addr, uint8_t val, void *p); +uint8_t piix_pm_pci_read(int addr, void *p); diff --git a/src/pit.c b/src/pit.c index c6e96f8..11a9829 100644 --- a/src/pit.c +++ b/src/pit.c @@ -21,7 +21,12 @@ //Tyrian writes 4300 or 17512 int displine; -double PITCONST; +uint64_t PITCONST; +uint64_t CGACONST; +uint64_t MDACONST; +uint64_t VGACONST1, VGACONST2; +uint64_t RTCCONST; + float cpuclock; float isa_timing, bus_timing; @@ -30,23 +35,23 @@ 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); + PITCONST = (uint64_t)(clock / 1193182.0 * (float)(1ull << 32)); + CGACONST = (uint64_t)((clock / (19687503.0/11.0)) * (float)(1ull << 32)); + MDACONST = (uint64_t)((clock / 2032125.0) * (float)(1ull << 32)); + VGACONST1 = (uint64_t)((clock / 25175000.0) * (float)(1ull << 32)); + VGACONST2 = (uint64_t)((clock / 28322000.0) * (float)(1ull << 32)); 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); + xt_cpu_multi = (uint64_t)((14318184.0*(double)(1ull << 32)) / (double)cpu_get_speed()); // 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)); + RTCCONST = (uint64_t)((clock / 32768.0) * (float)(1ull << 32)); + TIMER_USEC = (uint64_t)((clock / 1000000.0) * (float)(1ull << 32)); device_speed_changed(); } @@ -55,9 +60,9 @@ void setpitclock(float clock) void pit_reset(PIT *pit) { 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->l[0] = 0xFFFF; + pit->l[1] = 0xFFFF; + pit->l[2] = 0xFFFF; pit->m[0] = pit->m[1] = pit->m[2] = 0; pit->ctrls[0] = pit->ctrls[1] = pit->ctrls[2] = 0; pit->thit[0]=1; @@ -66,11 +71,6 @@ void pit_reset(PIT *pit) 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]) @@ -85,18 +85,52 @@ static void pit_set_out(PIT *pit, int t, int out) pit->out[t] = out; } +static int pit_read_timer(PIT *pit, int t) +{ +// pclog("pit_read_timer: t=%i using_timer=%i m=%i enabled=%i\n", t, pit->using_timer[t], pit->m[t], timer_is_enabled(&pit->timer[t])); + if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t]) && timer_is_enabled(&pit->timer[t])) + { + int read = (int)((timer_get_remaining_u64(&pit->timer[t])) / PITCONST); +// pclog(" read %i %08x %016llx\n", t, read, timer_get_remaining_u64(&pit->timer[t])); + 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]; +} + +/*Dump timer count back to pit->count[], and disable timer. This should be used + when stopping a PIT timer, to ensure the correct value can be read back.*/ +static void pit_dump_and_disable_timer(PIT *pit, int t) +{ + if (pit->using_timer[t] && timer_is_enabled(&pit->timer[t])) + { + pit->count[t] = pit_read_timer(pit, t); + timer_disable(&pit->timer[t]); + } +} + static void pit_load(PIT *pit, 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); +// pclog("pit_load: t=%i l=%x m=%i %016llx\n", t, l, pit->m[t], PITCONST); switch (pit->m[t]) { case 0: /*Interrupt on terminal count*/ pit->count[t] = l; - pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); pit_set_out(pit, t, 0); pit->thit[t] = 0; pit->enabled[t] = pit->gate[t]; @@ -108,7 +142,8 @@ static void pit_load(PIT *pit, int t) if (pit->initial[t]) { pit->count[t] = l - 1; - pit->c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)((l - 1) * PITCONST)); pit_set_out(pit, t, 1); pit->thit[t] = 0; } @@ -118,12 +153,13 @@ static void pit_load(PIT *pit, int t) if (pit->initial[t]) { pit->count[t] = l; - pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST)); pit_set_out(pit, t, 1); pit->thit[t] = 0; } pit->enabled[t] = pit->gate[t]; -// pclog("pit_load: square wave mode c=%x\n", pit->c[t]); +// pclog("pit_load: square wave mode c=%x\n", ); break; case 4: /*Software triggered stobe*/ if (!pit->thit[t] && !pit->initial[t]) @@ -131,7 +167,8 @@ static void pit_load(PIT *pit, int t) else { pit->count[t] = l; - pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); pit_set_out(pit, t, 0); pit->thit[t] = 0; } @@ -143,7 +180,9 @@ static void pit_load(PIT *pit, int t) } pit->initial[t] = 0; pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; - timer_update_outstanding(); + if (pit->using_timer[t] && !pit->running[t]) + pit_dump_and_disable_timer(pit, t); + // 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]); } @@ -161,6 +200,8 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate) { case 0: /*Interrupt on terminal count*/ case 4: /*Software triggered stobe*/ + if (pit->using_timer[t] && !pit->running[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); pit->enabled[t] = gate; break; case 1: /*Hardware retriggerable one-shot*/ @@ -168,7 +209,8 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate) if (gate && !pit->gate[t]) { pit->count[t] = l; - pit->c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); pit_set_out(pit, t, 0); pit->thit[t] = 0; pit->enabled[t] = 1; @@ -178,7 +220,8 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate) if (gate && !pit->gate[t]) { pit->count[t] = l - 1; - pit->c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); pit_set_out(pit, t, 1); pit->thit[t] = 0; } @@ -188,7 +231,8 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate) if (gate && !pit->gate[t]) { pit->count[t] = l; - pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST)); pit_set_out(pit, t, 1); pit->thit[t] = 0; } @@ -197,23 +241,21 @@ void pit_set_gate_no_timer(PIT *pit, int t, int gate) } pit->gate[t] = gate; pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; + if (pit->using_timer[t] && !pit->running[t]) + pit_dump_and_disable_timer(pit, t); // pclog("pit_set_gate: t=%i gate=%i\n", t, gate); } void pit_set_gate(PIT *pit, int t, int gate) { +// pclog("pit_set_gate: t=%i gate=%i\n", t, gate); if (pit->disabled[t]) { pit->gate[t] = gate; return; } - timer_process(); - pit_set_gate_no_timer(pit, t, gate); - - timer_update_outstanding(); -// pclog("pit_set_gate: t=%i gate=%i\n", t, gate); } static void pit_over(PIT *pit, int t) @@ -222,11 +264,12 @@ static void pit_over(PIT *pit, int t) if (pit->disabled[t]) { pit->count[t] += 0xffff; - pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * 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]); +// if (t == 2) pclog("pit_over: t=%i l=%x c=%llx hit=%i %016llx\n", t, pit->l[t], timer_get_remaining_u64(&pit->timer[t]), pit->thit[t], tsc); switch (pit->m[t]) { case 0: /*Interrupt on terminal count*/ @@ -235,11 +278,13 @@ static void pit_over(PIT *pit, int t) pit_set_out(pit, t, 1); pit->thit[t] = 1; pit->count[t] += 0xffff; - pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST)); break; case 2: /*Rate generator*/ pit->count[t] += l; - pit->c[t] += (int)((l << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); pit_set_out(pit, t, 0); pit_set_out(pit, t, 1); break; @@ -248,13 +293,15 @@ static void pit_over(PIT *pit, int t) { pit_set_out(pit, t, 0); pit->count[t] += (l >> 1); - pit->c[t] += (int)(((l >> 1) << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)((l >> 1) * PITCONST)); } else { pit_set_out(pit, t, 1); pit->count[t] += ((l + 1) >> 1); - pit->c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(((l + 1) >> 1) * PITCONST)); } // if (!t) pclog("pit_over: square wave mode c=%x %lli %f\n", pit.c[t], tsc, PITCONST); break; @@ -268,13 +315,15 @@ static void pit_over(PIT *pit, int t) { pit->newcount[t] = 0; pit->count[t] += l; - pit->c[t] += (int)((l << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(l * PITCONST)); } else { pit->thit[t] = 1; pit->count[t] += 0xffff; - pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * PITCONST)); } break; case 5: /*Hardware triggered strove*/ @@ -285,55 +334,20 @@ static void pit_over(PIT *pit, int t) } pit->thit[t] = 1; pit->count[t] += 0xffff; - pit->c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + if (pit->using_timer[t]) + timer_advance_u64(&pit->timer[t], (uint64_t)(0xffff * 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(PIT *pit, 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]; + if (pit->using_timer[t] && !pit->running[t]) + pit_dump_and_disable_timer(pit, t); } void pit_write(uint16_t addr, uint8_t val, void *p) { PIT *pit = (PIT *)p; 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]); +// /*if (val != 0x40) */pclog("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,cpu_state.pc,ins, pit->gate[0]); switch (addr&3) { @@ -343,27 +357,27 @@ void pit_write(uint16_t addr, uint8_t val, void *p) if (!(val&0x20)) { if (val & 2) - pit->rl[0] = pit->using_timer[0] ? ((int)(pit->c[0] / PITCONST) >> TIMER_SHIFT) : pit->count[0]; + pit->rl[0] = pit_read_timer(pit, 0); if (val & 4) - pit->rl[1] = pit->using_timer[1] ? ((int)(pit->c[1] / PITCONST) >> TIMER_SHIFT) : pit->count[1]; + pit->rl[1] = pit_read_timer(pit, 1); if (val & 8) - pit->rl[2] = pit->using_timer[2] ? ((int)(pit->c[2] / PITCONST) >> TIMER_SHIFT) : pit->count[2]; + pit->rl[2] = pit_read_timer(pit, 2); } if (!(val & 0x10)) { if (val & 2) { - pit->read_status[0] = (pit->ctrls[0] & 0x3f) | 0x40 | (pit->out[0] ? 0x80 : 0); + pit->read_status[0] = (pit->ctrls[0] & 0x3f) | (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->read_status[1] = (pit->ctrls[1] & 0x3f) | (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->read_status[2] = (pit->ctrls[2] & 0x3f) | (pit->out[2] ? 0x80 : 0); pit->do_read_status[2] = 1; } } @@ -401,7 +415,6 @@ void pit_write(uint16_t addr, uint8_t val, void *p) pit->rl[t] = pit_read_timer(pit, t); } pit->rereadlatch[t]=1; - if (t == 2) ppispeakon=speakon=(pit->m[2]==0)?0:1; pit->initial[t] = 1; if (!pit->m[t]) pit_set_out(pit, t, 0); @@ -458,8 +471,7 @@ uint8_t pit_read(uint16_t addr, void *p) PIT *pit = (PIT *)p; int t; uint8_t temp = 0xff; - cycles -= (int)PITCONST; -// printf("Read PIT %04X ",addr); +// printf("Read PIT %04X\n",addr); switch (addr&3) { case 0: case 1: case 2: /*Timers*/ @@ -540,11 +552,12 @@ void pit_set_using_timer(PIT *pit, int t, int using_timer) timer_process(); if (pit->using_timer[t] && !using_timer) pit->count[t] = pit_read_timer(pit, t); - if (!pit->using_timer[t] && using_timer) - pit->c[t] = (int)((pit->count[t] << TIMER_SHIFT) * PITCONST); + pit->running[t] = pit->enabled[t] && using_timer && !pit->disabled[t]; + if (!pit->using_timer[t] && using_timer && pit->running[t]) + timer_set_delay_u64(&pit->timer[t], (uint64_t)(pit->count[t] * PITCONST)); + else if (!pit->running[t]) + timer_disable(&pit->timer[t]); 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(PIT *pit, int t, void (*func)(int new_out, int old_out)) @@ -636,9 +649,9 @@ void pit_init() pit.pit_nr[2].nr = 2; pit.pit_nr[0].pit = pit.pit_nr[1].pit = pit.pit_nr[2].pit = &pit; - timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)&pit.pit_nr[0]); - timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)&pit.pit_nr[1]); - timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)&pit.pit_nr[2]); + timer_add(&pit.timer[0], pit_timer_over, (void *)&pit.pit_nr[0], 0); + timer_add(&pit.timer[1], pit_timer_over, (void *)&pit.pit_nr[1], 0); + timer_add(&pit.timer[2], pit_timer_over, (void *)&pit.pit_nr[2], 0); pit_set_out_func(&pit, 0, pit_irq0_timer); pit_set_out_func(&pit, 1, pit_null_timer); @@ -659,7 +672,7 @@ void pit_ps2_init() pit2.pit_nr[0].nr = 0; pit2.pit_nr[0].pit = &pit2; - timer_add(pit_timer_over, &pit2.c[0], &pit2.running[0], (void *)&pit2.pit_nr[0]); + timer_add(&pit2.timer[0], pit_timer_over, (void *)&pit2.pit_nr[0], 0); pit_set_out_func(&pit, 0, pit_irq0_ps2); pit_set_out_func(&pit2, 0, pit_nmi_ps2); diff --git a/src/pit.h b/src/pit.h index 2bed738..b314a93 100644 --- a/src/pit.h +++ b/src/pit.h @@ -1,4 +1,4 @@ -extern double PITCONST; +extern uint64_t PITCONST; void pit_init(); void pit_ps2_init(); void pit_reset(); diff --git a/src/plat-keyboard.h b/src/plat-keyboard.h index 4b5ea03..ab8b922 100644 --- a/src/plat-keyboard.h +++ b/src/plat-keyboard.h @@ -1,10 +1,12 @@ #ifdef __cplusplus extern "C" { #endif + #include + void keyboard_init(); void keyboard_close(); void keyboard_poll_host(); - extern int pcem_key[272]; + extern uint8_t pcem_key[272]; extern int rawinputkey[272]; #ifndef __unix diff --git a/src/ps1.c b/src/ps1.c index 72fa773..e1f6fce 100644 --- a/src/ps1.c +++ b/src/ps1.c @@ -73,7 +73,7 @@ void ps1_write(uint16_t port, uint8_t val, void *p) case 0x102: lpt1_remove(); if (val & 0x04) - serial1_init(0x3f8, 4); + serial1_init(0x3f8, 4, 1); else serial1_remove(); if (val & 0x10) @@ -131,15 +131,15 @@ void ps1mb_init() io_sethandler(0x0324, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); rom_init(&ps1_high_rom, - "roms/ibmps1es/f80000.bin", + "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", + "ibmps1es/ibm_1057757_24-05-90.bin", + "ibmps1es/ibm_1057757_29-15-90.bin", 0xfc0000, 0x40000, 0x3ffff, @@ -238,7 +238,7 @@ void ps1_m2121_write(uint16_t port, uint8_t val, void *p) case 0x102: lpt1_remove(); if (val & 0x04) - serial1_init(0x3f8, 4); + serial1_init(0x3f8, 4, 1); else serial1_remove(); if (val & 0x10) @@ -283,12 +283,13 @@ void ps1mb_m2121_init() 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", + "ibmps1_2121/fc0000.bin", 0xfc0000, 0x40000, 0x3ffff, 0, MEM_MAPPING_EXTERNAL); + ps1_92 = 0; ps1_190 = 0; lpt1_remove(); @@ -300,3 +301,65 @@ void ps1mb_m2121_init() mem_remap_top_384k(); } + + +/*Not sure what this SuperIO chip is, so define it here for now*/ +static struct +{ + int idx; + uint8_t regs[3]; +} ps1_m2133_superio; + +static uint16_t ps1_lpt_io[4] = {0x378, 0x3bc, 0x278, 0x378}; +static uint16_t ps1_com_io[4] = {0x3f8, 0x2f8, 0x3e8, 0x2e8}; + +static uint8_t ps1_m2133_read(uint16_t port, void *p) +{ + uint8_t ret = 0xff; + switch (port) + { + case 0x398: + ret = ps1_m2133_superio.idx; + break; + + case 0x399: + if (ps1_m2133_superio.idx < 3) + ret = ps1_m2133_superio.regs[ps1_m2133_superio.idx]; + break; + } + return ret; +} + +static void ps1_m2133_write(uint16_t port, uint8_t val, void *p) +{ +// pclog("ps1_m2133_write: port=%04x val=%02x\n", port, val); + switch (port) + { + case 0x398: + ps1_m2133_superio.idx = val; + break; + + case 0x399: + if (ps1_m2133_superio.idx < 3) + { + ps1_m2133_superio.regs[ps1_m2133_superio.idx] = val; + + lpt1_remove(); + serial1_remove(); + serial2_remove(); + + if (ps1_m2133_superio.regs[0] & 1) + lpt1_init(ps1_lpt_io[ps1_m2133_superio.regs[1] & 3]); + if (ps1_m2133_superio.regs[0] & 2) + serial1_set(ps1_com_io[(ps1_m2133_superio.regs[1] >> 2) & 3], 4); + if (ps1_m2133_superio.regs[0] & 4) + serial2_set(ps1_com_io[(ps1_m2133_superio.regs[1] >> 4) & 3], 3); + } + break; + } +} + +void ps1mb_m2133_init(void) +{ + io_sethandler(0x0398, 0x0002, ps1_m2133_read, NULL, NULL, ps1_m2133_write, NULL, NULL, NULL); +} diff --git a/src/ps1.h b/src/ps1.h index c054bcb..7253c8b 100644 --- a/src/ps1.h +++ b/src/ps1.h @@ -1,2 +1,3 @@ void ps1mb_init(); void ps1mb_m2121_init(); +void ps1mb_m2133_init(void); diff --git a/src/ps2.c b/src/ps2.c index 18b0ed7..fe0d6a9 100644 --- a/src/ps2.c +++ b/src/ps2.c @@ -68,7 +68,7 @@ void ps2_write(uint16_t port, uint8_t val, void *p) case 0x102: lpt1_remove(); if (val & 0x04) - serial1_init(0x3f8, 4); + serial1_init(0x3f8, 4, 1); else serial1_remove(); if (val & 0x10) @@ -124,7 +124,8 @@ void ps2board_init() io_sethandler(0x0320, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); io_sethandler(0x0322, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); io_sethandler(0x0324, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); - + + ps2_92 = 0; ps2_190 = 0; lpt1_remove(); diff --git a/src/ps2_mca.c b/src/ps2_mca.c index c482ab5..dd4e024 100644 --- a/src/ps2_mca.c +++ b/src/ps2_mca.c @@ -9,6 +9,7 @@ #include "ps2_nvr.h" #include "rom.h" #include "serial.h" +#include "vid_vga.h" #include "x86.h" //static uint8_t ps2_92, ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; @@ -35,6 +36,7 @@ static struct mem_mapping_t shadow_mapping; mem_mapping_t split_mapping; mem_mapping_t expansion_mapping; + mem_mapping_t cache_mapping; uint8_t (*planar_read)(uint16_t port); void (*planar_write)(uint16_t port, uint8_t val); @@ -44,8 +46,94 @@ static struct uint32_t split_addr; uint8_t mem_pos_regs[8]; + + int pending_cache_miss; } ps2; +/*The model 70 type 3/4 BIOS performs cache testing. Since PCem doesn't have any + proper cache emulation, it's faked a bit here. + + Port E2 is used for cache diagnostics. Bit 7 seems to be set on a cache miss, + toggling bit 2 seems to clear this. The BIOS performs at least the following + tests : + + - Disable RAM, access low 64kb (386) / 8kb (486), execute code from cache to + access low memory and verify that there are no cache misses. + - Write to low memory using DMA, read low memory and verify that all accesses + cause cache misses. + - Read low memory, verify that first access is cache miss. Read again and + verify that second access is cache hit. + + These tests are also performed on the 486 model 70, despite there being no + external cache on this system. Port E2 seems to control the internal cache on + these systems. Presumably this port is connected to KEN#/FLUSH# on the 486. + This behaviour is required to pass the timer interrupt test on the 486 version + - the BIOS uses a fixed length loop that will terminate too early on a 486/25 + if it executes from internal cache. + + To handle this, PCem uses some basic heuristics : + - If cache is enabled but RAM is disabled, accesses to low memory go directly + to cache memory. + - Reads to cache addresses not 'valid' will set the cache miss flag, and mark + that line as valid. + - Cache flushes will clear the valid array. + - DMA via the undocumented PS/2 command 0xb will clear the valid array. + - Disabling the cache will clear the valid array. + - Disabling the cache will also mark shadowed ROM areas as using ROM timings. + This works around the timing loop mentioned above. +*/ +static uint8_t ps2_cache[65536]; +static int ps2_cache_valid[65536/8]; + +static uint8_t ps2_read_cache_ram(uint32_t addr, void *priv) +{ +// pclog("ps2_read_cache_ram: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc); + if (!ps2_cache_valid[addr >> 3]) + { + ps2_cache_valid[addr >> 3] = 1; + ps2.mem_regs[2] |= 0x80; + } + else + ps2.pending_cache_miss = 0; + + return ps2_cache[addr]; +} +static uint16_t ps2_read_cache_ramw(uint32_t addr, void *priv) +{ +// pclog("ps2_read_cache_ramw: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc); + if (!ps2_cache_valid[addr >> 3]) + { + ps2_cache_valid[addr >> 3] = 1; + ps2.mem_regs[2] |= 0x80; + } + else + ps2.pending_cache_miss = 0; + + return *(uint16_t *)&ps2_cache[addr]; +} +static uint32_t ps2_read_cache_raml(uint32_t addr, void *priv) +{ +// pclog("ps2_read_cache_raml: addr=%08x %i %04x:%04x\n", addr, ps2_cache_valid[addr >> 3], CS,cpu_state.pc); + if (!ps2_cache_valid[addr >> 3]) + { + ps2_cache_valid[addr >> 3] = 1; + ps2.mem_regs[2] |= 0x80; + } + else + ps2.pending_cache_miss = 0; + + return *(uint32_t *)&ps2_cache[addr]; +} +static void ps2_write_cache_ram(uint32_t addr, uint8_t val, void *priv) +{ +// pclog("ps2_write_cache_ram: addr=%08x val=%02x %04x:%04x %i\n", addr, val, CS,cpu_state.pc, ins); + ps2_cache[addr] = val; +} + +void ps2_cache_clean() +{ + memset(ps2_cache_valid, 0, sizeof(ps2_cache_valid)); +} static uint8_t ps2_read_shadow_ram(uint32_t addr, void *priv) { @@ -164,6 +252,30 @@ static uint8_t model_55sx_read(uint16_t port) return 0xff; } +static uint8_t model_70_type3_read(uint16_t port) +{ + switch (port) + { + case 0x100: + return 0xff; + case 0x101: + return 0xf9; + case 0x102: + return ps2.option[0]; + case 0x103: + return ps2.option[1]; + case 0x104: + return ps2.option[2]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; + } + return 0xff; +} + static uint8_t model_80_read(uint16_t port) { switch (port) @@ -203,9 +315,9 @@ static void model_50_write(uint16_t port, uint8_t val) if (val & 0x04) { if (val & 0x08) - serial1_init(0x3f8, 4); + serial1_init(0x3f8, 4, 1); else - serial1_init(0x2f8, 3); + serial1_init(0x2f8, 3, 1); } else serial1_remove(); @@ -259,9 +371,9 @@ static void model_55sx_write(uint16_t port, uint8_t val) if (val & 0x04) { if (val & 0x08) - serial1_init(0x3f8, 4); + serial1_init(0x3f8, 4, 1); else - serial1_init(0x2f8, 3); + serial1_init(0x2f8, 3, 1); } else serial1_remove(); @@ -293,10 +405,8 @@ static void model_55sx_write(uint16_t port, uint8_t val) case 0x105: pclog("Write POS3 %02x\n", val); ps2.option[3] = val; - shadowbios = !(val & 0x10); - shadowbios_write = val & 0x10; - if (shadowbios) + if (!(val & 0x10)) { mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); mem_mapping_disable(&ps2.shadow_mapping); @@ -321,6 +431,55 @@ static void model_55sx_write(uint16_t port, uint8_t val) } } +static void model_70_type3_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x100: + break; + case 0x101: + break; + case 0x102: + lpt1_remove(); + serial1_remove(); + if (val & 0x04) + { + if (val & 0x08) + serial1_init(0x3f8, 4, 1); + else + serial1_init(0x2f8, 3, 1); + } + 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; + } + } + ps2.option[0] = val; + break; + case 0x105: + ps2.option[3] = val; + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + } +} + static void model_80_write(uint16_t port, uint8_t val) { switch (port) @@ -335,9 +494,9 @@ static void model_80_write(uint16_t port, uint8_t val) if (val & 0x04) { if (val & 0x08) - serial1_init(0x3f8, 4); + serial1_init(0x3f8, 4, 1); else - serial1_init(0x2f8, 3); + serial1_init(0x2f8, 3, 1); } else serial1_remove(); @@ -469,14 +628,14 @@ uint8_t ps2_mca_read(uint16_t port, void *p) break; } - pclog("ps2_read: port=%04x temp=%02x\n", port, temp); +// pclog("ps2_read: port=%04x temp=%02x %04x:%04x %i\n", port, temp, CS, cpu_state.pc, ins); return temp; } static void ps2_mca_write(uint16_t port, uint8_t val, void *p) { - pclog("ps2_write: port=%04x val=%02x %04x:%04x\n", port, val, CS,cpu_state.pc); +// pclog("ps2_write: port=%04x val=%02x %04x:%04x\n", port, val, CS,cpu_state.pc); switch (port) { @@ -494,6 +653,8 @@ static void ps2_mca_write(uint16_t port, uint8_t val, void *p) ps2.setup = val; break; case 0x96: + if ((val & 0x80) && !(ps2.adapter_setup & 0x80)) + mca_reset(); ps2.adapter_setup = val; mca_set_index(val & 7); break; @@ -513,7 +674,15 @@ static void ps2_mca_write(uint16_t port, uint8_t val, void *p) if (!(ps2.setup & PS2_SETUP_IO)) ps2.planar_write(port, val); else if (!(ps2.setup & PS2_SETUP_VGA)) + { + if (mb_vga) + { + vga_disable(mb_vga); + if (val & 1) + vga_enable(mb_vga); + } ps2.pos_vga = val; + } else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) mca_write(port, val); break; @@ -685,6 +854,70 @@ static void mem_encoding_write(uint16_t addr, uint8_t val, void *p) mem_encoding_update(); } +static uint8_t mem_encoding_read_cached(uint16_t addr, void *p) +{ + switch (addr) + { + case 0xe0: + return ps2.mem_regs[0]; + case 0xe1: + return ps2.mem_regs[1]; + case 0xe2: + return ps2.mem_regs[2]; + } + return 0xff; +} +static void mem_encoding_write_cached(uint16_t addr, uint8_t val, void *p) +{ + uint8_t old; + + switch (addr) + { + case 0xe0: + ps2.mem_regs[0] = val; + break; + case 0xe1: + ps2.mem_regs[1] = val; + break; + case 0xe2: + old = ps2.mem_regs[2]; + ps2.mem_regs[2] = (ps2.mem_regs[2] & 0x80) | (val & ~0x88); + if (val & 2) + { +// pclog("Clear latch - %i\n", ps2.pending_cache_miss); + if (ps2.pending_cache_miss) + ps2.mem_regs[2] |= 0x80; + else + ps2.mem_regs[2] &= ~0x80; + ps2.pending_cache_miss = 0; + } + + if ((val & 0x21) == 0x20 && (old & 0x21) != 0x20) + ps2.pending_cache_miss = 1; + if ((val & 0x21) == 0x01 && (old & 0x21) != 0x01) + ps2_cache_clean(); + if (val & 0x01) + ram_mid_mapping.flags |= MEM_MAPPING_ROM; + else + ram_mid_mapping.flags &= ~MEM_MAPPING_ROM; + break; + } +// pclog("mem_encoding_write: addr=%02x val=%02x %04x:%04x %02x %02x\n", addr, val, CS,cpu_state.pc, ps2.mem_regs[1],ps2.mem_regs[2]); + mem_encoding_update(); + if ((ps2.mem_regs[1] & 0x10) && (ps2.mem_regs[2] & 0x21) == 0x20) + { + mem_mapping_disable(&ram_low_mapping); + mem_mapping_enable(&ps2.cache_mapping); + flushmmucache(); + } + else + { + mem_mapping_disable(&ps2.cache_mapping); + mem_mapping_enable(&ram_low_mapping); + flushmmucache(); + } +} + static uint8_t ps2_mem_expansion_read(int port, void *p) { return ps2.mem_pos_regs[port & 7]; @@ -703,6 +936,116 @@ static void ps2_mem_expansion_write(int port, uint8_t val, void *p) mem_mapping_disable(&ps2.expansion_mapping); } +void ps2_mca_board_model_70_type34_init(int is_type4) +{ + ps2_mca_board_common_init(); + + mem_remap_top_256k(); + ps2.split_addr = mem_size * 1024; + mca_init(4); + + ps2.planar_read = model_70_type3_read; + ps2.planar_write = model_70_type3_write; + + device_add(&ps2_nvr_device); + + io_sethandler(0x00e0, 0x0003, mem_encoding_read_cached, NULL, NULL, mem_encoding_write_cached, NULL, NULL, NULL); + + ps2.mem_regs[1] = 2; + + switch (mem_size/1024) + { + case 2: + ps2.option[1] = 0xa6; + ps2.option[2] = 0x01; + break; + case 4: + ps2.option[1] = 0xaa; + ps2.option[2] = 0x01; + break; + case 6: + ps2.option[1] = 0xca; + ps2.option[2] = 0x01; + break; + case 8: + default: + ps2.option[1] = 0xca; + ps2.option[2] = 0x02; + break; + } + + if (is_type4) + ps2.option[2] |= 0x04; /*486 CPU*/ + + mem_mapping_add(&ps2.split_mapping, + (mem_size+256) * 1024, + 256*1024, + ps2_read_split_ram, + ps2_read_split_ramw, + ps2_read_split_raml, + ps2_write_split_ram, + ps2_write_split_ramw, + ps2_write_split_raml, + &ram[0xa0000], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.split_mapping); + + mem_mapping_add(&ps2.cache_mapping, + 0, + is_type4 ? (8 * 1024) : (64 * 1024), + ps2_read_cache_ram, + ps2_read_cache_ramw, + ps2_read_cache_raml, + ps2_write_cache_ram, + NULL, + NULL, + ps2_cache, + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.cache_mapping); + + if (mem_size > 8192) + { + /* Only 8 MB supported on planar, create a memory expansion card for the rest */ + mem_mapping_set_addr(&ram_high_mapping, 0x100000, 0x700000); + + ps2.mem_pos_regs[0] = 0xff; + ps2.mem_pos_regs[1] = 0xfc; + + switch (mem_size/1024) + { + case 10: + ps2.mem_pos_regs[4] = 0xfe; + break; + case 12: + ps2.mem_pos_regs[4] = 0xfa; + break; + case 14: + ps2.mem_pos_regs[4] = 0xea; + break; + case 16: + ps2.mem_pos_regs[4] = 0xaa; + break; + } + + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL, NULL); + mem_mapping_add(&ps2.expansion_mapping, + 0x800000, + (mem_size - 8192)*1024, + mem_read_ram, + mem_read_ramw, + mem_read_raml, + mem_write_ram, + mem_write_ramw, + mem_write_raml, + &ram[0x800000], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.expansion_mapping); + } +} + void ps2_mca_board_model_80_type2_init() { ps2_mca_board_common_init(); @@ -787,7 +1130,7 @@ void ps2_mca_board_model_80_type2_init() break; } - mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL); + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL, NULL); mem_mapping_add(&ps2.expansion_mapping, 0x400000, (mem_size - 4096)*1024, diff --git a/src/ps2_mca.h b/src/ps2_mca.h index d7a2e13..9e20914 100644 --- a/src/ps2_mca.h +++ b/src/ps2_mca.h @@ -1,3 +1,6 @@ void ps2_mca_board_model_50_init(); void ps2_mca_board_model_55sx_init(); +void ps2_mca_board_model_70_type34_init(int is_type4); void ps2_mca_board_model_80_type2_init(); + +void ps2_cache_clean(); diff --git a/src/ps2_nvr.c b/src/ps2_nvr.c index 1225f69..50829fb 100644 --- a/src/ps2_nvr.c +++ b/src/ps2_nvr.c @@ -3,6 +3,7 @@ #include "device.h" #include "io.h" #include "ps2_nvr.h" +#include "nvr.h" typedef struct ps2_nvr_t { @@ -57,7 +58,9 @@ static void *ps2_nvr_init() switch (romset) { - case ROM_IBMPS2_M80: f = romfopen("nvr/ibmps2_m80_sec.nvr", "rb"); break; + case ROM_IBMPS2_M70_TYPE3:f = nvrfopen("ibmps2_m70_type3_sec.nvr", "rb"); break; + case ROM_IBMPS2_M70_TYPE4:f = nvrfopen("ibmps2_m70_type4_sec.nvr", "rb"); break; + case ROM_IBMPS2_M80: f = nvrfopen("ibmps2_m80_sec.nvr", "rb"); break; } if (f) { @@ -77,7 +80,9 @@ static void ps2_nvr_close(void *p) switch (romset) { - case ROM_IBMPS2_M80: f = romfopen("nvr/ibmps2_m80_sec.nvr", "wb"); break; + case ROM_IBMPS2_M70_TYPE3:f = nvrfopen("ibmps2_m70_type3_sec.nvr", "wb"); break; + case ROM_IBMPS2_M70_TYPE4:f = nvrfopen("ibmps2_m70_type4_sec.nvr", "wb"); break; + case ROM_IBMPS2_M80: f = nvrfopen("ibmps2_m80_sec.nvr", "wb"); break; } if (f) { diff --git a/src/pzx.c b/src/pzx.c new file mode 100644 index 0000000..801ce72 --- /dev/null +++ b/src/pzx.c @@ -0,0 +1,419 @@ +/************************************************************************ + + PCem: IBM 5150 Cassette support + + Copyright (C) 2019 John Elliott + + 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. + +*************************************************************************/ + +#include +#include "ibm.h" +#include "pzx.h" + +/* This module is intended to abstract all the details of a PZX file and + * emit its contents as a bitstream in a form suitable for PCem. Similar + * modules could be written to add support for other tape formats such as TZX, + * TAP or CSW. */ + +#define CAS_LOG(x) pclog x +/* #define CAS_LOG(x) */ + +static uint32_t peek2(uint8_t *data) +{ + return (((uint32_t)data[1]) << 8) | data[0]; +} + +static uint32_t peek4(uint8_t *data) +{ + return (((uint32_t)data[3]) << 24) | + (((uint32_t)data[2]) << 16) | + (((uint32_t)data[1]) << 8) | data[0]; +} + +/* Cue up the next pulse definition from the current PULS block. */ +static void pzx_parse_pulse(pzxfile_t *pzx) +{ + pzx->puls_duration = peek2(pzx->curblock + pzx->puls_ptr); + pzx->puls_ptr += 2; + if (pzx->puls_duration > 0x8000) + { + pzx->puls_count = pzx->puls_duration & 0x7FFF; + pzx->puls_duration = peek2(pzx->curblock + pzx->puls_ptr); + pzx->puls_ptr += 2; + } + if (pzx->puls_duration >= 0x8000) + { + pzx->puls_duration &= 0x7FFF; + pzx->puls_duration <<= 16; + pzx->puls_duration |= peek2(pzx->curblock + pzx->puls_ptr); + pzx->puls_ptr += 2; + } + if (!pzx->puls_count) pzx->puls_count = 1; +} + + + +void pzx_init(pzxfile_t *pzx) +{ + memset(pzx, 0, sizeof(pzxfile_t)); + pzx->state = PZX_CLOSED; +} + +/* Load the next block from a PZX-format file. + * + * Returns block if successful, NULL if end of file or error + * Caller must free the block with free(). */ +uint8_t *pzx_load_block(FILE *fp) +{ + uint8_t block_header[8]; + uint8_t *block_data; + uint32_t block_len; + + /* The first 8 bytes of a PZX block are fixed: the first 4 give + * the ID, the second 4 the length (excluding the header itself) */ + if (fread(block_header, 1, 8, fp) < 8) return NULL; /* EoF */ + + block_len = peek4(block_header + 4); + block_data = malloc(8 + block_len); + if (!block_data) return NULL; + memcpy(block_data, block_header, 8); + if (!block_len) /* Block is only the header */ + { +/* CAS_LOG(("Loaded PZX block: %-4.4s\n", block_data)); */ + return block_data; + } + if (fread(block_data + 8, 1, block_len, fp) < block_len) + { + free(block_data); /* Unexpected EoF */ + return NULL; + } +/* CAS_LOG(("Loaded PZX block: %-4.4s\n", block_data)); */ + return block_data; +} + + +/* Search the current file for PZX version headers and check they're all 1.x */ +static const char * pzx_check_version(FILE *fp) +{ + uint8_t *block; + static char message[80]; + + rewind(fp); + while ( (block = pzx_load_block(fp)) ) + { + if (!memcmp(block, "PZXT", 4)) + { + CAS_LOG(("PZX version %d.%d\n", block[8], block[9])); + if (block[8] != 1) + { + sprintf(message, "Unsupported PZX version %d.%d\n", block[8], block[9]); + free(block); + return message; + } + } + free(block); + } + rewind(fp); + return NULL; +} + + +const char *pzx_open(pzxfile_t *pzx, FILE *fp) +{ + const char *result; + + rewind(fp); + /* Check that this file is compatible */ + result = pzx_check_version(fp); + if (result) return result; + + pzx->level = 0; + pzx->state = PZX_IDLE; + pzx->input = fp; + return NULL; +} + +void pzx_close(pzxfile_t *pzx) +{ + if (pzx->input) + { + fclose(pzx->input); + pzx->input = NULL; + } + if (pzx->curblock) + { + free(pzx->curblock); + pzx->curblock = NULL; + } + pzx->state = PZX_CLOSED; +} + +/* Read the next block of type DATA, PAUS or PULS */ +int pzx_next_block(pzxfile_t *pzx) +{ + long pos; + + pos = ftell(pzx->input); + while (pzx->state == PZX_IDLE) + { + uint8_t *blk; + + /* In idle state there should be no current block. But + * make sure of that */ + if (pzx->curblock) + { + free(pzx->curblock); + pzx->curblock = NULL; + } + + /* Load the next block */ + blk = pzx_load_block(pzx->input); + + /* If that didn't load we've reached the end of file; wrap to + * beginning. */ + if (!blk) + { + rewind(pzx->input); + blk = pzx_load_block(pzx->input); + if (!blk) /* Couldn't even load first block */ + { + pzx_close(pzx); + return 0; + } + /* Have we read the whole file and come back to where + * we were? */ + if (ftell(pzx->input) == pos) + { + free(blk); + pzx_close(pzx); + return 0; + } + } + /* We have loaded the next block. What is it? */ + if (!memcmp(blk, "PULS", 4)) + { + pzx->state = PZX_IN_PULS; + pzx->curblock = blk; + pzx->puls_len = 8 + peek4(blk + 4); + pzx->puls_ptr = 8; + pzx->puls_count = 0; + pzx->puls_remain = 0; + pzx->puls_duration = 0; + pzx->level = 0; + CAS_LOG(("Beginning PULS block\n")); + } + else if (!memcmp(blk, "PAUS", 4)) + { + pzx->state = PZX_IN_PAUS; + pzx->curblock = blk; + pzx->paus_remain = peek4(blk + 8); + pzx->level = (pzx->paus_remain >> 31); + pzx->paus_remain &= 0x7FFFFFFF; + CAS_LOG(("Beginning PAUS block, duration=%d\n", + pzx->paus_remain)); + } + else if (!memcmp(blk, "DATA", 4)) + { + pzx->state = PZX_IN_DATA; + pzx->curblock = blk; + pzx->data_bits = peek4(blk + 8); + pzx->level = (pzx->data_bits >> 31); + pzx->data_bits &= 0x7FFFFFFF; + pzx->data_tail = peek2(blk + 12); + pzx->data_p0 = blk[14]; + pzx->data_p1 = blk[15]; + pzx->data_p = 0; + pzx->data_w = 16; + pzx->data_remain = 0; + pzx->data_ptr = 16 + 2 * (pzx->data_p0 + pzx->data_p1); + pzx->data_mask = 0x80; + CAS_LOG(("Beginning DATA block, length=%d p0=%d p1=%d" + " data_ptr=%d\n", + pzx->data_bits, + pzx->data_p0, pzx->data_p1, + pzx->data_ptr)); + } + } + return 1; +} + +static void pzx_endblock(pzxfile_t *pzx) +{ + if (pzx->curblock) free(pzx->curblock); + pzx->curblock = NULL; + pzx->state = PZX_IDLE; +} + +/* PAUS is easy - just run the timer down */ +static int pzx_advance_paus(pzxfile_t *pzx, int time) +{ + if (pzx->paus_remain > time) + { + pzx->paus_remain -= time; + return 0; + } + time -= pzx->paus_remain; + pzx_endblock(pzx); + return time; +} + + + + + + +static int pzx_advance_puls(pzxfile_t *pzx, int time) +{ + /* At the start of a pulse sequence? */ + if (pzx->puls_count == 0) + { + pzx_parse_pulse(pzx); + pzx->puls_remain = pzx->puls_duration; + } + /* Does sample trigger a pulse change? If not, that's easy. */ + if (time < pzx->puls_remain) + { + pzx->puls_remain -= time; + return 0; + } + /* Sample does trigger a pulse change */ + time -= pzx->puls_remain; + /* If there's another pulse in the current sequence, that's + * straightforward; just flip the level and continue */ + --pzx->puls_count; + pzx->level = !pzx->level; + if (pzx->puls_count) + { + pzx->puls_remain = pzx->puls_duration; + return time; + } + /* If we've reached the end of the pulse sequence, there may be + * another one */ + if (pzx->puls_ptr < pzx->puls_len) + { + return time; + } + /* If there isn't another one, it's the end of the block */ + pzx_endblock(pzx); + return time; +} + + +/* Decode a DATA block */ +static int pzx_advance_data(pzxfile_t *pzx, int time) +{ + uint8_t bit; + + /* Reached end of data? */ + if (pzx->data_bits == 0) + { + /* Time interval is covered by the tail bit */ + if (pzx->data_tail > time) + { + pzx->data_tail -= time; + return 0; + } + /* Have run out of block */ + time -= pzx->data_tail; + pzx_endblock(pzx); + return time; + } + /* No more time remaining on the current bit? */ + if (pzx->data_p < 1 && !pzx->data_remain) + { + bit = pzx->curblock[pzx->data_ptr] & pzx->data_mask; + pzx->data_mask >>= 1; + if (!pzx->data_mask) + { + pzx->data_mask = 0x80; + ++pzx->data_ptr; + } + --pzx->data_bits; + + if (bit) + { + pzx->data_p = pzx->data_p1; + pzx->data_w = 16 + 2 * pzx->data_p0; + pzx->data_remain = 0; + } + else + { + pzx->data_p = pzx->data_p0; + pzx->data_w = 16; + pzx->data_remain = 0; + } + } + /* See if we've started processing the current waveform. If not, + * load its first element (assuming that there is one) */ + if (!pzx->data_remain) + { + if (pzx->data_p) + { + pzx->data_remain = peek2(pzx->curblock + pzx->data_w); + pzx->data_w += 2; + pzx->data_p--; + } + } + if (pzx->data_remain > time) + { + /* Time advance is contained within current wave */ + pzx->data_remain -= time; + return 0; + } + else /* Move on to next element of wave / next bit / next block */ + { + time -= pzx->data_remain; + pzx->data_remain = 0; + pzx->level = !pzx->level; + } + + return time; +} + + + + +int pzx_advance(pzxfile_t *pzx, int time) +{ + if (pzx->state == PZX_CLOSED) return 0; /* No tape loaded */ + + while (time) + { + switch (pzx->state) + { + case PZX_IDLE: + if (!pzx_next_block(pzx)) return 0; + break; + case PZX_IN_PULS: + time = pzx_advance_puls(pzx, time); + break; + case PZX_IN_PAUS: + time = pzx_advance_paus(pzx, time); + break; + case PZX_IN_DATA: + time = pzx_advance_data(pzx, time); + break; + case PZX_CLOSED: /*Should never get here*/ + return 0; + + } + } + return pzx->level; +} + + + diff --git a/src/pzx.h b/src/pzx.h new file mode 100644 index 0000000..94d5ca1 --- /dev/null +++ b/src/pzx.h @@ -0,0 +1,71 @@ +/************************************************************************ + + PCem: IBM 5150 cassette support + + Copyright (C) 2019 John Elliott + + 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. + +*************************************************************************/ + +typedef enum +{ + PZX_CLOSED, /* File is not open */ + PZX_IDLE, /* File is open, no block loaded */ + PZX_IN_PULS, /* File is open, current block is a PULS block */ + PZX_IN_DATA, /* File is open, current block is a DATA block */ + PZX_IN_PAUS, /* File is open, current block is a PAUS block */ +} PZX_STATE; + + +typedef struct pzxfile_t +{ + FILE *input; /* Input PZX file */ + uint8_t *curblock; /* Currently-loaded block, if any */ + int level; /* Current signal level */ + PZX_STATE state; /* State machine current status */ +/* State variables for PULS */ + uint32_t puls_ptr; /* Pointer within PULS block */ + uint32_t puls_len; /* Length of PULS block */ + uint32_t puls_count; /* Count of pulses */ + uint32_t puls_duration; /* Duration of each pulse */ + uint32_t puls_remain; /* Time remaining in this pulse */ +/* State variables for PAUS */ + uint32_t paus_remain; /* Time remaining in this pause */ +/* State variables for DATA */ + uint32_t data_ptr; /* Pointer within DATA block */ + uint32_t data_bits; /* Count of bits */ + uint16_t data_tail; /* Length of pulse after last bit */ + uint8_t data_mask; /* Mask for current bit */ + uint8_t data_p0; /* Length of 0 encoding */ + uint8_t data_p1; /* Length of 1 encoding */ + int data_p; /* Current sequence being emitted */ + uint32_t data_w; /* Current waveform */ + uint32_t data_remain; /* Current data pulse time remaining */ +} pzxfile_t; + +uint8_t *pzx_load_block(FILE *fp); + +/* Initialise structure */ +void pzx_init(pzxfile_t *pzx); + +/* Open file for input */ +const char *pzx_open(pzxfile_t *pzx, FILE *fp); + +/* Close file */ +void pzx_close(pzxfile_t *pzx); + +/* Advance by 'time' samples (3.5MHz sample rate) and return current state */ +int pzx_advance(pzxfile_t *pzx, int time); diff --git a/src/resources.h b/src/resources.h index 932eda4..02b4772 100644 --- a/src/resources.h +++ b/src/resources.h @@ -10,6 +10,8 @@ #define IDM_BPB_DISABLE 40015 #define IDM_CONFIG 40020 #define IDM_STATUS 40030 +#define IDM_CASSETTE_LOAD 40040 +#define IDM_CASSETTE_EJECT 40041 #define IDM_VID_RESIZE 40050 #define IDM_VID_REMEMBER 40051 #define IDM_VID_ASPECT 40052 @@ -21,10 +23,13 @@ #define IDM_VID_FS_43 40072 #define IDM_VID_FS_SQ 40073 #define IDM_VID_FS_INT 40074 +#define IDM_BUF_100MS 40080 +#define IDM_BUF_200MS 40081 +#define IDM_BUF_400MS 40082 #define IDM_CDROM_EMPTY 40100 #define IDM_CDROM_REAL 40100 #define IDM_CDROM_DISABLED 40200 -#define IDM_CDROM_ISO 40201 +#define IDM_CDROM_IMAGE 40201 #define IDC_COMBO1 1000 #define IDC_COMBOVID 1001 @@ -41,6 +46,7 @@ #define IDC_COMBOWS 1065 #define IDC_COMBOMOUSE 1066 #define IDC_COMBOHDD 1067 +#define IDC_COMBONETCARD 1068 #define IDC_CHECK1 1010 #define IDC_CHECK2 1011 #define IDC_CHECK3 1012 @@ -118,11 +124,13 @@ #define IDC_EDIT_F_FN 1233 #define IDC_HDTYPE 1280 +#define IDC_HDFORMAT 1281 #define IDC_CONFIGUREVID 1200 #define IDC_CONFIGURESND 1201 #define IDC_CONFIGUREVOODOO 1202 #define IDC_CONFIGUREMOD 1203 +#define IDC_CONFIGURENETCARD 1204 #define IDC_JOY1 1210 #define IDC_JOY2 1211 #define IDC_JOY3 1212 @@ -137,3 +145,7 @@ #define IDC_LIST 1201 #define IDC_CONFIG 1202 #define IDC_HDCONF 1203 +#define IDC_NETWORK 1204 + +#define IDC_COMBONETTYPE 1200 +#define IDC_COMBONETDEVICE 1201 diff --git a/src/rom.c b/src/rom.c index abbca06..f326326 100644 --- a/src/rom.c +++ b/src/rom.c @@ -4,25 +4,30 @@ #include "config.h" #include "mem.h" #include "rom.h" +#include "paths.h" FILE *romfopen(char *fn, char *mode) { + FILE *f; char s[512]; - strcpy(s, pcempath); - put_backslash(s); - strcat(s, fn); - return fopen(s, mode); + int i; + + for (i = 0; i < num_roms_paths; ++i) + { + get_roms_path(i, s, 511); + put_backslash(s); + strcat(s, fn); + f = fopen(s, mode); + if (f) + return f; + } + return 0; } int rom_present(char *fn) { FILE *f; - char s[512]; - - strcpy(s, pcempath); - put_backslash(s); - strcat(s, fn); - f = fopen(s, "rb"); + f = romfopen(fn, "rb"); if (f) { fclose(f); @@ -31,7 +36,7 @@ int rom_present(char *fn) return 0; } -static uint8_t rom_read(uint32_t addr, void *p) +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]); @@ -74,7 +79,7 @@ int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int fil mem_write_nullw, mem_write_nulll, rom->rom, - flags, + flags | MEM_MAPPING_ROM, rom); return 0; @@ -119,7 +124,7 @@ int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t addre mem_write_nullw, mem_write_nulll, rom->rom, - flags, + flags | MEM_MAPPING_ROM, rom); return 0; diff --git a/src/rom.h b/src/rom.h index 06ace63..5e578ed 100644 --- a/src/rom.h +++ b/src/rom.h @@ -1,3 +1,6 @@ +#ifndef _ROM_H_ +#define _ROM_H_ + FILE *romfopen(char *fn, char *mode); int rom_present(char *fn); @@ -10,3 +13,9 @@ typedef struct 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); + +uint8_t rom_read(uint32_t addr, void *p); +uint16_t rom_readw(uint32_t addr, void *p); +uint32_t rom_readl(uint32_t addr, void *p); + +#endif diff --git a/src/rtc.c b/src/rtc.c index d1a0515..323e5a6 100644 --- a/src/rtc.c +++ b/src/rtc.c @@ -42,7 +42,7 @@ static int rtc_is_leap(int org_year) static int rtc_get_days(int org_month, int org_year) { if (org_month != 2) - return rtc_days_in_month[org_month]; + return rtc_days_in_month[org_month-1]; else return rtc_is_leap(org_year) ? 29 : 28; } diff --git a/src/rtc_tc8521.c b/src/rtc_tc8521.c new file mode 100644 index 0000000..cfc1a36 --- /dev/null +++ b/src/rtc_tc8521.c @@ -0,0 +1,221 @@ +/* Emulation of: + Toshiba TC8521 Real Time Clock */ + +#include +#include +#include +#include +#include +#include "nvr.h" +#include "rtc_tc8521.h" + +#define peek2(a) (nvrram[(a##1)] + 10 * nvrram[(a##10)]) + +struct +{ + int sec; + int min; + int hour; + int mday; + int mon; + int year; +} internal_clock; + +/* Table for days in each month */ +static int rtc_days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +/* Called to determine whether the year is leap or not */ +static int rtc_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; +} + +/* Called to determine the days in the current month */ +static int rtc_get_days(int org_month, int org_year) +{ + if (org_month != 2) + return rtc_days_in_month[org_month-1]; + else + return rtc_is_leap(org_year) ? 29 : 28; +} + +/* Called when the internal clock gets updated */ +static void tc8521_recalc() +{ + if (internal_clock.sec == 60) + { + internal_clock.sec = 0; + internal_clock.min++; + } + if (internal_clock.min == 60) + { + internal_clock.min = 0; + internal_clock.hour++; + } + if (internal_clock.hour == 24) + { + internal_clock.hour = 0; + internal_clock.mday++; + } + if (internal_clock.mday == (rtc_get_days(internal_clock.mon, internal_clock.year) + 1)) + { + internal_clock.mday = 1; + internal_clock.mon++; + } + if (internal_clock.mon == 13) + { + internal_clock.mon = 1; + internal_clock.year++; + } +} + +/* Called when ticking the second */ +void tc8521_tick() +{ + internal_clock.sec++; + tc8521_recalc(); +} + +/* Called when modifying the NVR registers */ +void tc8521_update(uint8_t *nvrram, int reg) +{ + int temp; + + switch(reg) + { + case TC8521_SECOND1: + case TC8521_SECOND10: + internal_clock.sec = peek2(TC8521_SECOND); + break; + case TC8521_MINUTE1: + case TC8521_MINUTE10: + internal_clock.min = peek2(TC8521_MINUTE); + break; + case TC8521_HOUR1: + case TC8521_HOUR10: + temp = peek2(TC8521_HOUR); + if (nvrram[TC8521_24HR] & 1) + internal_clock.hour = temp; + else + internal_clock.hour = ((temp & ~0x20) % 12) + ((temp & 0x20) ? 12 : 0); + break; + case TC8521_DAY1: + case TC8521_DAY10: + internal_clock.mday = peek2(TC8521_DAY); + break; + case TC8521_MONTH1: + case TC8521_MONTH10: + internal_clock.mon = peek2(TC8521_MONTH); + break; + case TC8521_YEAR1: + case TC8521_YEAR10: + internal_clock.year = 1980 + peek2(TC8521_YEAR); + break; + } +} + +/* Called to obtain the current day of the week based on the internal clock */ +static int time_week_day() +{ + int day_of_month = internal_clock.mday; + int month2 = internal_clock.mon; + int year2 = internal_clock.year % 100; + int century = ((internal_clock.year - year2) / 100) % 4; + int sum = day_of_month + month2 + year2 + century; + /* (Sum mod 7) gives 0 for Saturday, we need it for Sunday, so +6 for Saturday to get 6 and Sunday 0 */ + int raw_wd = ((sum + 6) % 7); + return raw_wd; +} + +/* Called to get time into the internal clock */ +static void tc8521_internal_get(struct tm *time_var) +{ + time_var->tm_sec = internal_clock.sec; + time_var->tm_min = internal_clock.min; + time_var->tm_hour = internal_clock.hour; + time_var->tm_wday = time_week_day(); + time_var->tm_mday = internal_clock.mday; + time_var->tm_mon = internal_clock.mon - 1; + time_var->tm_year = internal_clock.year - 1900; +} + +static void tc8521_internal_set(struct tm *time_var) +{ + internal_clock.sec = time_var->tm_sec; + internal_clock.min = time_var->tm_min; + internal_clock.hour = time_var->tm_hour; + internal_clock.mday = time_var->tm_mday; + internal_clock.mon = time_var->tm_mon + 1; + internal_clock.year = time_var->tm_year + 1900; +} + +static void tc8521_set_nvrram(uint8_t *nvrram, struct tm *cur_time_tm) +{ + nvrram[TC8521_SECOND1] = cur_time_tm->tm_sec % 10; + nvrram[TC8521_SECOND10] = cur_time_tm->tm_sec / 10; + nvrram[TC8521_MINUTE1] = cur_time_tm->tm_min % 10; + nvrram[TC8521_MINUTE10] = cur_time_tm->tm_min / 10; + if (nvrram[TC8521_24HR] & 1) + { + nvrram[TC8521_HOUR1] = cur_time_tm->tm_hour % 10; + nvrram[TC8521_HOUR10] = cur_time_tm->tm_hour / 10; + } + else + { + nvrram[TC8521_HOUR1] = (cur_time_tm->tm_hour % 12) % 10; + nvrram[TC8521_HOUR10] = ((cur_time_tm->tm_hour % 12) / 10) + | (cur_time_tm->tm_hour >= 12) ? 2 : 0; + } + nvrram[TC8521_WEEKDAY] = cur_time_tm->tm_wday; + nvrram[TC8521_DAY1] = cur_time_tm->tm_mday % 10; + nvrram[TC8521_DAY10] = cur_time_tm->tm_mday / 10; + nvrram[TC8521_MONTH1] = (cur_time_tm->tm_mon + 1) / 10; + nvrram[TC8521_MONTH10] = (cur_time_tm->tm_mon + 1) % 10; + nvrram[TC8521_YEAR1] = (cur_time_tm->tm_year - 80) % 10; + nvrram[TC8521_YEAR10] = ((cur_time_tm->tm_year - 80) % 100) / 10; +} + + +void tc8521_internal_set_nvrram(uint8_t *nvrram) +{ + /* Load the entire internal clock state from the NVR. */ + internal_clock.sec = peek2(TC8521_SECOND); + internal_clock.min = peek2(TC8521_MINUTE); + if (nvrram[TC8521_24HR] & 1) + { + internal_clock.hour = peek2(TC8521_HOUR); + } + else + { + internal_clock.hour = (peek2(TC8521_HOUR) % 12) + + (nvrram[TC8521_HOUR10] & 2) ? 12 : 0; + } + internal_clock.mday = peek2(TC8521_DAY); + internal_clock.mon = peek2(TC8521_MONTH); + internal_clock.year = 1980 + peek2(TC8521_YEAR); +} + +void tc8521_internal_sync(uint8_t *nvrram) +{ + struct tm *cur_time_tm; + time_t cur_time; + + time(&cur_time); + cur_time_tm = localtime(&cur_time); + + tc8521_internal_set(cur_time_tm); + + tc8521_set_nvrram(nvrram, cur_time_tm); +} + +void tc8521_get(uint8_t *nvrram) +{ + struct tm cur_time_tm; + + tc8521_internal_get(&cur_time_tm); + + tc8521_set_nvrram(nvrram, &cur_time_tm); +} diff --git a/src/rtc_tc8521.h b/src/rtc_tc8521.h new file mode 100644 index 0000000..158bd97 --- /dev/null +++ b/src/rtc_tc8521.h @@ -0,0 +1,33 @@ + +/* The TC8521 is a 4-bit RTC, so each memory location can only hold a single + * BCD digit. Hence everything has 'ones' and 'tens' digits. */ +enum TC8521_ADDR +{ + /* Page 0 registers */ + TC8521_SECOND1, + TC8521_SECOND10, + TC8521_MINUTE1, + TC8521_MINUTE10, + TC8521_HOUR1, + TC8521_HOUR10, + TC8521_WEEKDAY, + TC8521_DAY1, + TC8521_DAY10, + TC8521_MONTH1, + TC8521_MONTH10, + TC8521_YEAR1, + TC8521_YEAR10, + TC8521_PAGE, /* PAGE register */ + TC8521_TEST, /* TEST register */ + TC8521_RESET, /* RESET register */ + /* Page 1 registers */ + TC8521_24HR = 0x1A, + TC8521_LEAPYEAR = 0x1B +}; + + +void tc8521_tick(); +void tc8521_update(uint8_t *nvrram, int reg); +void tc8521_get(uint8_t *nvrram); +void tc8521_internal_set_nvrram(uint8_t *nvrram); +void tc8521_internal_sync(uint8_t *nvrram); diff --git a/src/scamp.c b/src/scamp.c new file mode 100644 index 0000000..93c716f --- /dev/null +++ b/src/scamp.c @@ -0,0 +1,766 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "scamp.h" + +static struct +{ + int cfg_index; + uint8_t cfg_regs[256]; + int cfg_enable; + + int ram_config; + + mem_mapping_t ram_mapping[2]; + uint32_t ram_virt_base[2], ram_phys_base[2]; + uint32_t ram_mask[2]; + int row_virt_shift[2], row_phys_shift[2]; + int ram_interleaved[2]; + int ibank_shift[2]; + + uint8_t port_92; +} scamp; + +#define CFG_ID 0x00 +#define CFG_SLTPTR 0x02 +#define CFG_RAMMAP 0x03 +#define CFG_EMSEN1 0x0b +#define CFG_EMSEN2 0x0c +#define CFG_ABAXS 0x0e +#define CFG_CAXS 0x0f +#define CFG_DAXS 0x10 +#define CFG_FEAXS 0x11 + +#define ID_VL82C311 0xd6 + +#define RAMMAP_REMP386 (1 << 4) + +/*Commodore SL386SX requires proper memory slot decoding to detect memory size. + Therefore we emulate the SCAMP memory address decoding, and therefore are + limited to the DRAM combinations supported by the actual chip*/ +enum +{ + BANK_NONE, + BANK_256K, + BANK_256K_INTERLEAVED, + BANK_1M, + BANK_1M_INTERLEAVED, + BANK_4M, + BANK_4M_INTERLEAVED +}; + +static const struct +{ + int size_kb; + int rammap; + int bank[2]; +} ram_configs[] = +{ + {512, 0x0, {BANK_256K, BANK_NONE}}, + {1024, 0x1, {BANK_256K_INTERLEAVED, BANK_NONE}}, + {1536, 0x2, {BANK_256K_INTERLEAVED, BANK_256K}}, + {2048, 0x3, {BANK_256K_INTERLEAVED, BANK_256K_INTERLEAVED}}, + {3072, 0xc, {BANK_256K_INTERLEAVED, BANK_1M}}, + {4096, 0x5, {BANK_1M_INTERLEAVED, BANK_NONE}}, + {5120, 0xd, {BANK_256K_INTERLEAVED, BANK_1M_INTERLEAVED}}, + {6144, 0x6, {BANK_1M_INTERLEAVED, BANK_1M}}, + {8192, 0x7, {BANK_1M_INTERLEAVED, BANK_1M_INTERLEAVED}}, + {12288, 0xe, {BANK_1M_INTERLEAVED, BANK_4M}}, + {16384, 0x9, {BANK_4M_INTERLEAVED, BANK_NONE}}, +}; + +static const struct +{ + int bank[2]; + int remapped; +} rammap[16] = +{ + {{BANK_256K, BANK_NONE}, 0}, + {{BANK_256K_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_256K_INTERLEAVED, BANK_256K}, 0}, + {{BANK_256K_INTERLEAVED, BANK_256K_INTERLEAVED}, 0}, + + {{BANK_1M, BANK_NONE}, 0}, + {{BANK_1M_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_1M_INTERLEAVED, BANK_1M}, 0}, + {{BANK_1M_INTERLEAVED, BANK_1M_INTERLEAVED}, 0}, + + {{BANK_4M, BANK_NONE}, 0}, + {{BANK_4M_INTERLEAVED, BANK_NONE}, 0}, + {{BANK_NONE, BANK_4M}, 1}, /*Bank 2 remapped to 0*/ + {{BANK_NONE, BANK_4M_INTERLEAVED}, 1}, /*Banks 2/3 remapped to 0/1*/ + + {{BANK_256K_INTERLEAVED, BANK_1M}, 0}, + {{BANK_256K_INTERLEAVED, BANK_1M_INTERLEAVED}, 0}, + {{BANK_1M_INTERLEAVED, BANK_4M}, 0}, + {{BANK_1M_INTERLEAVED, BANK_4M_INTERLEAVED}, 0}, /*Undocumented - probably wrong!*/ +}; + +/*The column bits masked when using 256kbit DRAMs in 4Mbit mode aren't contiguous, + so we use separate routines for that special case*/ +static uint8_t ram_mirrored_256k_in_4mi_read(uint32_t addr, void *p) +{ + int bank = (intptr_t)p; + int row, column, byte; + + addr -= scamp.ram_virt_base[bank]; + byte = addr & 1; + if (!scamp.ram_interleaved[bank]) + { + if (addr & 0x400) + return 0xff; + + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & scamp.ram_mask[bank]; + row = ((addr & 0xff000) >> 13) | (((addr & 0x200000) >> 22) << 9); + + addr = byte | (column << 1) | (row << scamp.row_phys_shift[bank]); + } + else + { + column = (addr >> 1) & ((scamp.ram_mask[bank] << 1) | 1); + row = ((addr & 0x1fe000) >> 13) | (((addr & 0x400000) >> 22) << 9); + + addr = byte | (column << 1) | (row << (scamp.row_phys_shift[bank]+1)); + } + + return ram[addr + scamp.ram_phys_base[bank]]; +} +static void ram_mirrored_256k_in_4mi_write(uint32_t addr, uint8_t val, void *p) +{ + int bank = (intptr_t)p; + int row, column, byte; + + addr -= scamp.ram_virt_base[bank]; + byte = addr & 1; + if (!scamp.ram_interleaved[bank]) + { + if (addr & 0x400) + return; + + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & scamp.ram_mask[bank]; + row = ((addr & 0xff000) >> 13) | (((addr & 0x200000) >> 22) << 9); + + addr = byte | (column << 1) | (row << scamp.row_phys_shift[bank]); + } + else + { + column = (addr >> 1) & ((scamp.ram_mask[bank] << 1) | 1); + row = ((addr & 0x1fe000) >> 13) | (((addr & 0x400000) >> 22) << 9); + + addr = byte | (column << 1) | (row << (scamp.row_phys_shift[bank]+1)); + } + + ram[addr + scamp.ram_phys_base[bank]] = val; +} + +/*Read/write handlers for interleaved memory banks. We must keep CPU and ram array + mapping linear, otherwise we won't be able to execute code from interleaved banks*/ +static uint8_t ram_mirrored_interleaved_read(uint32_t addr, void *p) +{ + int bank = (intptr_t)p; + int row, column, byte; + + addr -= scamp.ram_virt_base[bank]; + byte = addr & 1; + if (!scamp.ram_interleaved[bank]) + { + if (addr & 0x400) + return 0xff; + + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & scamp.ram_mask[bank]; + row = (addr >> scamp.row_virt_shift[bank]) & scamp.ram_mask[bank]; + + addr = byte | (column << 1) | (row << scamp.row_phys_shift[bank]); + } + else + { + column = (addr >> 1) & ((scamp.ram_mask[bank] << 1) | 1); + row = (addr >> (scamp.row_virt_shift[bank]+1)) & scamp.ram_mask[bank]; + + addr = byte | (column << 1) | (row << (scamp.row_phys_shift[bank]+1)); + } + + return ram[addr + scamp.ram_phys_base[bank]]; +} +static void ram_mirrored_interleaved_write(uint32_t addr, uint8_t val, void *p) +{ + int bank = (intptr_t)p; + int row, column, byte; + + addr -= scamp.ram_virt_base[bank]; + byte = addr & 1; + if (!scamp.ram_interleaved[bank]) + { + if (addr & 0x400) + return; + + addr = (addr & 0x3ff) | ((addr & ~0x7ff) >> 1); + column = (addr >> 1) & scamp.ram_mask[bank]; + row = (addr >> scamp.row_virt_shift[bank]) & scamp.ram_mask[bank]; + + addr = byte | (column << 1) | (row << scamp.row_phys_shift[bank]); + } + else + { + column = (addr >> 1) & ((scamp.ram_mask[bank] << 1) | 1); + row = (addr >> (scamp.row_virt_shift[bank]+1)) & scamp.ram_mask[bank]; + + addr = byte | (column << 1) | (row << (scamp.row_phys_shift[bank]+1)); + } + + ram[addr + scamp.ram_phys_base[bank]] = val; +} + +static uint8_t ram_mirrored_read(uint32_t addr, void *p) +{ + int bank = (intptr_t)p; + int row, column, byte; + + addr -= scamp.ram_virt_base[bank]; + byte = addr & 1; + column = (addr >> 1) & scamp.ram_mask[bank]; + row = (addr >> scamp.row_virt_shift[bank]) & scamp.ram_mask[bank]; + addr = byte | (column << 1) | (row << scamp.row_phys_shift[bank]); + + return ram[addr + scamp.ram_phys_base[bank]]; +} +static void ram_mirrored_write(uint32_t addr, uint8_t val, void *p) +{ + int bank = (intptr_t)p; + int row, column, byte; + + addr -= scamp.ram_virt_base[bank]; + byte = addr & 1; + column = (addr >> 1) & scamp.ram_mask[bank]; + row = (addr >> scamp.row_virt_shift[bank]) & scamp.ram_mask[bank]; + addr = byte | (column << 1) | (row << scamp.row_phys_shift[bank]); + + ram[addr + scamp.ram_phys_base[bank]] = val; +} + +static void recalc_mappings(void) +{ + int c; + uint32_t virt_base = 0; + uint8_t cur_rammap = scamp.cfg_regs[CFG_RAMMAP] & 0xf; + intptr_t bank_nr = 0; + + for (c = 0; c < 2; c++) + mem_mapping_disable(&scamp.ram_mapping[c]); + + /*Once the BIOS programs the correct DRAM configuration, switch to regular + linear memory mapping*/ + if (cur_rammap == ram_configs[scamp.ram_config].rammap) + { + mem_mapping_set_handler(&ram_low_mapping, + mem_read_ram, mem_read_ramw, mem_read_raml, + mem_write_ram, mem_write_ramw, mem_write_raml); + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_enable(&ram_high_mapping); + return; + } + else + { + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + mem_mapping_disable(&ram_low_mapping); + } + + if (rammap[cur_rammap].bank[0] == BANK_NONE) + bank_nr = 1; + + pclog("Bank remap, cur_rammap=%x\n", cur_rammap); + + for (; bank_nr < 2; bank_nr++) + { + uint32_t old_virt_base = virt_base; + int phys_bank = ram_configs[scamp.ram_config].bank[bank_nr]; + + pclog(" Bank %i: phys_bank=%i rammap_bank=%i virt_base=%08x phys_base=%08x\n", bank_nr, phys_bank, rammap[cur_rammap].bank[bank_nr], virt_base, scamp.ram_phys_base[bank_nr]); + scamp.ram_virt_base[bank_nr] = virt_base; + + if (virt_base == 0) + { + switch (rammap[cur_rammap].bank[bank_nr]) + { + case BANK_NONE: + fatal("Bank 0 is empty!\n"); + break; + + case BANK_256K: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&ram_low_mapping, 0, 0x80000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + } + virt_base += 512*1024; + scamp.row_virt_shift[bank_nr] = 10; + break; + + case BANK_256K_INTERLEAVED: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + } + virt_base += 512*1024*2; + scamp.row_virt_shift[bank_nr] = 10; + break; + + case BANK_1M: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], 0x100000, 0x100000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr] + 0x100000]); + } + virt_base += 2048*1024; + scamp.row_virt_shift[bank_nr] = 11; + break; + + case BANK_1M_INTERLEAVED: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], 0x100000, 0x300000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr] + 0x100000]); + } + virt_base += 2048*1024*2; + scamp.row_virt_shift[bank_nr] = 11; + break; + + case BANK_4M: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], 0x100000, 0x700000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr] + 0x100000]); + } + virt_base += 8192*1024; + scamp.row_virt_shift[bank_nr] = 12; + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&ram_low_mapping, 0, 0xa0000); + mem_mapping_set_p(&ram_low_mapping, (void *)bank_nr); + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], 0x100000, 0xf00000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr] + 0x100000]); + } + virt_base += 8192*1024*2; + scamp.row_virt_shift[bank_nr] = 12; + break; + } + } + else + { + switch (rammap[cur_rammap].bank[bank_nr]) + { + case BANK_NONE: + break; + + case BANK_256K: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], virt_base, 0x80000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr]]); + } + virt_base += 512*1024; + scamp.row_virt_shift[bank_nr] = 10; + break; + + case BANK_256K_INTERLEAVED: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], virt_base, 0x100000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr]]); + } + virt_base += 512*1024*2; + scamp.row_virt_shift[bank_nr] = 10; + break; + + case BANK_1M: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], virt_base, 0x200000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr]]); + } + virt_base += 2048*1024; + scamp.row_virt_shift[bank_nr] = 11; + break; + + case BANK_1M_INTERLEAVED: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], virt_base, 0x400000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr]]); + } + virt_base += 2048*1024*2; + scamp.row_virt_shift[bank_nr] = 11; + break; + + case BANK_4M: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], virt_base, 0x800000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr]]); + } + virt_base += 8192*1024; + scamp.row_virt_shift[bank_nr] = 12; + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank != BANK_NONE) + { + mem_mapping_set_addr(&scamp.ram_mapping[bank_nr], virt_base, 0x1000000); + mem_mapping_set_exec(&scamp.ram_mapping[bank_nr], &ram[scamp.ram_phys_base[bank_nr]]); + } + virt_base += 8192*1024*2; + scamp.row_virt_shift[bank_nr] = 12; + break; + } + } + switch (rammap[cur_rammap].bank[bank_nr]) + { + case BANK_256K: case BANK_1M: case BANK_4M: + mem_mapping_set_handler(&scamp.ram_mapping[bank_nr], + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + pclog(" not interleaved\n"); + break; + + case BANK_256K_INTERLEAVED: case BANK_1M_INTERLEAVED: + mem_mapping_set_handler(&scamp.ram_mapping[bank_nr], + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + pclog(" interleaved\n"); + break; + + case BANK_4M_INTERLEAVED: + if (phys_bank == BANK_256K || phys_bank == BANK_256K_INTERLEAVED) + { + mem_mapping_set_handler(&scamp.ram_mapping[bank_nr], + ram_mirrored_256k_in_4mi_read, NULL, NULL, + ram_mirrored_256k_in_4mi_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_256k_in_4mi_read, NULL, NULL, + ram_mirrored_256k_in_4mi_write, NULL, NULL); + pclog(" 256k in 4mi\n"); + } + else + { + mem_mapping_set_handler(&scamp.ram_mapping[bank_nr], + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + if (!old_virt_base) + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_interleaved_read, NULL, NULL, + ram_mirrored_interleaved_write, NULL, NULL); + pclog(" interleaved\n"); + } + break; + } + } +} + +#define NR_ELEMS(x) (sizeof(x) / sizeof(x[0])) + +static void shadow_control(uint32_t addr, uint32_t size, int state) +{ +// pclog("shadow_control: addr=%08x size=%04x state=%i\n", addr, size, state); + switch (state) + { + 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_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void scamp_write(uint16_t addr, uint8_t val, void *p) +{ +// pclog("scamp_write: addr=%04x val=%02x\n", addr, val); + switch (addr) + { + case 0x92: + if ((mem_a20_alt ^ val) & 2) + { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~scamp.port_92 & val) & 1) + { + softresetx86(); + cpu_set_edx(); + } + scamp.port_92 = val; + break; + + case 0xec: + if (scamp.cfg_enable) + scamp.cfg_index = val; + break; + + case 0xed: + if (scamp.cfg_enable) + { + if (scamp.cfg_index >= 0x02 && scamp.cfg_index <= 0x16) + { + scamp.cfg_regs[scamp.cfg_index] = val; +// pclog("SCAMP CFG[%02x]=%02x\n", scamp.cfg_index, val); + switch (scamp.cfg_index) + { + case CFG_SLTPTR: + break; + + case CFG_RAMMAP: + recalc_mappings(); + mem_mapping_disable(&ram_remapped_mapping); + if (scamp.cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386) + { + /*Enabling remapping will disable all shadowing*/ + mem_remap_top_384k(); + shadow_control(0xa0000, 0x60000, 0); + } + else + { + shadow_control(0xa0000, 0x8000, scamp.cfg_regs[CFG_ABAXS] & 3); + shadow_control(0xa8000, 0x8000, (scamp.cfg_regs[CFG_ABAXS] >> 2) & 3); + shadow_control(0xb0000, 0x8000, (scamp.cfg_regs[CFG_ABAXS] >> 4) & 3); + shadow_control(0xb8000, 0x8000, (scamp.cfg_regs[CFG_ABAXS] >> 6) & 3); + + shadow_control(0xc0000, 0x4000, scamp.cfg_regs[CFG_CAXS] & 3); + shadow_control(0xc4000, 0x4000, (scamp.cfg_regs[CFG_CAXS] >> 2) & 3); + shadow_control(0xc8000, 0x4000, (scamp.cfg_regs[CFG_CAXS] >> 4) & 3); + shadow_control(0xcc000, 0x4000, (scamp.cfg_regs[CFG_CAXS] >> 6) & 3); + + shadow_control(0xd0000, 0x4000, scamp.cfg_regs[CFG_DAXS] & 3); + shadow_control(0xd4000, 0x4000, (scamp.cfg_regs[CFG_DAXS] >> 2) & 3); + shadow_control(0xd8000, 0x4000, (scamp.cfg_regs[CFG_DAXS] >> 4) & 3); + shadow_control(0xdc000, 0x4000, (scamp.cfg_regs[CFG_DAXS] >> 6) & 3); + + shadow_control(0xe0000, 0x8000, scamp.cfg_regs[CFG_FEAXS] & 3); + shadow_control(0xe8000, 0x8000, (scamp.cfg_regs[CFG_FEAXS] >> 2) & 3); + shadow_control(0xf0000, 0x8000, (scamp.cfg_regs[CFG_FEAXS] >> 4) & 3); + shadow_control(0xf8000, 0x8000, (scamp.cfg_regs[CFG_FEAXS] >> 6) & 3); + } + break; + + case CFG_ABAXS: + if (!(scamp.cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) + { + shadow_control(0xa0000, 0x8000, val & 3); + shadow_control(0xa8000, 0x8000, (val >> 2) & 3); + shadow_control(0xb0000, 0x8000, (val >> 4) & 3); + shadow_control(0xb8000, 0x8000, (val >> 6) & 3); + } + break; + + case CFG_CAXS: + if (!(scamp.cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) + { + shadow_control(0xc0000, 0x4000, val & 3); + shadow_control(0xc4000, 0x4000, (val >> 2) & 3); + shadow_control(0xc8000, 0x4000, (val >> 4) & 3); + shadow_control(0xcc000, 0x4000, (val >> 6) & 3); + } + break; + + case CFG_DAXS: + if (!(scamp.cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) + { + shadow_control(0xd0000, 0x4000, val & 3); + shadow_control(0xd4000, 0x4000, (val >> 2) & 3); + shadow_control(0xd8000, 0x4000, (val >> 4) & 3); + shadow_control(0xdc000, 0x4000, (val >> 6) & 3); + } + break; + + case CFG_FEAXS: + if (!(scamp.cfg_regs[CFG_RAMMAP] & RAMMAP_REMP386)) + { + shadow_control(0xe0000, 0x8000, val & 3); + shadow_control(0xe8000, 0x8000, (val >> 2) & 3); + shadow_control(0xf0000, 0x8000, (val >> 4) & 3); + shadow_control(0xf8000, 0x8000, (val >> 6) & 3); + } + break; + } + } + } + break; + + case 0xee: + if (scamp.cfg_enable && mem_a20_alt) + { + scamp.port_92 &= ~2; + mem_a20_alt = 0; + mem_a20_recalc(); + } + break; + } +} + +uint8_t scamp_read(uint16_t addr, void *p) +{ + uint8_t ret = 0xff; + + switch (addr) + { + case 0x92: + ret = scamp.port_92; + break; + + case 0xed: + if (scamp.cfg_enable) + { + if (scamp.cfg_index >= 0x00 && scamp.cfg_index <= 0x16) + ret = scamp.cfg_regs[scamp.cfg_index]; + } + break; + + case 0xee: + if (!mem_a20_alt) + { + scamp.port_92 |= 2; + mem_a20_alt = 1; + mem_a20_recalc(); + } + break; + + case 0xef: + softresetx86(); + cpu_set_edx(); + break; + } + +// pclog("scamp_read: addr=%04x ret=%02x\n", addr, ret); + return ret; +} + +void scamp_init(void) +{ + uint32_t addr; + intptr_t c; + + memset(&scamp, 0, sizeof(scamp)); + scamp.cfg_regs[CFG_ID] = ID_VL82C311; + scamp.cfg_enable = 1; + + io_sethandler(0x0092, 0x0001, scamp_read, NULL, NULL, scamp_write, NULL, NULL, NULL); + io_sethandler(0x00e8, 0x0001, scamp_read, NULL, NULL, scamp_write, NULL, NULL, NULL); + io_sethandler(0x00ea, 0x0006, scamp_read, NULL, NULL, scamp_write, NULL, NULL, NULL); + io_sethandler(0x00f4, 0x0002, scamp_read, NULL, NULL, scamp_write, NULL, NULL, NULL); + io_sethandler(0x00f9, 0x0001, scamp_read, NULL, NULL, scamp_write, NULL, NULL, NULL); + io_sethandler(0x00fb, 0x0001, scamp_read, NULL, NULL, scamp_write, NULL, NULL, NULL); + + scamp.ram_config = 0; + + /*Find best fit configuration for the requested memory size*/ + for (c = 0; c < NR_ELEMS(ram_configs); c++) + { + if (mem_size < ram_configs[c].size_kb) + break; + + scamp.ram_config = c; + } + + mem_mapping_set_handler(&ram_low_mapping, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL); + mem_mapping_disable(&ram_high_mapping); + + addr = 0; + for (c = 0; c < 2; c++) + { + mem_mapping_add(&scamp.ram_mapping[c], 0, 0, + ram_mirrored_read, NULL, NULL, + ram_mirrored_write, NULL, NULL, + &ram[addr], MEM_MAPPING_INTERNAL, (void *)c); + mem_mapping_disable(&scamp.ram_mapping[c]); + + scamp.ram_phys_base[c] = addr; +// pclog("Bank calc : %i = %08x\n", c ,addr); + + switch (ram_configs[scamp.ram_config].bank[c]) + { + case BANK_NONE: + scamp.ram_mask[c] = 0; + scamp.ram_interleaved[c] = 0; + break; + + case BANK_256K: + addr += 512*1024; + scamp.ram_mask[c] = 0x1ff; + scamp.row_phys_shift[c] = 10; + scamp.ram_interleaved[c] = 0; + break; + + case BANK_256K_INTERLEAVED: + addr += 512*1024*2; + scamp.ram_mask[c] = 0x1ff; + scamp.row_phys_shift[c] = 10; + scamp.ibank_shift[c] = 19; + scamp.ram_interleaved[c] = 1; + break; + + case BANK_1M: + addr += 2048*1024; + scamp.ram_mask[c] = 0x3ff; + scamp.row_phys_shift[c] = 11; + scamp.ram_interleaved[c] = 0; + break; + + case BANK_1M_INTERLEAVED: + addr += 2048*1024*2; + scamp.ram_mask[c] = 0x3ff; + scamp.row_phys_shift[c] = 11; + scamp.ibank_shift[c] = 21; + scamp.ram_interleaved[c] = 1; + break; + + case BANK_4M: + addr += 8192*1024; + scamp.ram_mask[c] = 0x7ff; + scamp.row_phys_shift[c] = 12; + scamp.ram_interleaved[c] = 0; + break; + + case BANK_4M_INTERLEAVED: + addr += 8192*1024*2; + scamp.ram_mask[c] = 0x7ff; + scamp.row_phys_shift[c] = 12; + scamp.ibank_shift[c] = 23; + scamp.ram_interleaved[c] = 1; + break; + } + } + + mem_set_mem_state(0xfe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} diff --git a/src/scamp.h b/src/scamp.h new file mode 100644 index 0000000..a4785ca --- /dev/null +++ b/src/scamp.h @@ -0,0 +1 @@ +void scamp_init(void); diff --git a/src/scat.c b/src/scat.c index 10cdc6e..ca33af5 100644 --- a/src/scat.c +++ b/src/scat.c @@ -5,44 +5,92 @@ #include "mem.h" #include "scat.h" #include "x86.h" -#include "cpu.h" +#include "nmi.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_low_mapping[32]; +static mem_mapping_t scat_ems_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; -static mem_mapping_t scat_4000_9FFF_mapping[24]; -static mem_mapping_t scat_A000_BFFF_mapping; +static mem_mapping_t scat_remap_mapping[6]; +static mem_mapping_t scat_4000_EFFF_mapping[44]; +static mem_mapping_t scat_low_ROMCS_mapping[8]; + +static int scat_max_map[32] = { 0, 1, 1, 1, 2, 3, 4, 8, + 4, 8, 12, 16, 20, 24, 28, 32, + 0, 5, 9, 13, 6, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; +static int scatsx_max_map[32] = { 0, 1, 2, 1, 3, 4, 6, 10, + 5, 9, 13, 4, 8, 12, 16, 14, + 18, 22, 26, 20, 24, 28, 32, 18, + 20, 32, 0, 0, 0, 0, 0, 0 }; + +static int external_is_RAS = 0; + +static int scatsx_external_is_RAS[33] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0 }; + +uint8_t scat_read(uint16_t port, void *priv); +void scat_write(uint16_t port, uint8_t val, void *priv); + +void scat_romcs_state_update(uint8_t val) +{ + int i; + for(i = 0; i < 4; i++) + { + if (val & 1) + { + mem_mapping_enable(&scat_low_ROMCS_mapping[i << 1]); + mem_mapping_enable(&scat_low_ROMCS_mapping[(i << 1) + 1]); + } + else + { + mem_mapping_disable(&scat_low_ROMCS_mapping[i << 1]); + mem_mapping_disable(&scat_low_ROMCS_mapping[(i << 1) + 1]); + } + val >>= 1; + } + + for(i = 0; i < 4; i++) + { + if (val & 1) + { + mem_mapping_enable(&bios_mapping[i << 1]); + mem_mapping_enable(&bios_mapping[(i << 1) + 1]); + } + else + { + mem_mapping_disable(&bios_mapping[i << 1]); + mem_mapping_disable(&bios_mapping[(i << 1) + 1]); + } + val >>= 1; + } +} void scat_shadow_state_update() { int i, val; - for (i = 0; i < 24; i++) + if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) < 4) { - val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; - if (i < 8) + /*Less than 1MB low memory, no shadow RAM available*/ + for (i = 0; i < 24; i++) + mem_set_mem_state((i + 40) << 14, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + else + { + for (i = 0; i < 24; i++) { - val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; + val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL | MEM_WRITE_INTERNAL : MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; + mem_set_mem_state((i + 40) << 14, 0x4000, val); } - 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(); @@ -50,9 +98,9 @@ void scat_shadow_state_update() void scat_set_xms_bound(uint8_t val) { - uint32_t max_xms_size = (mem_size >= 16384) ? 0xFC0000 : mem_size << 10; + uint32_t max_xms_size = ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) || (scat_regs[SCAT_VERSION] >= 4) ? 0xFE0000 : 0xFC0000; - switch (val) + switch (val & 0x0F) { case 1: scat_xms_bound = 0x100000; @@ -73,38 +121,42 @@ void scat_set_xms_bound(uint8_t val) scat_xms_bound = 0x400000; break; case 7: - scat_xms_bound = 0x600000; + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x600000 : 0x500000; break; case 8: - scat_xms_bound = 0x800000; + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x800000 : 0x700000; break; case 9: - scat_xms_bound = 0xA00000; + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xA00000 : 0x800000; break; case 10: - scat_xms_bound = 0xC00000; + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xC00000 : 0x900000; break; case 11: - scat_xms_bound = 0xE00000; + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xE00000 : 0xA00000; + break; + case 12: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xB00000; + break; + case 13: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xC00000; + break; + case 14: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xD00000; + break; + case 15: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xF00000; break; default: - scat_xms_bound = (mem_size >= 16384 ? 0xFC0000 : mem_size << 10); + scat_xms_bound = max_xms_size; break; } - if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) + if ((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (val & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 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((val & 0x0F) == 0 || scat_xms_bound > 0x160000) + scat_xms_bound = 0x160000; +// 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) @@ -114,31 +166,847 @@ void scat_set_xms_bound(uint8_t val) { 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); +// 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); } + + mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) || (scat_regs[SCAT_VERSION] >= 4) ? 0x60000 : 0x40000); + if(scat_regs[SCAT_VERSION] & 0xF0) + { + int i; + for(i=0;i<8;i++) + { + if(val & 0x10) + mem_mapping_disable(&scat_high_mapping[i]); + else + mem_mapping_enable(&scat_high_mapping[i]); + } + } } 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; + int nbank; + if (p && (scat_regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) + addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; + + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) + { + switch((scat_regs[SCAT_EXTENDED_BOUNDARY] & ((scat_regs[SCAT_VERSION] & 0x0F) > 3 ? 0x40 : 0)) | (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F)) + { + case 0x41: + nbank = addr >> 19; + if(nbank < 4) + nbank = 1; + else if(nbank == 4) + nbank = 0; + else + nbank -= 3; + break; + case 0x42: + nbank = addr >> 19; + if(nbank < 8) + nbank = 1 + (nbank >> 2); + else if(nbank == 8) + nbank = 0; + else + nbank -= 6; + break; + case 0x43: + nbank = addr >> 19; + if(nbank < 12) + nbank = 1 + (nbank >> 2); + else if(nbank == 12) + nbank = 0; + else + nbank -= 9; + break; + case 0x44: + nbank = addr >> 19; + if(nbank < 4) + nbank = 2; + else if(nbank < 6) + nbank -= 4; + else + nbank -= 3; + break; + case 0x45: + nbank = addr >> 19; + if(nbank < 8) + nbank = 2 + (nbank >> 2); + else if(nbank < 10) + nbank -= 8; + else + nbank -= 6; + break; + default: + nbank = addr >> (((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 8 && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) ? 19 : 21); + break; + } + nbank &= (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + if ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3 && nbank == 2 && (addr & 0x7FFFF) < 0x60000 && mem_size > 640) + { + nbank = 1; + addr ^= 0x70000; + } + + if(external_is_RAS && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) + { + if(nbank == 3) + nbank = 7; + else + return 0xFFFFFFFF; + } + else if(!external_is_RAS && scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) + { + switch(nbank) + { + case 7: + nbank = 3; + break; + // Note - In the following cases, the chipset accesses multiple memory banks at the same time, so it's impossible to predict which memory bank is actually accessed. + case 5: + case 1: + nbank = 1; + break; + case 3: + nbank = 2; + break; + default: + nbank = 0; + break; + } + } + + if((scat_regs[SCAT_VERSION] & 0x0F) > 3 && (mem_size > 2048) && (mem_size & 1536)) + { + if((mem_size & 1536) == 512) + { + if(nbank == 0) + addr &= 0x7FFFF; + else + addr = 0x80000 + ((addr & 0x1FFFFF) | ((nbank - 1) << 21)); + } + else + { + if(nbank < 2) + addr = (addr & 0x7FFFF) | (nbank << 19); + else + addr = 0x100000 + ((addr & 0x1FFFFF) | ((nbank - 2) << 21)); + } + } + else + { + int nbanks_2048k, nbanks_512k; + if (mem_size <= ((scat_regs[SCAT_VERSION] & 0x0F) > 3 ? 2048 : 4096) && (((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 8) || external_is_RAS)) + { + nbanks_2048k = 0; + nbanks_512k = mem_size >> 9; + } + else + { + nbanks_2048k = mem_size >> 11; + nbanks_512k = (mem_size & 1536) >> 9; + } + if(nbank < nbanks_2048k || (nbanks_2048k > 0 && nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7))) + { + addr &= 0x1FFFFF; + addr |= (nbank << 21); + } + else if(nbank < nbanks_2048k + nbanks_512k || nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7)) + { + addr &= 0x7FFFF; + addr |= (nbanks_2048k << 21) | ((nbank - nbanks_2048k) << 19); + } + else + { + addr &= 0x1FFFF; + addr |= (nbanks_2048k << 21) | (nbanks_512k << 19) | ((nbank - nbanks_2048k - nbanks_512k) << 17); + } + } + } + else + { + uint32_t addr2; + switch(scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) + { + case 2: + case 4: + nbank = addr >> 19; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) + { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } + else + addr2 = addr >> 10; + break; + case 3: + nbank = addr >> 19; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) + { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } + else if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) == 2 && (addr & 0x7FFFF) < 0x60000) + { + addr ^= 0x1F0000; + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } + else + addr2 = addr >> 10; + break; + case 5: + nbank = addr >> 19; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) + { + nbank = (addr >> 10) & 3; + addr2 = addr >> 12; + } + else + addr2 = addr >> 10; + break; + case 6: + nbank = addr >> 19; + if(nbank < 2) + { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } + else + { + nbank = 2 + ((addr - 0x100000) >> 21); + addr2 = (addr - 0x100000) >> 11; + } + break; + case 7: + case 0x0F: + nbank = addr >> 19; + if(nbank < 2) + { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } + else if(nbank < 10) + { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } + else + { + nbank = 4 + ((addr - 0x500000) >> 21); + addr2 = (addr - 0x500000) >> 11; + } + break; + case 8: + nbank = addr >> 19; + if(nbank < 4) + { + nbank = 1; + addr2 = addr >> 11; + } + else if(nbank == 4) + { + nbank = 0; + addr2 = addr >> 10; + } + else + { + nbank -= 3; + addr2 = addr >> 10; + } + break; + case 9: + nbank = addr >> 19; + if(nbank < 8) + { + nbank = 1 + ((addr >> 11) & 1); + addr2 = addr >> 12; + } + else if(nbank == 8) + { + nbank = 0; + addr2 = addr >> 10; + } + else + { + nbank -= 6; + addr2 = addr >> 10; + } + break; + case 0x0A: + nbank = addr >> 19; + if(nbank < 8) + { + nbank = 1 + ((addr >> 11) & 1); + addr2 = addr >> 12; + } + else if(nbank < 12) + { + nbank = 3; + addr2 = addr >> 11; + } + else if(nbank == 12) + { + nbank = 0; + addr2 = addr >> 10; + } + else + { + nbank -= 9; + addr2 = addr >> 10; + } + break; + case 0x0B: + nbank = addr >> 21; + addr2 = addr >> 11; + break; + case 0x0C: + case 0x0D: + nbank = addr >> 21; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) + { + nbank = (addr >> 11) & 1; + addr2 = addr >> 12; + } + else + addr2 = addr >> 11; + break; + case 0x0E: + case 0x13: + nbank = addr >> 21; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) + { + nbank = (addr >> 11) & 3; + addr2 = addr >> 13; + } + else + addr2 = addr >> 11; + break; + case 0x10: + case 0x11: + nbank = addr >> 19; + if(nbank < 2) + { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } + else if(nbank < 10) + { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } + else if(nbank < 18) + { + nbank = 4 + (((addr - 0x500000) >> 11) & 1); + addr2 = (addr - 0x500000) >> 12; + } + else + { + nbank = 6 + ((addr - 0x900000) >> 21); + addr2 = (addr - 0x900000) >> 11; + } + break; + case 0x12: + nbank = addr >> 19; + if(nbank < 2) + { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } + else if(nbank < 10) + { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } + else + { + nbank = 4 + (((addr - 0x500000) >> 11) & 3); + addr2 = (addr - 0x500000) >> 13; + } + break; + case 0x14: + case 0x15: + nbank = addr >> 21; + if((nbank & 7) < 4) + { + nbank = (addr >> 11) & 3; + addr2 = addr >> 13; + } + else if((nbank & 7) < 6) + { + nbank = 4 + (((addr - 0x800000) >> 11) & 1); + addr2 = (addr - 0x800000) >> 12; + } + else + { + nbank = 6 + (((addr - 0xC00000) >> 11) & 3); + addr2 = (addr - 0xC00000) >> 13; + } + break; + case 0x16: + nbank = ((addr >> 21) & 4) | ((addr >> 11) & 3); + addr2 = addr >> 13; + break; + case 0x17: + if(external_is_RAS && (addr & 0x800) == 0) + return 0xFFFFFFFF; + nbank = addr >> 19; + if(nbank < 2) + { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } + else + { + nbank = 2 + ((addr - 0x100000) >> 23); + addr2 = (addr - 0x100000) >> 12; + } + break; + case 0x18: + if(external_is_RAS && (addr & 0x800) == 0) + return 0xFFFFFFFF; + nbank = addr >> 21; + if(nbank < 4) + { + nbank = 1; + addr2 = addr >> 12; + } + else if(nbank == 4) + { + nbank = 0; + addr2 = addr >> 11; + } + else + { + nbank -= 3; + addr2 = addr >> 11; + } + break; + case 0x19: + if(external_is_RAS && (addr & 0x800) == 0) + return 0xFFFFFFFF; + nbank = addr >> 23; + if((nbank & 3) < 2) + { + nbank = (addr >> 12) & 1; + addr2 = addr >> 13; + } + else + addr2 = addr >> 12; + break; + default: + if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 6) + { + nbank = addr >> 19; + addr2 = (addr >> 10) & 0x1FF; + } + else if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 0x17) + { + nbank = addr >> 21; + addr2 = (addr >> 11) & 0x3FF; + } + else + { + nbank = addr >> 23; + addr2 = (addr >> 12) & 0x7FF; + } + break; + } + + nbank &= (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) > 0x16 && nbank == 3) + return 0xFFFFFFFF; + + if(external_is_RAS && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) + { + if(nbank == 3) + nbank = 7; + else + return 0xFFFFFFFF; + } + else if(!external_is_RAS && scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) + { + switch(nbank) + { + case 7: + nbank = 3; + break; + // Note - In the following cases, the chipset accesses multiple memory banks at the same time, so it's impossible to predict which memory bank is actually accessed. + case 5: + case 1: + nbank = 1; + break; + case 3: + nbank = 2; + break; + default: + nbank = 0; + break; + } + } + + switch(mem_size & ~511) + { + case 1024: + case 1536: + addr &= 0x3FF; + if(nbank < 2) + addr |= (nbank << 10) | ((addr2 & 0x1FF) << 11); + else + addr |= ((addr2 & 0x1FF) << 10) | (nbank << 19); + break; + case 2048: + if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 5) + { + addr &= 0x3FF; + if(nbank < 4) + addr |= (nbank << 10) | ((addr2 & 0x1FF) << 12); + else + addr |= ((addr2 & 0x1FF) << 10) | (nbank << 19); + } + else + { + addr &= 0x7FF; + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + } + break; + case 2560: + if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else + { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); + } + break; + case 3072: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); + break; + case 4096: + case 6144: + addr &= 0x7FF; + if(nbank < 2) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 12); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + break; + case 4608: + if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) >= 8 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) <= 0x0A) || ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 0x18)) + { + if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else if(nbank < 3) + addr = 0x80000 + ((addr & 0x7FF) | ((nbank - 1) << 11) | ((addr2 & 0x3FF) << 12)); + else + addr = 0x480000 + ((addr & 0x3FF) | ((addr2 & 0x1FF) << 10) | ((nbank - 3) << 19)); + } + else if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else + { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); + } + break; + case 5120: + case 7168: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if(nbank < 4) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); + break; + case 6656: + if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) >= 8 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) <= 0x0A) || ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 0x18)) + { + if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else if(nbank < 3) + addr = 0x80000 + ((addr & 0x7FF) | ((nbank - 1) << 11) | ((addr2 & 0x3FF) << 12)); + else if(nbank == 3) + addr = 0x480000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11)); + else + addr = 0x680000 + ((addr & 0x3FF) | ((addr2 & 0x1FF) << 10) | ((nbank - 4) << 19)); + } + else if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else if(nbank == 1) + { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr = addr + 0x80000 + (addr2 << 11); + } + else + { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr = addr + 0x280000 + ((addr2 << 12) | ((nbank & 1) << 11) | (((nbank - 2) & 6) << 21)); + } + break; + case 8192: + addr &= 0x7FF; + if(nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + break; + case 9216: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if(external_is_RAS) + { + if(nbank < 6) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); + } + else + addr = 0x100000 + ((addr & 0xFFF) | ((addr2 & 0x7FF) << 12) | ((nbank - 2) << 23)); + break; + case 10240: + if(external_is_RAS) + { + addr &= 0x7FF; + if(nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + } + else if(nbank == 0) + addr = (addr & 0x7FF) | ((addr2 & 0x3FF) << 11); + else + { + addr &= 0xFFF; + addr2 &= 0x7FF; + addr = addr + 0x200000 + ((addr2 << 12) | ((nbank - 1) << 23)); + } + break; + case 11264: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if(nbank < 6) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); + break; + case 12288: + if(external_is_RAS) + { + addr &= 0x7FF; + if(nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); + else if(nbank < 6) + addr |= ((nbank & 1) << 11) | ((addr2 & 0x3FF) << 12) | ((nbank & 4) << 21); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + } + else + { + if(nbank < 2) + addr = (addr & 0x7FF) | (nbank << 11) | ((addr2 & 0x3FF) << 12); + else + addr = 0x400000 + ((addr & 0xFFF) | ((addr2 & 0x7FF) << 12) | ((nbank - 2) << 23)); + } + break; + case 13312: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if(nbank < 4) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x500000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 13) | ((nbank & 3) << 11)); + break; + case 14336: + addr &= 0x7FF; + if(nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); + else if(nbank < 6) + addr |= ((nbank & 1) << 11) | ((addr2 & 0x3FF) << 12) | ((nbank & 4) << 21); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + break; + case 16384: + if(external_is_RAS) + { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr |= ((nbank & 3) << 11) | (addr2 << 13) | ((nbank & 4) << 21); + } + else + { + addr &= 0xFFF; + addr2 &= 0x7FF; + if(nbank < 2) + addr |= (addr2 << 13) | (nbank << 12); + else + addr |= (addr2 << 12) | (nbank << 23); + } + break; + default: + if(mem_size < 2048 || ((mem_size & 1536) == 512) || (mem_size == 2048 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 6)) + { + addr &= 0x3FF; + addr2 &= 0x1FF; + addr |= (addr2 << 10) | (nbank << 19); + } + else if(mem_size < 8192 || (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 0x17) + { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr |= (addr2 << 11) | (nbank << 21); + } + else + { + addr &= 0xFFF; + addr2 &= 0x7FF; + addr |= (addr2 << 12) | (nbank << 23); + } + break; + } + } return addr; } +void scat_set_global_EMS_state(int state) +{ + int i; + uint32_t base_addr, virt_addr; + + for(i=((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0 : 24; i<32; i++) + { + base_addr = (i + 16) << 14; + if(i >= 24) + base_addr += 0x30000; + if(state && (scat_stat[i].regs_2x9 & 0x80)) + { + virt_addr = get_scat_addr(base_addr, &scat_stat[i]); + if(i < 24) mem_mapping_disable(&scat_4000_EFFF_mapping[i]); + else mem_mapping_disable(&scat_4000_EFFF_mapping[i + 12]); + mem_mapping_enable(&scat_ems_mapping[i]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[i], ram + virt_addr); + else mem_mapping_set_exec(&scat_ems_mapping[i], NULL); + } + else + { + mem_mapping_set_exec(&scat_ems_mapping[i], ram + base_addr); + mem_mapping_disable(&scat_ems_mapping[i]); + + int conf = (scat_regs[SCAT_VERSION] & 0xF0) ? (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) : (scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2); + if(i < 24) + { + if(conf > 1 || (conf == 1 && i < 16)) + mem_mapping_enable(&scat_4000_EFFF_mapping[i]); + else + mem_mapping_disable(&scat_4000_EFFF_mapping[i]); + } + else if(conf > 3 || ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && conf == 2)) + mem_mapping_enable(&scat_4000_EFFF_mapping[i + 12]); + else + mem_mapping_disable(&scat_4000_EFFF_mapping[i + 12]); + } + } + flushmmucache(); +} + +void scat_memmap_state_update() +{ + int i; + uint32_t addr; + + for(i=(((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0 : 16);i<44;i++) + { + addr = get_scat_addr(0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&scat_4000_EFFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); +// pclog("scat_memmap_state_update : Address %06X to %06X\n", 0x40000 + (i << 14), addr); + } + addr = get_scat_addr(0, NULL); +// pclog("scat_memmap_state_update : Address 000000 to %06X\n", addr); + mem_mapping_set_exec(&scat_low_mapping[0], addr < (mem_size << 10) ? ram + addr : NULL); + addr = get_scat_addr(0xF0000, NULL); +// pclog("scat_memmap_state_update : Address 0F0000 to %06X\n", addr); + mem_mapping_set_exec(&scat_low_mapping[1], addr < (mem_size << 10) ? ram + addr : NULL); + for(i=2;i<32;i++) + { + addr = get_scat_addr(i << 19, NULL); + mem_mapping_set_exec(&scat_low_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); +// pclog("scat_memmap_state_update : Address %06X to %06X\n", i << 19, addr); + } + + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) + { + for(i=0;i < scat_max_map[(scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2)];i++) + mem_mapping_enable(&scat_low_mapping[i]); + for(;i<32;i++) mem_mapping_disable(&scat_low_mapping[i]); + + for(i=24;i<36;i++) + { + if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40)) < 4) + mem_mapping_disable(&scat_4000_EFFF_mapping[i]); + else + mem_mapping_enable(&scat_4000_EFFF_mapping[i]); + } + } + else + { + for(i=0;i < scatsx_max_map[scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F];i++) + mem_mapping_enable(&scat_low_mapping[i]); + for(;i<32;i++) mem_mapping_disable(&scat_low_mapping[i]); + + for(i=24;i<36;i++) + { + if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 2 || (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3) + mem_mapping_disable(&scat_4000_EFFF_mapping[i]); + else + mem_mapping_enable(&scat_4000_EFFF_mapping[i]); + } + } + + if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((scat_regs[SCAT_VERSION] & 0xF0) != 0)) + { + if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3)) + { + mem_mapping_disable(&scat_low_mapping[2]); + for(i=0;i<6;i++) + { + addr = get_scat_addr(0x100000 + (i << 16), NULL); + mem_mapping_set_exec(&scat_remap_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); + mem_mapping_enable(&scat_remap_mapping[i]); +// pclog("scat_memmap_state_update : Address %06X to %06X\n", 0x100000 + (i << 16), addr); + } + } + else + { + for(i=0;i<6;i++) + mem_mapping_disable(&scat_remap_mapping[i]); + if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) > 4) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) > 3)) + mem_mapping_enable(&scat_low_mapping[2]); + } + } + else + { + for(i=0;i<6;i++) + mem_mapping_disable(&scat_remap_mapping[i]); + mem_mapping_enable(&scat_low_mapping[2]); + } + + scat_set_global_EMS_state(scat_regs[SCAT_EMS_CONTROL] & 0x80); +} + void scat_write(uint16_t port, uint8_t val, void *priv) { - uint8_t scat_reg_valid = 0, scat_shadow_update = 0, index; + uint8_t scat_reg_valid = 0, scat_shadow_update = 0, scat_map_update = 0, index; uint32_t base_addr, virt_addr; switch (port) @@ -150,61 +1018,107 @@ void scat_write(uint16_t port, uint8_t val, void *priv) case 0x23: switch (scat_index) { + case SCAT_DMA_WAIT_STATE_CONTROL: case SCAT_CLOCK_CONTROL: case SCAT_PERIPHERAL_CONTROL: + scat_reg_valid = 1; + break; 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 & 0x40) { - if((val & 0x0F) == 3) + if(val & 1) { - mem_mapping_enable(&scat_shadowram_mapping); + io_sethandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); } 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); + io_sethandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); } } - flushmmucache(); + else + { + io_removehandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + } + scat_set_global_EMS_state(val & 0x80); + scat_reg_valid = 1; + break; + case SCAT_POWER_MANAGEMENT: + cpu_set_nonturbo_divider((val & 0xc) > 0 ? 1 << ((val & 0xc) >> 2) : 0); + scat_reg_valid = 1; + break; + case SCAT_DRAM_CONFIGURATION: + scat_map_update = 1; + scat_shadow_update = 1; - cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; - cpu_update_waitstates(); + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) + { + cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; + cpu_update_waitstates(); + } scat_reg_valid = 1; break; case SCAT_EXTENDED_BOUNDARY: - scat_set_xms_bound(val & 0x0f); + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) + { + if(scat_regs[SCAT_VERSION] < 4) + { + val &= 0xBF; + scat_set_xms_bound(val & 0x0f); + } + else + { + val = (val & 0x7F) | 0x80; + scat_set_xms_bound(val & 0x4f); + } + } + else + scat_set_xms_bound(val & 0x1f); mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); - flushmmucache(); + if((val ^ scat_regs[SCAT_EXTENDED_BOUNDARY]) & 0xC0) scat_map_update = 1; scat_reg_valid = 1; break; case SCAT_ROM_ENABLE: + scat_reg_valid = 1; + scat_romcs_state_update(val); + break; case SCAT_RAM_WRITE_PROTECT: + scat_reg_valid = 1; + flushmmucache_cr3(); + break; 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; + case SCATSX_LAPTOP_FEATURES: + if((scat_regs[SCAT_VERSION] & 0xF0) != 0) + { + val = (val & ~8) | (scat_regs[SCATSX_LAPTOP_FEATURES] & 8); + scat_reg_valid = 1; + } + break; + case SCATSX_FAST_VIDEO_CONTROL: + case SCATSX_FAST_VIDEORAM_ENABLE: + case SCATSX_HIGH_PERFORMANCE_REFRESH: + case SCATSX_CAS_TIMING_FOR_DMA: + if((scat_regs[SCAT_VERSION] & 0xF0) != 0) scat_reg_valid = 1; + break; default: break; } if (scat_reg_valid) scat_regs[scat_index] = val; + else pclog("Attemped to write unimplemented SCAT register %02X at %04X:%04X\n", scat_index, val, CS, cpu_state.oldpc); 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); + if (scat_map_update) + scat_memmap_state_update(); +// pclog("Write SCAT Register %02X to %02X at %04X:%04X\n", scat_index, val, CS, cpu_state.pc); break; case 0x92: @@ -222,110 +1136,73 @@ void scat_write(uint16_t port, uint8_t val, void *priv) break; case 0x208: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - 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; +// pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; + else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; scat_stat[index].regs_2x8 = val; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x30000; - if(scat_stat[index].regs_2x9 & 0x80) + if((scat_regs[SCAT_EMS_CONTROL] & 0x80) && (scat_stat[index].regs_2x9 & 0x80)) { + virt_addr = get_scat_addr(base_addr, &scat_stat[index]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[index], ram + virt_addr); + else mem_mapping_set_exec(&scat_ems_mapping[index], NULL); flushmmucache(); } } break; case 0x209: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - 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; +// pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; + else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; scat_stat[index].regs_2x9 = val; base_addr = (index + 16) << 14; if(index >= 24) base_addr += 0x30000; - if (val & 0x80) + if (scat_regs[SCAT_EMS_CONTROL] & 0x80) { - virt_addr = get_scat_addr(base_addr, &scat_stat[index]); - if(index < 24) mem_mapping_disable(&scat_4000_9FFF_mapping[index]); - mem_mapping_set_exec(&scat_mapping[index], ram + virt_addr); - mem_mapping_enable(&scat_mapping[index]); - pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); + if (val & 0x80) + { + virt_addr = get_scat_addr(base_addr, &scat_stat[index]); + if(index < 24) mem_mapping_disable(&scat_4000_EFFF_mapping[index]); + else mem_mapping_disable(&scat_4000_EFFF_mapping[index + 12]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[index], ram + virt_addr); + else mem_mapping_set_exec(&scat_ems_mapping[index], NULL); + mem_mapping_enable(&scat_ems_mapping[index]); +// pclog("Map page %d(address %05X) to address %06X\n", index, base_addr, virt_addr); + } + else + { + mem_mapping_set_exec(&scat_ems_mapping[index], ram + base_addr); + mem_mapping_disable(&scat_ems_mapping[index]); + if(index < 24) mem_mapping_enable(&scat_4000_EFFF_mapping[index]); + else mem_mapping_enable(&scat_4000_EFFF_mapping[index + 12]); +// pclog("Unmap page %d(address %06X)\n", index, base_addr); + } + flushmmucache(); } - else - { - mem_mapping_set_exec(&scat_mapping[index], ram + base_addr); - mem_mapping_disable(&scat_mapping[index]); - if(index < 24) mem_mapping_enable(&scat_4000_9FFF_mapping[index]); - pclog("Unmap page %d(address %06X)\n", scat_ems_reg_2xA & 0x1f, base_addr); - } - flushmmucache(); if (scat_ems_reg_2xA & 0x80) { - scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & 0x1f); + scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & (((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0x1f : 3)); } } 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; - - if(scat_stat[index].regs_2x9 & 0x80) - { - flushmmucache(); - } - } - 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 = get_scat_addr(base_addr, &scat_stat[index]); - if(index < 24) mem_mapping_disable(&scat_4000_9FFF_mapping[index]); - mem_mapping_set_exec(&scat_mapping[index], ram + virt_addr); - mem_mapping_enable(&scat_mapping[index]); - pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); - } - else - { - mem_mapping_set_exec(&scat_mapping[index], ram + base_addr); - mem_mapping_disable(&scat_mapping[index]); - if(index < 24) mem_mapping_enable(&scat_4000_9FFF_mapping[index]); - pclog("Unmap page %d(address %05X)\n", scat_ems_reg_2xA & 0x1f, base_addr); - } - flushmmucache(); - - 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) + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); - scat_ems_reg_2xA = val; +// pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + scat_ems_reg_2xA = ((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? val : val & 0xc3; } break; } @@ -340,16 +1217,30 @@ uint8_t scat_read(uint16_t port, void *priv) switch (scat_index) { case SCAT_MISCELLANEOUS_STATUS: - val = (scat_regs[scat_index] & 0xbf) | ((mem_a20_key & 2) << 5); + val = (scat_regs[scat_index] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); + break; + case SCAT_POWER_MANAGEMENT: + val = (scat_regs[scat_index] & (cpu_get_turbo() ? 0xF3 : 0xFF)); break; case SCAT_DRAM_CONFIGURATION: - val = (scat_regs[scat_index] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10); + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) val = (scat_regs[scat_index] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10); + else val = scat_regs[scat_index]; + break; + case SCAT_EXTENDED_BOUNDARY: + val = scat_regs[scat_index]; + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) + { + if((scat_regs[SCAT_VERSION] & 0x0F) >= 4) + val |= 0x80; + else + val &= 0xAF; + } break; default: val = scat_regs[scat_index]; break; } - pclog("Read SCAT Register %02X at %04X:%04X\n", scat_index, CS, cpu_state.pc); +// pclog("Read SCAT Register %02X at %04X:%04X\n", scat_index, CS, cpu_state.pc); break; case 0x92: @@ -357,49 +1248,30 @@ uint8_t scat_read(uint16_t port, void *priv) break; case 0x208: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); - index = scat_ems_reg_2xA & 0x1F; +// pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; + else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; val = scat_stat[index].regs_2x8; } break; case 0x209: - if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); - index = scat_ems_reg_2xA & 0x1F; +// pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; + else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; 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) + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { - pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); +// pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); val = scat_ems_reg_2xA; } break; @@ -407,25 +1279,89 @@ uint8_t scat_read(uint16_t port, void *priv) return val; } -uint8_t mem_read_scatems(uint32_t addr, void *priv) +uint8_t mem_read_scatb(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); + val = ram[addr]; return val; } -void mem_write_scatems(uint32_t addr, uint8_t val, void *priv) +void mem_write_scatb(uint32_t addr, uint8_t val, void *priv) { scat_t *stat = (scat_t *)priv; + uint32_t oldaddr = addr, chkaddr; addr = get_scat_addr(addr, stat); + chkaddr = stat ? addr : oldaddr; + if (chkaddr >= 0xC0000 && chkaddr < 0x100000) + { + if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; + } if (addr < (mem_size << 10)) - mem_write_ram(addr, val, priv); + ram[addr] = val; +} + +uint16_t mem_read_scatw(uint32_t addr, void *priv) +{ + uint16_t val = 0xffff; + scat_t *stat = (scat_t *)priv; + + if((addr & 0x3FFF) == 0x3FFF) pclog("mem_read_scatw(%08X, %p) called.\n", addr, priv); + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = *(uint16_t *)&ram[addr]; + + return val; +} + +void mem_write_scatw(uint32_t addr, uint16_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + uint32_t oldaddr = addr, chkaddr; + + if((addr & 0x3FFF) == 0x3FFF) pclog("mem_write_scatw(%08X, %04X, %p) called.\n", addr, val, priv); + addr = get_scat_addr(addr, stat); + chkaddr = stat ? addr : oldaddr; + if (chkaddr >= 0xC0000 && chkaddr < 0x100000) + { + if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; + } + if (addr < (mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + +uint32_t mem_read_scatl(uint32_t addr, void *priv) +{ + uint32_t val = 0xffffffff; + scat_t *stat = (scat_t *)priv; + + if((addr & 0x3FFF) > 0x3FFC) pclog("mem_read_scatl(%08X, %p) called.\n", addr, priv); + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = *(uint32_t *)&ram[addr]; + + return val; +} + +void mem_write_scatl(uint32_t addr, uint32_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + uint32_t oldaddr = addr, chkaddr; + + if((addr & 0x3FFF) > 0x3FFC) pclog("mem_write_scatl(%08X, %08X, %p) called.\n", addr, val, priv); + addr = get_scat_addr(addr, stat); + chkaddr = stat ? addr : oldaddr; + if (chkaddr >= 0xC0000 && chkaddr < 0x100000) + { + if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; + } + if (addr < (mem_size << 10)) + *(uint32_t *)&ram[addr] = val; } void scat_init() @@ -434,8 +1370,6 @@ void scat_init() 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++) { @@ -443,7 +1377,17 @@ void scat_init() } scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; - scat_regs[SCAT_VERSION] = 10; + switch(romset) + { + case ROM_GW286CT: + case ROM_SPC4216P: + case ROM_SPC4620P: + scat_regs[SCAT_VERSION] = 4; + break; + default: + scat_regs[SCAT_VERSION] = 1; + break; + } scat_regs[SCAT_CLOCK_CONTROL] = 2; scat_regs[SCAT_PERIPHERAL_CONTROL] = 0x80; scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; @@ -456,48 +1400,129 @@ void scat_init() scat_regs[SCAT_DRAM_CONFIGURATION] = cpu_waitstates == 1 ? 2 : 0x12; scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; scat_regs[SCAT_EMS_CONTROL] = 0; + scat_port_92 = 0; - mem_mapping_set_addr(&ram_low_mapping, 0, 0x40000); - - for (i = 0; i < 24; i++) + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + for (i = 0; i < 4; i++) + mem_mapping_disable(&bios_mapping[i]); + mem_mapping_add(&scat_low_mapping[0], 0, 0x40000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_add(&scat_low_mapping[1], 0xF0000, 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + 0xF0000, MEM_MAPPING_INTERNAL, NULL); + for(i=2;i<32;i++) { - if(mem_size > 256 + (i << 4)) - { - mem_mapping_add(&scat_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0x40000 + (i << 14), MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&scat_4000_9FFF_mapping[i]); - } + mem_mapping_add(&scat_low_mapping[i], (i << 19), 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + (i << 19), MEM_MAPPING_INTERNAL, NULL); } + mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, scat_regs[SCAT_VERSION] < 4 ? 0x40000 : 0x60000); - mem_mapping_add(&scat_A000_BFFF_mapping, 0xA0000, 0x20000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_enable(&scat_A000_BFFF_mapping); + for (i = 0; i < 44; i++) + mem_mapping_add(&scat_4000_EFFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); + for (i = 0; i < 8; i++) + { + mem_mapping_add(&scat_low_ROMCS_mapping[i], 0xC0000 + (i << 14), 0x4000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); + mem_mapping_disable(&scat_low_ROMCS_mapping[i]); + } 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, NULL, NULL, mem_write_scatems, NULL, NULL, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); - mem_mapping_disable(&scat_mapping[i]); + mem_mapping_add(&scat_ems_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); } - for(i=4;i<10;i++) isram[i] = 0; - - // 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++) + for (i = (scat_regs[SCAT_VERSION] < 4 ? 0 : 8); 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); + 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) & biosmask), 0, NULL); + mem_mapping_enable(&scat_high_mapping[i]); } - if (mem_size == 1024) - { - mem_mapping_add(&scat_shadowram_mapping, 0x100000, 0x60000, mem_read_scatems, NULL, NULL, mem_write_scatems, NULL, NULL, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); - } + for(i=0;i<6;i++) + mem_mapping_add(&scat_remap_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, 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, NULL, NULL, mem_write_scatems, NULL, NULL, ram, MEM_MAPPING_INTERNAL, NULL); - mem_mapping_disable(&scat_512k_clip_mapping); - // --- + external_is_RAS = (scat_regs[SCAT_VERSION] > 3) || (((mem_size & ~2047) >> 11) + ((mem_size & 1536) >> 9) + ((mem_size & 511) >> 7)) > 4; scat_set_xms_bound(0); + scat_memmap_state_update(); + scat_shadow_state_update(); +} + +void scatsx_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); + + for (i = 0; i < 256; i++) + { + scat_regs[i] = 0xff; + } + + scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + scat_regs[SCAT_VERSION] = 0x13; + scat_regs[SCAT_CLOCK_CONTROL] = 6; + scat_regs[SCAT_PERIPHERAL_CONTROL] = 0; + 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] = 1; + scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; + scat_regs[SCAT_EMS_CONTROL] = 0; + scat_regs[SCATSX_LAPTOP_FEATURES] = 0; + scat_regs[SCATSX_FAST_VIDEO_CONTROL] = 0; + scat_regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0; + scat_regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8; + scat_regs[SCATSX_CAS_TIMING_FOR_DMA] = 3; + scat_port_92 = 0; + + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + for (i = 0; i < 4; i++) + mem_mapping_disable(&bios_mapping[i]); + mem_mapping_add(&scat_low_mapping[0], 0, 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_add(&scat_low_mapping[1], 0xF0000, 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + 0xF0000, MEM_MAPPING_INTERNAL, NULL); + for(i=2;i<32;i++) + { + mem_mapping_add(&scat_low_mapping[i], (i << 19), 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + (i << 19), MEM_MAPPING_INTERNAL, NULL); + } + mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, 0x40000); + + for (i = 16; i < 44; i++) + { + mem_mapping_add(&scat_4000_EFFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&scat_4000_EFFF_mapping[i]); + } + for (i = 0; i < 8; i++) + { + mem_mapping_add(&scat_low_ROMCS_mapping[i], 0xC0000 + (i << 14), 0x4000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); + mem_mapping_disable(&scat_low_ROMCS_mapping[i]); + } + + for (i = 24; i < 32; i++) + { + scat_stat[i].regs_2x8 = 0xff; + scat_stat[i].regs_2x9 = 0x03; + mem_mapping_add(&scat_ems_mapping[i], (i + 28) << 14, 0x04000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + ((i + 28) << 14), 0, &scat_stat[i]); + mem_mapping_disable(&scat_ems_mapping[i]); + } + + for (i = 0; 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) & biosmask), 0, NULL); + mem_mapping_enable(&scat_high_mapping[i]); + } + + for(i=0;i<6;i++) + mem_mapping_add(&scat_remap_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); + + external_is_RAS = scatsx_external_is_RAS[mem_size >> 9]; + + scat_set_xms_bound(0); + scat_memmap_state_update(); scat_shadow_state_update(); } diff --git a/src/scat.h b/src/scat.h index 8c822ec..cab41ba 100644 --- a/src/scat.h +++ b/src/scat.h @@ -13,6 +13,12 @@ #define SCAT_EXTENDED_BOUNDARY 0x4E #define SCAT_EMS_CONTROL 0x4F +#define SCATSX_LAPTOP_FEATURES 0x60 +#define SCATSX_FAST_VIDEO_CONTROL 0x61 +#define SCATSX_FAST_VIDEORAM_ENABLE 0x62 +#define SCATSX_HIGH_PERFORMANCE_REFRESH 0x63 +#define SCATSX_CAS_TIMING_FOR_DMA 0x64 + typedef struct scat_t { uint8_t regs_2x8; @@ -20,3 +26,4 @@ typedef struct scat_t } scat_t; void scat_init(); +void scatsx_init(); diff --git a/src/scsi.c b/src/scsi.c new file mode 100644 index 0000000..199ac6e --- /dev/null +++ b/src/scsi.c @@ -0,0 +1,394 @@ +#include "ibm.h" +#include "ide.h" +#include "ide_atapi.h" +#include "scsi.h" +#include "scsi_cd.h" +#include "scsi_hd.h" +#include "scsi_zip.h" + +#define STATE_IDLE 0 +#define STATE_COMMAND 1 +#define STATE_COMMANDWAIT 2 +#define STATE_DATAIN 3 +#define STATE_DATAOUT 4 +#define STATE_STATUS 5 +#define STATE_MESSAGEIN 6 +#define STATE_PHASESEL 7 + +#define SET_BUS_STATE(bus, state) bus->bus_out = (bus->bus_out & ~(BUS_CD | BUS_IO | BUS_MSG)) | (state & (BUS_CD | BUS_IO | BUS_MSG)) + +static int cmd_len[8] = {6, 10, 10, 6, 16, 12, 6, 6}; + +static int get_dev_id(uint8_t data) +{ + int c; + + for (c = 0; c < 8; c++) + { + if (data & (1 << c)) + return c; + } + + return -1; +} + +int scsi_bus_update(scsi_bus_t *bus, int bus_assert) +{ + scsi_device_t *dev = NULL; + void *dev_data = NULL; + +// pclog("scsi_hd_bus_update: state=%d bus_assert=%04x bus_in=%02x %i %02x %p\n", bus->state, bus_assert, bus->bus_in, bus->clear_req, bus->bus_out, bus); + + if (bus_assert & BUS_ARB) + bus->state = STATE_IDLE; + + if (bus->dev_id != -1) + { + dev = bus->devices[bus->dev_id]; + dev_data = bus->device_data[bus->dev_id]; + } + + switch (bus->state) + { + case STATE_IDLE: + bus->clear_req = bus->change_state_delay = bus->new_req_delay = 0; + if ((bus_assert & BUS_SEL) && !(bus_assert & BUS_BSY)) + { + uint8_t sel_data = BUS_GETDATA(bus_assert); + + //bus->state = STATE_PHASESEL; + bus->dev_id = get_dev_id(sel_data); +// pclog("PHASESEL %02x %2x %i %p\n", sel_data, bus->bus_out, bus->dev_id, bus->devices[bus->dev_id]); + if (bus->dev_id != -1 && bus->devices[bus->dev_id]) + { + bus->bus_out |= BUS_BSY; + bus->state = STATE_PHASESEL; +// pclog("Move to phase sel\n"); + } + break; + } + break; + case STATE_PHASESEL: + if (!(bus_assert & BUS_SEL)) + { + if (!(bus_assert & BUS_ATN)) + { +/* uint8_t sel_data = BUS_GETDATA(bus_assert); + + bus->dev_id = get_dev_id(sel_data);*/ +// pclog("STATE_PHASESEL: %i %p\n", bus->dev_id, bus->devices[bus->dev_id]); + if (bus->dev_id != -1 && bus->devices[bus->dev_id]) + { + bus->state = STATE_COMMAND; + bus->bus_out = BUS_BSY | BUS_REQ; + bus->command_pos = 0; + SET_BUS_STATE(bus, BUS_CD); + } + else + { + bus->state = STATE_IDLE; + bus->bus_out = 0; + } + } + else + fatal("dropped sel %x\n", bus_assert & BUS_ATN); + } + break; + case STATE_COMMAND: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { +// pclog(" get data %02x\n", BUS_GETDATA(bus_assert)); + bus->command[bus->command_pos++] = BUS_GETDATA(bus_assert); + bus->clear_req = 3; + bus->new_state = bus->bus_out & (BUS_IO | BUS_CD | BUS_MSG); + bus->bus_out &= ~BUS_REQ; + + if (bus->command_pos == (bus->is_atapi ? 12 : cmd_len[bus->command[0] >> 5])) + { + int new_state; + + dev->start_command(dev_data); + new_state = dev->command(bus->command, dev_data); +// pclog("COMMAND new_state = %x\n", new_state); + if ((new_state & (BUS_IO | BUS_CD | BUS_MSG)) == BUS_CD) + { + bus->state = STATE_COMMANDWAIT; + bus->clear_req = 0; + } + else + { +// pclog("Set change_state_delay COMMAND\n"); + bus->new_state = new_state; + bus->change_state_delay = 4; + } + } + } + break; + + case STATE_COMMANDWAIT: + { + int new_state; + +// pclog("COMMANDWAIT\n"); + new_state = dev->command(bus->command, dev_data); +// pclog("new_state=%x\n", new_state); + if ((new_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + { +// pclog("Set change_state_delay\n"); + bus->new_state = new_state; + bus->change_state_delay = 4; + bus->clear_req = 4; + } + } + break; + + case STATE_DATAIN: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + if (dev->read_complete(dev_data)) + { +// pclog("Read complete\n"); + bus->bus_out &= ~BUS_REQ; + //bus->clear_req = 3; + bus->new_state = BUS_CD | BUS_IO; +// pclog("change_state_delay STATE_DATAIN\n"); + bus->change_state_delay = 4; + bus->new_req_delay = 8; +// SET_BUS_STATE(data, BUS_CD | BUS_IO); + } + else + { + uint8_t val = dev->read(dev_data); + +// pclog(" Read data pos %04x %02x %x %x\n", bus->data_pos_read, bus->data_in[bus->data_pos_read], bus->data_pos_read, bus->data_pos_write); + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ; +// bus->bus_out |= BUS_REQ; + bus->clear_req = 3; + bus->bus_out &= ~BUS_REQ; + bus->new_state = BUS_IO; + } +// scsi_hd_command(bus->command, data); + } + break; + + case STATE_DATAOUT: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + dev->write(BUS_GETDATA(bus_assert), dev_data); +// pclog("Got data %02x\n", BUS_GETDATA(bus_assert)); +// pclog(" Write data pos %04x %02x %08x %08x\n", bus->data_pos_write-1, bus->data_out[bus->data_pos_write-1], cpu_getd(5), cpu_getd(6)); + + if (dev->write_complete(dev_data)) + { + int new_state; + //pclog(" Write data, command complete\n"); + bus->bus_out &= ~BUS_REQ; + new_state = dev->command(bus->command, dev_data); + + bus->new_state = new_state; +// pclog("change_state_delay STATE_DATAOUT\n"); + bus->change_state_delay = 4; + bus->new_req_delay = 8; + } + else + { + bus->bus_out |= BUS_REQ; + } + } + break; + + case STATE_STATUS: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { + bus->bus_out &= ~BUS_REQ; +/* bus->clear_req = 3;*/ + bus->new_state = BUS_CD | BUS_IO | BUS_MSG; +// pclog("change_state_delay STATE_STATUS\n"); + bus->change_state_delay = 4; + bus->new_req_delay = 8; +/* bus->state = STATE_MESSAGEIN;*/ + } + break; + + case STATE_MESSAGEIN: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) + { +// pclog("Scheduling change to idle\n"); + bus->bus_out &= ~BUS_REQ; + bus->new_state = BUS_IDLE; +// pclog("change_state_delay STATE_MESSAGEIN\n"); + bus->change_state_delay = 4; +/* bus->bus_out &= ~BUS_BSY; + SET_BUS_STATE(bus, BUS_CD | BUS_IO); + bus->state = STATE_IDLE;*/ + } + break; + } + bus->bus_in = bus_assert; + + return bus->bus_out | bus->bus_in; +} + +int scsi_bus_read(scsi_bus_t *bus) +{ + scsi_device_t *dev = NULL; + void *dev_data = NULL; + + if (bus->dev_id != -1) + { + dev = bus->devices[bus->dev_id]; + dev_data = bus->device_data[bus->dev_id]; + } + +// pclog("scsi_hd_bus_read: bus_out=%02x bus_in=%02x %i %i %i\n", bus->bus_out, bus->bus_in, bus->clear_req, bus->change_state_delay, bus->new_req_delay); + + if (bus->clear_req) + { + bus->clear_req--; + if (!bus->clear_req) + { + SET_BUS_STATE(bus, bus->new_state); +// pclog("clear_req\n"); + bus->bus_out |= BUS_REQ; + } + } + + if (bus->change_state_delay) + { + bus->change_state_delay--; + if (!bus->change_state_delay) + { + uint8_t val; + +// pclog("change_state_delay %08x\n", bus->bus_out & (BUS_IO | BUS_CD | BUS_MSG | BUS_IDLE)); + SET_BUS_STATE(bus, bus->new_state); + + switch (bus->bus_out & (BUS_IO | BUS_CD | BUS_MSG)) + { + case BUS_IO: + bus->state = STATE_DATAIN; + val = dev->read(dev_data); + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP; + break; + + case 0: + if (bus->new_state & BUS_IDLE) + { + bus->state = STATE_IDLE; + bus->bus_out &= ~BUS_BSY; + } + else + bus->state = STATE_DATAOUT; + break; + + case (BUS_IO | BUS_CD): + bus->state = STATE_STATUS; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->get_status(dev_data)) | BUS_DBP; + break; + + case (BUS_CD | BUS_IO | BUS_MSG): + bus->state = STATE_MESSAGEIN; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + break; + + default: + fatal("change_state_delay bad state %x\n", bus->bus_out); + } + + } + } + if (bus->new_req_delay) + { + bus->new_req_delay--; + if (!bus->new_req_delay) + { +// pclog("new_req_delay\n"); + bus->bus_out |= BUS_REQ; + } + } + +// pclog(" bus_out now %02x\n", bus->bus_out); + return bus->bus_out;// | bus->bus_in; +} + +int scsi_bus_match(scsi_bus_t *bus, int bus_assert) +{ +// pclog("bus_match %02x %02x\n", bus_assert & (BUS_CD | BUS_IO | BUS_MSG), bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG)); + + return (bus_assert & (BUS_CD | BUS_IO | BUS_MSG)) == (bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG)); +} + +void scsi_bus_kick(scsi_bus_t *bus) +{ +// pclog("scsi_bus_kick\n"); + scsi_bus_update(bus, 0); +} + +void scsi_bus_atapi_init(scsi_bus_t *bus, scsi_device_t *device, int id, atapi_device_t *atapi_dev) +{ + memset(bus->devices, 0, sizeof(bus->devices)); + memset(bus->device_data, 0, sizeof(bus->device_data)); + + bus->devices[0] = device; + bus->device_data[0] = bus->devices[0]->atapi_init(bus, id, atapi_dev); + if (!bus->device_data[0]) + bus->devices[0] = NULL; + + bus->is_atapi = 1; +} + +void scsi_bus_init(scsi_bus_t *bus) +{ + int c; + + memset(bus->devices, 0, sizeof(bus->devices)); + memset(bus->device_data, 0, sizeof(bus->device_data)); + + for (c = 0; c < 7; c++) + { + if (cdrom_channel == c) + bus->devices[c] = &scsi_cd; + else if (zip_channel == c) + bus->devices[c] = &scsi_zip; + else + bus->devices[c] = &scsi_hd; + + bus->device_data[c] = bus->devices[c]->init(bus, c); + if (!bus->device_data[c]) + bus->devices[c] = NULL; + } + + bus->is_atapi = 0; +} + +void scsi_bus_close(scsi_bus_t *bus) +{ + int c; + + memset(bus->devices, 0, sizeof(bus->devices)); + memset(bus->device_data, 0, sizeof(bus->device_data)); + + for (c = 0; c < 8; c++) + { + if (bus->device_data[c]) + bus->devices[c]->close(bus->device_data[c]); + } +} + +void scsi_bus_reset(scsi_bus_t *bus) +{ + int c; + + bus->state = STATE_IDLE; + bus->clear_req = 0; + bus->change_state_delay = 0; + bus->new_req_delay = 0; + bus->bus_in = bus->bus_out = 0; + bus->command_pos = 0; + + for (c = 0; c < 8; c++) + { + if (bus->device_data[c] && bus->devices[c]->reset) + bus->devices[c]->reset(bus->device_data[c]); + } +} diff --git a/src/scsi.h b/src/scsi.h new file mode 100644 index 0000000..cba4a98 --- /dev/null +++ b/src/scsi.h @@ -0,0 +1,142 @@ +#ifndef _SCSI_H_ +#define _SCSI_H_ + +struct scsi_bus_t; +struct atapi_device_t; + +typedef struct scsi_device_t +{ + void *(*init)(struct scsi_bus_t *bus, int id); + void *(*atapi_init)(struct scsi_bus_t *bus, int id, struct atapi_device_t *atapi_dev); + void (*close)(void *p); + void (*reset)(void *p); + + void (*start_command)(void *p); + int (*command)(uint8_t *cdb, void *p); + + uint8_t (*get_status)(void *p); + uint8_t (*get_sense_key)(void *p); + int (*get_bytes_required)(void *p); + + void (*atapi_identify)(uint16_t *buffer, void *p); + int (*atapi_set_feature)(uint8_t feature, uint8_t val, void *p); + + uint8_t (*read)(void *p); + void (*write)(uint8_t val, void *p); + int (*read_complete)(void *p); + int (*write_complete)(void *p); +} scsi_device_t; + +#define CDB_MAX_LEN 20 + +typedef struct scsi_bus_t +{ + int state; + int new_state; + int clear_req; + uint32_t bus_in, bus_out; + int dev_id; + + int command_pos; + uint8_t command[CDB_MAX_LEN]; + + scsi_device_t *devices[8]; + void *device_data[8]; + + int change_state_delay; + int new_req_delay; + + int is_atapi; +} scsi_bus_t; + +//int scsi_add_data(uint8_t val); +//int scsi_get_data(); +void scsi_set_phase(uint8_t phase); +void scsi_set_irq(uint8_t status); + +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_REZERO_UNIT 0x01 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_FORMAT 0x04 +#define SCSI_READ_6 0x08 +#define SCSI_WRITE_6 0x0a +#define SCSI_SEEK_6 0x0b +#define SCSI_INQUIRY 0x12 +#define SCSI_MODE_SELECT_6 0x15 +#define SCSI_MODE_SENSE_6 0x1a +#define SCSI_START_STOP_UNIT 0x1b +#define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e +#define SCSI_READ_CAPACITY_10 0x25 +#define SCSI_READ_10 0x28 +#define SCSI_WRITE_10 0x2a +#define SCSI_SEEK_10 0x2b +#define SCSI_WRITE_AND_VERIFY 0x2e +#define SCSI_VERIFY_10 0x2f +#define SCSI_READ_BUFFER 0x3c +#define SCSI_MODE_SENSE_10 0x5a + +#define SCSI_RESERVE 0x16 +#define SCSI_RELEASE 0x17 +#define SEND_DIAGNOSTIC 0x1d + +#define STATUS_GOOD 0x00 +#define STATUS_CHECK_CONDITION 0x02 + +#define MSG_COMMAND_COMPLETE 0x00 + +#define BUS_DBP 0x01 +#define BUS_SEL 0x02 +#define BUS_IO 0x04 +#define BUS_CD 0x08 +#define BUS_MSG 0x10 +#define BUS_REQ 0x20 +#define BUS_BSY 0x40 +#define BUS_RST 0x80 +#define BUS_ACK 0x200 +#define BUS_ATN 0x200 +#define BUS_ARB 0x8000 +#define BUS_SETDATA(val) ((uint32_t)val << 16) +#define BUS_GETDATA(val) ((val >> 16) & 0xff) +#define BUS_DATAMASK 0xff0000 + +#define BUS_IDLE (1 << 31) + +int scsi_bus_update(scsi_bus_t *bus, int bus_assert); +int scsi_bus_read(scsi_bus_t *bus); +int scsi_bus_match(scsi_bus_t *bus, int bus_assert); +void scsi_bus_kick(scsi_bus_t *bus); +void scsi_bus_init(scsi_bus_t *bus); +void scsi_bus_close(scsi_bus_t *bus); +void scsi_bus_reset(scsi_bus_t *bus); + +void scsi_bus_atapi_init(scsi_bus_t *bus, scsi_device_t *device, int id, struct atapi_device_t *atapi_dev); + +#define KEY_NONE 0 +#define KEY_NOT_READY 2 +#define KEY_ILLEGAL_REQ 5 +#define KEY_UNIT_ATTENTION 6 +#define KEY_DATA_PROTECT 7 + +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INVALID_LUN 0x25 +#define ASC_WRITE_PROTECT 0x27 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + + +#define SCSI_PHASE_DATA_OUT 0 +#define SCSI_PHASE_DATA_IN BUS_IO +#define SCSI_PHASE_COMMAND BUS_CD +#define SCSI_PHASE_STATUS (BUS_CD | BUS_IO) +#define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) +#define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) + +#define START_STOP_START 0x01 +#define START_STOP_LOEJ 0x02 + +#endif /*_SCSI_H_*/ diff --git a/src/scsi_53c400.c b/src/scsi_53c400.c new file mode 100644 index 0000000..03629eb --- /dev/null +++ b/src/scsi_53c400.c @@ -0,0 +1,835 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "scsi.h" +#include "scsi_53c400.h" +#include "timer.h" + +#define POLL_TIME_US 1 +#define MAX_BYTES_TRANSFERRED_PER_POLL 50 + +typedef struct ncr5380_t +{ + uint8_t output_data; + uint8_t icr; + uint8_t mode; + uint8_t tcr; + uint8_t ser; + uint8_t isr; + + int target_id; + int target_bsy; + int target_req; + + uint8_t bus_status; + + int dma_mode; + + void (*dma_changed)(struct ncr5380_t *ncr, int mode, int enable); + void *p; + + scsi_bus_t bus; +} ncr5380_t; + +typedef struct lcs6821n_t +{ + rom_t bios_rom; + + mem_mapping_t mapping; + + uint8_t block_count; + int block_count_loaded; + + uint8_t status_ctrl; + + uint8_t buffer[0x80]; + int buffer_pos; + int buffer_host_pos; + + uint8_t int_ram[0x40]; + uint8_t ext_ram[0x600]; + + ncr5380_t ncr; + + int ncr5380_dma_enabled; + + pc_timer_t dma_timer; + + int ncr_busy; +} lcs6821n_t; + +#define ICR_DBP 0x01 +#define ICR_ATN 0x02 +#define ICR_SEL 0x04 +#define ICR_BSY 0x08 +#define ICR_ACK 0x10 +#define ICR_ARB_LOST 0x20 +#define ICR_ARB_IN_PROGRESS 0x40 + +#define MODE_ARBITRATE 0x01 +#define MODE_DMA 0x02 +#define MODE_MONITOR_BUSY 0x04 +#define MODE_ENA_EOP_INT 0x08 + +#define STATUS_ACK 0x01 +#define STATUS_BUSY_ERROR 0x04 +#define STATUS_INT 0x10 +#define STATUS_DRQ 0x40 +#define STATUS_END_OF_DMA 0x80 + +#define TCR_IO 0x01 +#define TCR_CD 0x02 +#define TCR_MSG 0x04 +#define TCR_REQ 0x08 +#define TCR_LAST_BYTE_SENT 0x80 + +enum +{ + DMA_IDLE = 0, + DMA_SEND, + DMA_TARGET_RECEIVE, + DMA_INITIATOR_RECEIVE +}; + +static void set_dma_enable(lcs6821n_t *scsi, int enable) +{ + if (enable) + { + if (!timer_is_enabled(&scsi->dma_timer)) + timer_set_delay_u64(&scsi->dma_timer, TIMER_USEC * POLL_TIME_US); + } + else + timer_disable(&scsi->dma_timer); +} + +static void ncr53c400_dma_changed(ncr5380_t *ncr, int mode, int enable) +{ + lcs6821n_t *scsi = (lcs6821n_t *)ncr->p; + + scsi->ncr5380_dma_enabled = (mode && enable); + + set_dma_enable(scsi, scsi->ncr5380_dma_enabled && scsi->block_count_loaded); +} + +void ncr5380_reset(ncr5380_t *ncr) +{ + memset(ncr, 0, sizeof(ncr5380_t)); +} + +static uint32_t get_bus_host(ncr5380_t *ncr) +{ + uint32_t bus_host = 0; + + if (ncr->icr & ICR_DBP) + bus_host |= BUS_DBP; + if (ncr->icr & ICR_SEL) + bus_host |= BUS_SEL; + if (ncr->icr & ICR_ATN) + bus_host |= BUS_ATN; + if (ncr->tcr & TCR_IO) + bus_host |= BUS_IO; + if (ncr->tcr & TCR_CD) + bus_host |= BUS_CD; + if (ncr->tcr & TCR_MSG) + bus_host |= BUS_MSG; + if (ncr->tcr & TCR_REQ) + bus_host |= BUS_REQ; + if (ncr->icr & ICR_BSY) + bus_host |= BUS_BSY; + if (ncr->icr & ICR_ACK) + bus_host |= BUS_ACK; + if (ncr->mode & MODE_ARBITRATE) + bus_host |= BUS_ARB; +// pclog("get_bus_host %02x %08x\n", ncr->output_data, BUS_SETDATA(ncr->output_data)); + return bus_host | BUS_SETDATA(ncr->output_data); +} + +void ncr5380_write(uint32_t addr, uint8_t val, void *p) +{ + ncr5380_t *ncr = (ncr5380_t *)p; + int bus_host = 0; + +// pclog("ncr5380_write: addr=%06x val=%02x %04x:%04x\n", addr, val, CS,cpu_state.pc); + switch (addr & 7) + { + case 0: /*Output data register*/ + ncr->output_data = val; + break; + + case 1: /*Initiator Command Register*/ + if ((val & (ICR_BSY | ICR_SEL)) == (ICR_BSY | ICR_SEL) && + (ncr->icr & (ICR_BSY | ICR_SEL)) == ICR_SEL) + { + uint8_t temp = ncr->output_data & 0x7f; + + ncr->target_id = -1; + while (temp) + { + temp >>= 1; + ncr->target_id++; + } +// pclog("Select - target ID = %i\n", ncr->target_id); + + if (!ncr->target_id) + ncr->target_bsy = 1; + } + + ncr->icr = val; + break; + + case 2: /*Mode register*/ + if ((val & MODE_ARBITRATE) && !(ncr->mode & MODE_ARBITRATE)) + { + ncr->icr &= ~ICR_ARB_LOST; + ncr->icr |= ICR_ARB_IN_PROGRESS; + } + +// output = 1; + ncr->mode = val; + ncr->dma_changed(ncr, ncr->dma_mode, ncr->mode & MODE_DMA); + if (!(ncr->mode & MODE_DMA)) + { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } + break; + + case 3: /*Target Command Register*/ + ncr->tcr = val; +/* switch (val & (TCR_MSG | TCR_CD | TCR_IO)) + { + case TCR_CD: + ncr->target_req = 1; + break; + }*/ + break; + case 4: /*Select Enable Register*/ + ncr->ser = val; + break; + + case 5: /*Start DMA Send*/ + ncr->dma_mode = DMA_SEND; + ncr->dma_changed(ncr, ncr->dma_mode, ncr->mode & MODE_DMA); + break; + + case 7: /*Start DMA Initiator Receive*/ + ncr->dma_mode = DMA_INITIATOR_RECEIVE; + ncr->dma_changed(ncr, ncr->dma_mode, ncr->mode & MODE_DMA); + break; + + default: + pclog("Bad NCR5380 write %06x %02x\n", addr, val); + } + + bus_host = get_bus_host(ncr); + + scsi_bus_update(&ncr->bus, bus_host); +} + +uint8_t ncr5380_read(uint32_t addr, void *p) +{ + ncr5380_t *ncr = (ncr5380_t *)p; + uint32_t bus = 0; + uint8_t temp = 0xff; + + switch (addr & 7) + { + case 0: /*Current SCSI Data*/ + //output = 3; + //fatal("Here\n"); + if (ncr->icr & ICR_DBP) + temp = ncr->output_data; + else + { + bus = scsi_bus_read(&ncr->bus); + temp = BUS_GETDATA(bus); + } + break; + case 1: /*Initiator Command Register*/ + temp = ncr->icr; + break; + case 2: /*Mode Register*/ + temp = ncr->mode; + break; + case 3: /*Target Command Register*/ + temp = ncr->tcr; + break; + + case 4: /*Current SCSI Bus Status*/ + temp = 0;//get_bus_host(ncr); + bus = scsi_bus_read(&ncr->bus); +// pclog(" SCSI bus status = %02x %02x\n", temp, bus); + temp |= (bus & 0xff); +// pclog(" SCSI bus status = %02x\n", temp); + break; + + case 5: /*Bus and Status Register*/ + temp = 0; + + bus = get_bus_host(ncr); + if (scsi_bus_match(&ncr->bus, bus)) + temp |= 8; + bus = scsi_bus_read(&ncr->bus); + + if (bus & BUS_ACK) + temp |= STATUS_ACK; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) + temp |= STATUS_DRQ; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) + { + int bus_state = 0; + if (bus & BUS_IO) + bus_state |= TCR_IO; + if (bus & BUS_CD) + bus_state |= TCR_CD; + if (bus & BUS_MSG) + bus_state |= TCR_MSG; + if ((ncr->tcr & 7) != bus_state) + ncr->isr |= STATUS_INT; + } + if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + temp |= STATUS_BUSY_ERROR; + temp |= (ncr->isr & (STATUS_INT | STATUS_END_OF_DMA)); + +// pclog(" bus and status register = %02x\n", temp); + break; + + case 7: /*Reset Parity/Interrupt*/ + ncr->isr &= ~STATUS_INT; + break; + + default: + pclog("Bad NCR5380 read %06x\n", addr); + } +// pclog("ncr5380_read: addr=%06x temp=%02x pc=%04x:%04x\n", addr, temp, CS,cpu_state.pc); + return temp; +} + +#define CTRL_DATA_DIR (1 << 6) + +#define STATUS_BUFFER_NOT_READY (1 << 2) +#define STATUS_53C80_ACCESSIBLE (1 << 7) + +static uint8_t lcs6821n_read(uint32_t addr, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; +//if (addr >= 0xca000) + addr &= 0x3fff; +// pclog("lcs6821n_read %08x\n", addr); + if (addr < 0x2000) + temp = scsi->bios_rom.rom[addr & 0x1fff]; + else if (addr < 0x3800) + temp = 0xff; + else if (addr >= 0x3a00) + temp = scsi->ext_ram[addr - 0x3a00]; + else switch (addr & 0x3f80) + { + case 0x3800: +// pclog("Read intRAM %02x %02x\n", addr & 0x3f, scsi->int_ram[addr & 0x3f]); + temp = scsi->int_ram[addr & 0x3f]; + break; + + case 0x3880: +// pclog("Read 53c80 %04x\n", addr); + temp = ncr5380_read(addr, &scsi->ncr); + break; + + case 0x3900: +//pclog(" Read 3900 %i %02x\n", scsi->buffer_host_pos, scsi->status_ctrl); + if (scsi->buffer_host_pos >= 128 || !(scsi->status_ctrl & CTRL_DATA_DIR)) + temp = 0xff; + else + { + temp = scsi->buffer[scsi->buffer_host_pos++]; + + if (scsi->buffer_host_pos == 128) + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + break; + + case 0x3980: + switch (addr) + { + case 0x3980: /*Status*/ + temp = scsi->status_ctrl;// | 0x80; + if (!scsi->ncr_busy) + temp |= STATUS_53C80_ACCESSIBLE; + break; + case 0x3981: /*Block counter register*/ + temp = scsi->block_count; + break; + case 0x3982: /*Switch register read*/ +// temp = 7 | (7 << 3); + temp = 0xff; + break; + case 0x3983: + temp = 0xff; + break; + } + break; + } + +// if (addr >= 0x3880) pclog("lcs6821n_read: addr=%05x val=%02x %04x:%04x\n", addr, temp, CS,cpu_state.pc); + + return temp; +} + +static void lcs6821n_write(uint32_t addr, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + addr &= 0x3fff; + +// /*if (addr >= 0x3880) */pclog("lcs6821n_write: addr=%05x val=%02x %04x:%04x %i %02x\n", addr, val, CS,cpu_state.pc, scsi->buffer_host_pos, scsi->status_ctrl); + + if (addr >= 0x3a00) + scsi->ext_ram[addr - 0x3a00] = val; + else switch (addr & 0x3f80) + { + case 0x3800: +// pclog("Write intram %02x %02x\n", addr & 0x3f, val); + scsi->int_ram[addr & 0x3f] = val; + break; + + case 0x3880: +// pclog("Write 53c80 %04x %02x\n", addr, val); + ncr5380_write(addr, val, &scsi->ncr); + break; + + case 0x3900: + if (!(scsi->status_ctrl & CTRL_DATA_DIR) && scsi->buffer_host_pos < 128) + { +// pclog(" Write %i %02x\n", scsi->buffer_host_pos, val); + scsi->buffer[scsi->buffer_host_pos++] = val; + if (scsi->buffer_host_pos == 128) + { + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + scsi->ncr_busy = 1; + } + } + break; + + case 0x3980: + switch (addr) + { + case 0x3980: /*Control*/ + if ((val & CTRL_DATA_DIR) && !(scsi->status_ctrl & CTRL_DATA_DIR)) + { + scsi->buffer_host_pos = 128; + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + else if (!(val & CTRL_DATA_DIR) && (scsi->status_ctrl & CTRL_DATA_DIR)) + { + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + scsi->status_ctrl = (scsi->status_ctrl & 0x87) | (val & 0x78); + break; + case 0x3981: /*Block counter register*/ + scsi->block_count = val; + scsi->block_count_loaded = 1; + set_dma_enable(scsi, scsi->ncr5380_dma_enabled && scsi->block_count_loaded); + if (scsi->status_ctrl & CTRL_DATA_DIR) + { + scsi->buffer_host_pos = 128; + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + else + { + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + break; + } + break; + } +} + +static uint8_t t130b_read(uint32_t addr, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; +//if (addr >= 0xca000) + addr &= 0x3fff; + + if (addr < 0x1800) + temp = scsi->bios_rom.rom[addr & 0x1fff]; + else if (addr < 0x1880) + temp = scsi->ext_ram[addr & 0x7f]; +// else +// pclog("Bad T130B read %04x\n", addr); + +// if (addr >= 0x3880) pclog("lcs6821n_read: addr=%05x val=%02x %04x:%04x\n", addr, temp, CS,cpu_state.pc); + + return temp; +} +static void t130b_write(uint32_t addr, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + addr &= 0x3fff; + +// if (addr >= 0x3880) pclog("lcs6821n_write: addr=%05x val=%02x %04x:%04x %i %02x\n", addr, val, CS,cpu_state.pc, scsi->buffer_host_pos, scsi->status_ctrl); + + if (addr >= 0x1800 && addr < 0x1880) + scsi->ext_ram[addr & 0x7f] = val; +// else +// pclog("Bad T130B write %04x %02x\n", addr, val); +} + +static uint8_t t130b_in(uint16_t port, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + uint8_t temp = 0xff; + + switch (port & 0xf) + { + case 0x0: case 0x1: case 0x2: case 0x3: + temp = lcs6821n_read((port & 7) | 0x3980, scsi); + break; + + case 0x4: case 0x5: + temp = lcs6821n_read(0x3900, scsi); + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + temp = ncr5380_read(port, &scsi->ncr); + break; + } + + if (CS != 0xdc00) + { + //pclog("t130b_in: port=%04x val=%02x %04x:%04x\n", port, temp, CS,cpu_state.pc); + //output = 3; + //fatal("Here\n"); + } + return temp; +} +static void t130b_out(uint16_t port, uint8_t val, void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + //if (CS != 0xdc00) pclog("t130b_out: port=%04x val=%02x %04x:%04x\n", port, val, CS,cpu_state.pc); + + switch (port & 0xf) + { + case 0x0: case 0x1: case 0x2: case 0x3: + lcs6821n_write((port & 7) | 0x3980, val, scsi); + break; + + case 0x4: case 0x5: + lcs6821n_write(0x3900, val, scsi); + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + ncr5380_write(port, val, &scsi->ncr); + break; + } +} + +static void ncr53c400_dma_callback(void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + ncr5380_t *ncr = &scsi->ncr; + int c; + int bytes_transferred = 0; + +//pclog("dma_Callback poll\n"); + timer_advance_u64(&scsi->dma_timer, TIMER_USEC * POLL_TIME_US); + + switch (scsi->ncr.dma_mode) + { + case DMA_SEND: + if (scsi->status_ctrl & CTRL_DATA_DIR) + { + pclog("DMA_SEND with DMA direction set wrong\n"); + break; + } + +// if (!device_data[ncr->target_id]) +// fatal("DMA with no device\n"); + + if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) + { +// pclog(" !(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)\n"); + break; + } + + if (!scsi->block_count_loaded) + { +// pclog("!scsi->block_count_loaded\n"); + break; + } + + while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus; + uint8_t data; + + for (c = 0; c < 10; c++) + { + uint8_t status = scsi_bus_read(&ncr->bus); + + if (status & BUS_REQ) + break; + } + if (c == 10) + { +// pclog(" No req\n"); + break; + } + + /*Data ready*/ + data = scsi->buffer[scsi->buffer_pos]; + bus = get_bus_host(ncr) & ~BUS_DATAMASK; + bus |= BUS_SETDATA(data); + + scsi_bus_update(&ncr->bus, bus | BUS_ACK); + scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); +// pclog(" Sent data %02x %i\n", data, scsi->buffer_pos); + + scsi->buffer_pos++; + bytes_transferred++; + + if (scsi->buffer_pos == 128) + { + scsi->buffer_pos = 0; + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + scsi->block_count = (scsi->block_count - 1) & 255; + scsi->ncr_busy = 0; +// pclog("Sent buffer %i\n", scsi->block_count); + if (!scsi->block_count) + { + scsi->block_count_loaded = 0; + set_dma_enable(scsi, 0); +// scsi->buffer_host_pos = 128; +// scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + ncr->isr |= STATUS_INT; + } + break; + } + } + break; + + case DMA_INITIATOR_RECEIVE: + if (!(scsi->status_ctrl & CTRL_DATA_DIR)) + { + pclog("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); + break; + } + + if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) + break; + + if (!scsi->block_count_loaded) + break; + + while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus; + uint8_t temp; + + for (c = 0; c < 10; c++) + { + uint8_t status = scsi_bus_read(&ncr->bus); + + if (status & BUS_REQ) + break; + } + if (c == 10) + break; + + /*Data ready*/ + bus = scsi_bus_read(&ncr->bus); + temp = BUS_GETDATA(bus); +// pclog(" Got data %02x %i\n", temp, scsi->buffer_pos); + + bus = get_bus_host(ncr); + + scsi_bus_update(&ncr->bus, bus | BUS_ACK); + scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); + + scsi->buffer[scsi->buffer_pos++] = temp; + bytes_transferred++; + + if (scsi->buffer_pos == 128) + { + scsi->buffer_pos = 0; + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + scsi->block_count = (scsi->block_count - 1) & 255; +// pclog("Got buffer %i\n", scsi->block_count); + if (!scsi->block_count) + { + scsi->block_count_loaded = 0; + set_dma_enable(scsi, 0); + +// output=3; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + ncr->isr |= STATUS_INT; + } + break; + } + } + break; + + default: + pclog("DMA callback bad mode %i\n", scsi->ncr.dma_mode); + break; + } + + { + int bus = scsi_bus_read(&ncr->bus); + + if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + { + ncr->mode &= ~MODE_DMA; + ncr->dma_mode = DMA_IDLE; + ncr->dma_changed(ncr, ncr->dma_mode, ncr->mode & MODE_DMA); + } + } +} + +static void *scsi_53c400_init(char *bios_fn) +{ + lcs6821n_t *scsi = malloc(sizeof(lcs6821n_t)); + memset(scsi, 0, sizeof(lcs6821n_t)); + + rom_init(&scsi->bios_rom, bios_fn, 0xdc000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&scsi->bios_rom.mapping); + + mem_mapping_add(&scsi->mapping, 0xdc000, 0x4000, + lcs6821n_read, NULL, NULL, + lcs6821n_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + + ncr5380_reset(&scsi->ncr); + + scsi->ncr.dma_changed = ncr53c400_dma_changed; + scsi->ncr.p = scsi; + + scsi->status_ctrl = STATUS_BUFFER_NOT_READY; + scsi->buffer_host_pos = 128; + + scsi_bus_init(&scsi->ncr.bus); + + timer_add(&scsi->dma_timer, ncr53c400_dma_callback, scsi, 0); + + return scsi; +} + +static void *scsi_lcs6821n_init() +{ + return scsi_53c400_init("Longshine LCS-6821N - BIOS version 1.04.bin"); +} +static void *scsi_rt1000b_init() +{ + return scsi_53c400_init("Rancho_RT1000_RTBios_version_8.10R.bin"); +} + +static void *scsi_t130b_init(char *bios_fn) +{ + lcs6821n_t *scsi = malloc(sizeof(lcs6821n_t)); + memset(scsi, 0, sizeof(lcs6821n_t)); + + rom_init(&scsi->bios_rom, "trantor_t130b_bios_v2.14.bin", 0xdc000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&scsi->mapping, 0xdc000, 0x4000, + t130b_read, NULL, NULL, + t130b_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + io_sethandler(0x0350, 0x0010, + t130b_in, NULL, NULL, + t130b_out, NULL, NULL, + scsi); + + ncr5380_reset(&scsi->ncr); + + scsi->ncr.dma_changed = ncr53c400_dma_changed; + scsi->ncr.p = scsi; + + scsi->status_ctrl = STATUS_BUFFER_NOT_READY; + scsi->buffer_host_pos = 128; + + scsi_bus_init(&scsi->ncr.bus); + + timer_add(&scsi->dma_timer, ncr53c400_dma_callback, scsi, 0); + + return scsi; +} + +static void scsi_53c400_close(void *p) +{ + lcs6821n_t *scsi = (lcs6821n_t *)p; + + scsi_bus_close(&scsi->ncr.bus); + + free(scsi); +} + +static int scsi_lcs6821n_available() +{ + return rom_present("Longshine LCS-6821N - BIOS version 1.04.bin"); +} + +static int scsi_rt1000b_available() +{ + return rom_present("Rancho_RT1000_RTBios_version_8.10R.bin"); +} + +static int scsi_t130b_available() +{ + return rom_present("trantor_t130b_bios_v2.14.bin"); +} + +device_t scsi_lcs6821n_device = +{ + "Longshine LCS-6821N (SCSI)", + 0, + scsi_lcs6821n_init, + scsi_53c400_close, + scsi_lcs6821n_available, + NULL, + NULL, + NULL, + NULL +}; + +device_t scsi_rt1000b_device = +{ + "Ranco RT1000B (SCSI)", + 0, + scsi_rt1000b_init, + scsi_53c400_close, + scsi_rt1000b_available, + NULL, + NULL, + NULL, + NULL +}; + +device_t scsi_t130b_device = +{ + "Trantor T130B (SCSI)", + 0, + scsi_t130b_init, + scsi_53c400_close, + scsi_t130b_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/scsi_53c400.h b/src/scsi_53c400.h new file mode 100644 index 0000000..d1dc52d --- /dev/null +++ b/src/scsi_53c400.h @@ -0,0 +1,3 @@ +extern device_t scsi_lcs6821n_device; +extern device_t scsi_rt1000b_device; +extern device_t scsi_t130b_device; diff --git a/src/scsi_aha1540.c b/src/scsi_aha1540.c new file mode 100644 index 0000000..f3bb9b6 --- /dev/null +++ b/src/scsi_aha1540.c @@ -0,0 +1,2612 @@ +/*AH1542C firmware notes : + + d1a - command dispatch + 193c - send data + 1954 - get data + + FW data - 164e + + BIOS command table - f4b*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "nvr.h" +#include "pic.h" +#include "rom.h" +#include "scsi.h" +#include "scsi_aha1540.h" +#include "timer.h" + +int primed = 0; +typedef enum +{ + SCSI_AHA1542C, + SCSI_BT545S +} scsi_type_t; + +/*Firmware emulation is implemented via three state machines : + + - Command state - foreground command processing + - CCB state - CCB/mailbox processing - triggered by commands 0x02/0x82 + - SCSI state - SCSI bus handling / data transfer*/ +typedef enum +{ + CMD_STATE_RESET, + CMD_STATE_IDLE, + CMD_STATE_GET_PARAMS, + CMD_STATE_CMD_IN_PROGRESS, + CMD_STATE_SEND_RESULT +} cmd_state_t; + +typedef enum +{ + CCB_STATE_IDLE, + CCB_STATE_SEND_COMMAND, + CCB_STATE_WAIT_COMMAND, + CCB_STATE_SEND_REQUEST_SENSE, + CCB_STATE_WAIT_REQUEST_SENSE +} ccb_state_t; + +typedef enum +{ + SCSI_STATE_IDLE, + SCSI_STATE_SELECT, + SCSI_STATE_SELECT_FAILED, + SCSI_STATE_SEND_COMMAND, + SCSI_STATE_NEXT_PHASE, + SCSI_STATE_END_PHASE, + SCSI_STATE_READ_DATA, + SCSI_STATE_WRITE_DATA, + SCSI_STATE_READ_STATUS, + SCSI_STATE_READ_MESSAGE +} scsi_state_t; + +typedef enum +{ + MB_FORMAT_4, + MB_FORMAT_8 +} mb_format_t; + +typedef struct aha154x_t +{ + rom_t bios_rom; + mem_mapping_t mapping; + uint32_t bios_addr; + + uint8_t shadow_ram[0x4000]; + uint8_t shadow; + + uint32_t bios_bank; + + uint8_t eeprom[256]; + char fn[256]; + + scsi_type_t type; + + scsi_bus_t bus; + + uint8_t isr; + uint8_t isr_pending; + uint8_t status; + + int mbo_irq_enable; + + uint8_t cmd_data; + uint8_t data_in; + + uint8_t command; + int command_len; + int cur_param; + uint8_t params[64]; + + int result_pos, result_len; + uint8_t result[256]; + + uint8_t dma_buffer[64]; + + uint8_t bon, boff; + uint8_t atbs; + + int mbc; + uint32_t mba; + uint32_t mba_i; + int mbo_req; + mb_format_t mb_format; + + int bios_mbc; + uint32_t bios_mba; + int bios_mbo_req; + int bios_mbo_inited; + + cmd_state_t cmd_state; + ccb_state_t ccb_state; + scsi_state_t scsi_state; + + int bios_cmd_state; + + pc_timer_t timer; + + int current_mbo; + int current_mbo_is_bios; + int current_mbi; + + uint8_t mblt, mbu; + + uint8_t int_buffer[512]; + + uint8_t e_d; + uint16_t to; + + uint8_t dipsw; + int irq, dma, host_id; + + struct + { + uint32_t addr; + + uint8_t opcode; + int target_id, transfer_dir, lun; + int scsi_cmd_len; + int req_sense_len; + uint32_t data_len; + uint32_t data_pointer; + uint32_t link_pointer; + uint8_t link_id; + + uint8_t cdb[256]; + + uint8_t status; + + int from_mailbox; + + uint32_t data_seg_list_pointer; + uint32_t data_seg_list_len; + uint32_t data_seg_list_idx; + + int residual; + + int bytes_transferred; + uint32_t total_data_len; + } ccb; + + struct + { + int idx, len; + uint8_t data[256]; + + int data_idx, data_len; + uint32_t data_pointer; + + uint8_t last_status; + + uint32_t data_seg_list_pointer; + uint32_t data_seg_list_len; + uint32_t data_seg_list_idx; + + int scatter_gather; + int bytes_transferred; + } cdb; + + int reg3_idx; +} aha154x_t; + +#define STATUS_INVDCMD 0x01 +#define STATUS_DF 0x04 +#define STATUS_CDF 0x08 +#define STATUS_IDLE 0x10 +#define STATUS_INIT 0x20 +#define STATUS_STST 0x80 + +#define CTRL_BRST 0x10 +#define CTRL_IRST 0x20 +#define CTRL_SRST 0x40 +#define CTRL_RESET 0x80 + +#define ISR_MBIF 0x01 +#define ISR_MBOA 0x02 +#define ISR_HACC 0x04 +#define ISR_ANYINTR 0x80 + +#define COMMAND_NOP 0x00 +#define COMMAND_MAILBOX_INITIALIZATION 0x01 +#define COMMAND_START_SCSI_COMMAND 0x02 +#define COMMAND_START_BIOS_COMMAND 0x03 +#define COMMAND_ADAPTER_INQUIRY 0x04 +#define COMMAND_MAILBOX_OUT_IRQ_ENA 0x05 +#define COMMAND_SET_SELECTION_TIMEOUT 0x06 +#define COMMAND_SET_BUS_ON_TIME 0x07 +#define COMMAND_SET_BUS_OFF_TIME 0x08 +#define COMMAND_SET_AT_BUS_SPEED 0x09 +#define COMMAND_INQUIRE_INSTALLED_DEVICES 0x0a +#define COMMAND_RETURN_CONFIG_DATA 0x0b +#define COMMAND_RETURN_SETUP_DATA 0x0d +#define COMMAND_WRITE_CHANNEL_2_BUF 0x1a +#define COMMAND_READ_CHANNEL_2_BUF 0x1b +#define COMMAND_ECHO 0x1f + +#define COMMAND_ADAPTEC_PROGRAM_EEPROM 0x22 +#define COMMAND_ADAPTEC_RETURN_EEPROM_DATA 0x23 +#define COMMAND_ADAPTEC_SET_SHADOW_PARAMS 0x24 +#define COMMAND_ADAPTEC_BIOS_MAILBOX_INIT 0x25 +#define COMMAND_ADAPTEC_SET_BIOS_BANK_1 0x26 +#define COMMAND_ADAPTEC_SET_BIOS_BANK_2 0x27 +#define COMMAND_ADAPTEC_GET_EXT_BIOS_INFO 0x28 +#define COMMAND_ENABLE_MAILBOX_INTERFACE 0x29 +#define COMMAND_ADAPTEC_START_BIOS_SCSI_CMD 0x82 + +#define COMMAND_BUSLOGIC_22 0x22 +#define COMMAND_BUSLOGIC_81 0x81 +#define COMMAND_BUSLOGIC_84 0x84 +#define COMMAND_BUSLOGIC_85 0x85 +#define COMMAND_BUSLOGIC_ADAPTER_MODEL_NR 0x8b +#define COMMAND_BUSLOGIC_INQUIRY_SYNC_PERIOD 0x8c +#define COMMAND_BUSLOGIC_EXTENDED_SETUP_INFO 0x8d +#define COMMAND_BUSLOGIC_STRICT_RR 0x8f +#define COMMAND_BUSLOGIC_SET_CCB_FORMAT 0x96 + +#define COMMAND_FREE_CCB 0 +#define COMMAND_START_CCB 1 +#define COMMAND_ABORT_CCB 2 + +#define CCB_INITIATOR 0 +#define CCB_INITIATOR_SCATTER_GATHER 2 +#define CCB_INITIATOR_RESIDUAL 3 +#define CCB_INITIATOR_SCATTER_GATHER_RESIDUAL 4 + +#define CCB_SENSE_14 0x00 +#define CCB_SENSE_NONE 0x01 + +#define MBI_CCB_COMPLETE 0x01 +#define MBI_CCB_ABORTED 0x02 +#define MBI_CCB_COMPLETE_WITH_ERROR 0x04 + +#define HOST_STATUS_COMMAND_COMPLETE 0x00 +#define HOST_STATUS_SELECTION_TIME_OUT 0x11 + +#define POLL_TIME_US 10 +#define MAX_BYTES_TRANSFERRED_PER_POLL 50 +/*10us poll period with 50 bytes transferred per poll = 5MB/sec*/ + +static void aha1542c_eeprom_save(aha154x_t *scsi); +static void process_cmd(aha154x_t *scsi); + +static void set_irq(aha154x_t *scsi, uint8_t val) +{ + picint(1 << scsi->irq); + scsi->isr |= val | ISR_ANYINTR; +} + +static void clear_irq(aha154x_t *scsi) +{ + picintc(1 << scsi->irq); +} + +static void aha154x_out(uint16_t port, uint8_t val, void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + + if (CS != 0xc800) + { +// pclog("aha154x_out: port=%04x val=%02x %04x:%04x %i\n", port, val, CS, cpu_state.pc, scsi->cmd_state); + } + + switch (port & 3) + { + case 0: /*Control register*/ + if (val & CTRL_RESET) + { + scsi->isr = 0; + clear_irq(scsi); + scsi->status = STATUS_STST; + pclog("hardware reset\n"); + scsi->cmd_state = CMD_STATE_RESET; + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + scsi->mb_format = MB_FORMAT_4; + scsi->current_mbi = 0; + scsi->mbo_irq_enable = 0; + } + if (val & CTRL_SRST) + { + scsi->isr = 0; + clear_irq(scsi); + scsi->status = STATUS_INIT; +// pclog("software reset\n"); + scsi->cmd_state = CMD_STATE_IDLE; + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + scsi->mb_format = MB_FORMAT_4; + scsi->current_mbi = 0; + scsi->mbo_irq_enable = 0; + } + if (val & CTRL_IRST) + { + scsi->isr = 0; + clear_irq(scsi); +// update_irq(scsi); + if (scsi->type == SCSI_AHA1542C) + scsi->status &= ~STATUS_INVDCMD; + } + if (val & CTRL_BRST) + { + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; +// output = 3; + } + break; + + case 1: /*Command/data register*/ + if (scsi->status & STATUS_CDF) + break; + if (scsi->type == SCSI_BT545S) + scsi->status &= ~STATUS_INVDCMD; +// fatal("Write command reg while full\n"); + scsi->status |= STATUS_CDF; + scsi->cmd_data = val; +// pclog("Write command %02x %04x(%08x):%08x\n", val, CS,cs,cpu_state.pc); + process_cmd(scsi); + break; + + case 2: + if (scsi->type == SCSI_BT545S) + scsi->isr = val; + break; + } +} + +static uint8_t aha154x_in(uint16_t port, void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + uint8_t temp = 0xff; + +// if (primed) +// output = 3; + switch (port & 3) + { + case 0: /*Status register*/ + temp = scsi->status; + if (scsi->cmd_state == CMD_STATE_IDLE && scsi->ccb_state == CCB_STATE_IDLE && scsi->scsi_state == SCSI_STATE_IDLE) + temp |= STATUS_IDLE; + break; + + case 1: /*Data in register*/ +/* if (!(scsi->status & STATUS_DF)) + fatal("Read data in while empty\n");*/ + scsi->status &= ~STATUS_DF; + temp = scsi->data_in; + break; + + case 2: /*Interrupt status register*/ + if (scsi->type == SCSI_BT545S) + temp = scsi->isr; + else + temp = scsi->isr & ~0x70; + break; + + case 3: /*???*/ + if (scsi->type == SCSI_BT545S) + temp = 0x29; /*BT-545S BIOS expects this to return not zero or 0xff for six consecutive reads*/ + else + { + scsi->reg3_idx++; + switch (scsi->reg3_idx & 3) + { + case 0: temp = 'A'; break; + case 1: temp = 'D'; break; + case 2: temp = 'A'; break; + case 3: temp = 'P'; break; + } + } + break; + } + if (CS != 0xc800) + { +// pclog("aha154x_in: port=%04x val=%02x %04x(%08x):%04x %i %i\n", port, temp, CS, cs, cpu_state.pc, ins, scsi->cmd_state); + } + + return temp; +} + +static int wait_for_bus(scsi_bus_t *bus, int state, int req_needed) +{ + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(bus); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) == state && (bus_state & BUS_BSY)) + { + if (!req_needed || (bus_state & BUS_REQ)) + return 1; + } + } + + return 0; +} + +static void process_cdb(aha154x_t *scsi) +{ + int c; + uint8_t temp; + + scsi->ccb.opcode = mem_readb_phys(scsi->ccb.addr); + switch (scsi->ccb.opcode) + { + case CCB_INITIATOR: + case CCB_INITIATOR_RESIDUAL: + temp = mem_readb_phys(scsi->ccb.addr + 0x01); +// pclog("Read addr+ctrl %02x %06x\n", temp, scsi->ccb.addr+0x01); + scsi->ccb.transfer_dir = (temp >> 3) & 3; + scsi->ccb.scsi_cmd_len = mem_readb_phys(scsi->ccb.addr + 0x02); + scsi->ccb.req_sense_len = mem_readb_phys(scsi->ccb.addr + 0x03); + + if (scsi->mb_format == MB_FORMAT_4) + { + scsi->ccb.lun = temp & 7; + scsi->ccb.target_id = (temp >> 5) & 7; + + scsi->ccb.data_len = mem_readb_phys(scsi->ccb.addr + 0x06) | (mem_readb_phys(scsi->ccb.addr + 0x05) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x04) << 16); + scsi->ccb.data_pointer = mem_readb_phys(scsi->ccb.addr + 0x09) | (mem_readb_phys(scsi->ccb.addr + 0x08) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x07) << 16); + scsi->ccb.link_pointer = mem_readb_phys(scsi->ccb.addr + 0x0c) | (mem_readb_phys(scsi->ccb.addr + 0x0b) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x0a) << 16); + scsi->ccb.link_id = mem_readb_phys(scsi->ccb.addr + 0x0d); + } + else + { + scsi->ccb.data_len = mem_readl_phys(scsi->ccb.addr + 0x04); + scsi->ccb.data_pointer = mem_readl_phys(scsi->ccb.addr + 0x08); + + scsi->ccb.target_id = mem_readb_phys(scsi->ccb.addr + 0x10); + scsi->ccb.lun = mem_readb_phys(scsi->ccb.addr + 0x11) & 0x1f; +// pclog("Target ID = %02x addr=%08x len=%08x\n", scsi->ccb.target_id, scsi->ccb.data_pointer, scsi->ccb.data_len); + } + for (c = 0; c < scsi->ccb.scsi_cmd_len; c++) + scsi->ccb.cdb[c] = mem_readb_phys(scsi->ccb.addr+0x12+c); +// pclog("CCB_INITIATOR: target=%i lun=%i\n", scsi->ccb.target_id, scsi->ccb.lun); +// pclog(" scsi_len=%i data_len=%06x data_pointer=%06x\n", scsi->ccb.scsi_cmd_len, scsi->ccb.data_len, scsi->ccb.data_pointer); + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->ccb.status = 0; + scsi->ccb.from_mailbox = 1; + scsi->ccb.residual = (scsi->ccb.opcode == CCB_INITIATOR_RESIDUAL); + scsi->ccb.total_data_len = scsi->ccb.data_len; + break; + + case CCB_INITIATOR_SCATTER_GATHER: + case CCB_INITIATOR_SCATTER_GATHER_RESIDUAL: +// pclog("Scatter-gather : %08x %08x %08x %08x %08x %i %02x\n", mem_readl_phys(scsi->ccb.addr),mem_readl_phys(scsi->ccb.addr+4),mem_readl_phys(scsi->ccb.addr+8),mem_readl_phys(scsi->ccb.addr+12),mem_readl_phys(scsi->ccb.addr+16), scsi->mb_format == MB_FORMAT_4, scsi->ccb.opcode); + temp = mem_readb_phys(scsi->ccb.addr + 0x01); +// pclog("Read addr+ctrl %02x %06x\n", temp, scsi->ccb.addr+0x01); + scsi->ccb.transfer_dir = (temp >> 3) & 3; + scsi->ccb.scsi_cmd_len = mem_readb_phys(scsi->ccb.addr + 0x02); + scsi->ccb.req_sense_len = mem_readb_phys(scsi->ccb.addr + 0x03); + + if (scsi->mb_format == MB_FORMAT_4) + { + scsi->ccb.lun = temp & 7; + scsi->ccb.target_id = (temp >> 5) & 7; + + scsi->ccb.data_seg_list_len = mem_readb_phys(scsi->ccb.addr + 0x06) | (mem_readb_phys(scsi->ccb.addr + 0x05) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x04) << 16); + scsi->ccb.data_seg_list_pointer = mem_readb_phys(scsi->ccb.addr + 0x09) | (mem_readb_phys(scsi->ccb.addr + 0x08) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x07) << 16); + scsi->ccb.data_seg_list_idx = 0; + if (scsi->ccb.data_seg_list_len < 6) + pclog("Scatter gather table < 6 bytes\n"); + + scsi->ccb.link_pointer = mem_readb_phys(scsi->ccb.addr + 0x0c) | (mem_readb_phys(scsi->ccb.addr + 0x0b) << 8) | (mem_readb_phys(scsi->ccb.addr + 0x0a) << 16); + scsi->ccb.link_id = mem_readb_phys(scsi->ccb.addr + 0x0d); + } + else + { + scsi->ccb.data_seg_list_len = mem_readl_phys(scsi->ccb.addr + 0x04); + scsi->ccb.data_seg_list_pointer = mem_readl_phys(scsi->ccb.addr + 0x08); + scsi->ccb.data_seg_list_idx = 0; + if (scsi->ccb.data_seg_list_len < 8) + pclog("Scatter gather table < 8 bytes\n"); + + scsi->ccb.target_id = mem_readb_phys(scsi->ccb.addr + 0x10); + scsi->ccb.lun = mem_readb_phys(scsi->ccb.addr + 0x11) & 0x1f; +// pclog("Target ID = %02x\n", scsi->ccb.target_id); + } + for (c = 0; c < scsi->ccb.scsi_cmd_len; c++) + scsi->ccb.cdb[c] = mem_readb_phys(scsi->ccb.addr+0x12+c); +// pclog("CCB_INITIATOR_SCATTER_GATHER: target=%i lun=%i\n", scsi->ccb.target_id, scsi->ccb.lun); +// pclog(" scsi_len=%i data_len=%06x data_pointer=%06x\n", scsi->ccb.scsi_cmd_len, scsi->ccb.data_len, scsi->ccb.data_pointer); + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->ccb.status = 0; + scsi->ccb.from_mailbox = 1; + scsi->ccb.residual = (scsi->ccb.opcode == CCB_INITIATOR_SCATTER_GATHER_RESIDUAL); + + if (scsi->ccb.residual) + { + /*Read total data length from scatter list, to use when calculating residual*/ + uint32_t addr = scsi->ccb.data_seg_list_pointer; + + scsi->ccb.total_data_len = 0; + + if (scsi->mb_format == MB_FORMAT_4) + { + for (c = 0; c < scsi->ccb.data_seg_list_len; c += 6) + { + uint32_t len = mem_readb_phys(addr + c + 2) | + (mem_readb_phys(addr + c + 1) << 8) | + (mem_readb_phys(addr + c) << 16); + + scsi->ccb.total_data_len += len; + } + } + else + { + for (c = 0; c < scsi->ccb.data_seg_list_len; c += 6) + { + uint32_t len = mem_readl_phys(addr + c); + + scsi->ccb.total_data_len += len; + } + } + } + break; + + default: + fatal("Unknown CCD opcode %02x\n", scsi->ccb.opcode); + } + pclog("Start CCB at %06x\n", scsi->ccb.addr); +} + +static void process_cmd(aha154x_t *scsi) +{ + uint32_t addr; + int c; + + switch (scsi->cmd_state) + { + case CMD_STATE_RESET: + scsi->status = STATUS_INIT; + scsi->cmd_state = CMD_STATE_IDLE; + pclog("AHA154x reset complete\n"); + break; + + case CMD_STATE_IDLE: + if (scsi->status & STATUS_CDF) + { + int invalid = 0; + + scsi->status &= ~STATUS_CDF; + + scsi->command = scsi->cmd_data; + pclog("New command %02x\n", scsi->command); +// if (scsi->command == 0x22) +// fatal("Here\n"); +// output = 3; + switch (scsi->command) + { + case COMMAND_NOP: + case COMMAND_START_SCSI_COMMAND: + case COMMAND_ADAPTER_INQUIRY: + case COMMAND_INQUIRE_INSTALLED_DEVICES: + case COMMAND_RETURN_CONFIG_DATA: + scsi->command_len = 0; + break; + + case COMMAND_ADAPTEC_SET_BIOS_BANK_1: + case COMMAND_ADAPTEC_SET_BIOS_BANK_2: + case COMMAND_ADAPTEC_GET_EXT_BIOS_INFO: + case COMMAND_ADAPTEC_START_BIOS_SCSI_CMD: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 0; + else + invalid = 1; + break; + + case COMMAND_BUSLOGIC_84: + case COMMAND_BUSLOGIC_85: + if (scsi->type == SCSI_BT545S) + scsi->command_len = 0; + else + invalid = 1; + break; + + case COMMAND_ECHO: + case COMMAND_MAILBOX_OUT_IRQ_ENA: + case COMMAND_SET_BUS_ON_TIME: + case COMMAND_SET_BUS_OFF_TIME: + case COMMAND_SET_AT_BUS_SPEED: + case COMMAND_RETURN_SETUP_DATA: + scsi->command_len = 1; + break; + + case COMMAND_ADAPTEC_SET_SHADOW_PARAMS: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 1; + else + invalid = 1; + break; + + case 0x22: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 35; /*COMMAND_ADAPTEC_PROGRAM_EEPROM*/ + else + { +// scsi->command_len = 1; /*COMMAND_BUSLOGIC_22*/ + pclog("Get 22\n"); +// scsi->command_len = 0; + invalid = 1; + primed = 1; + } + break; + + case COMMAND_BUSLOGIC_SET_CCB_FORMAT: + case COMMAND_BUSLOGIC_STRICT_RR: + case COMMAND_BUSLOGIC_EXTENDED_SETUP_INFO: + case COMMAND_BUSLOGIC_ADAPTER_MODEL_NR: + case COMMAND_BUSLOGIC_INQUIRY_SYNC_PERIOD: + if (scsi->type == SCSI_BT545S) + scsi->command_len = 1; + else + invalid = 1; + break; + + case COMMAND_ENABLE_MAILBOX_INTERFACE: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 2; + else + invalid = 1; + break; + + case COMMAND_WRITE_CHANNEL_2_BUF: + case COMMAND_READ_CHANNEL_2_BUF: + scsi->command_len = 3; + break; + + case COMMAND_SET_SELECTION_TIMEOUT: + scsi->command_len = 4; + break; + + case COMMAND_ADAPTEC_RETURN_EEPROM_DATA: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 3; + else + invalid = 1; + break; + + case COMMAND_MAILBOX_INITIALIZATION: + scsi->command_len = 4; + break; + + case COMMAND_BUSLOGIC_81: + if (scsi->type == SCSI_BT545S) + scsi->command_len = 5; + else + invalid = 1; + break; + + case COMMAND_START_BIOS_COMMAND: + scsi->command_len = 10; + scsi->bios_cmd_state = 0; + break; + + case COMMAND_ADAPTEC_BIOS_MAILBOX_INIT: + if (scsi->type == SCSI_AHA1542C) + scsi->command_len = 4; + else + invalid = 1; + break; + +/* case 0x40: case 0x42: case 0x44: case 0xff: + invalid = 1; + break;*/ + + default: + if (scsi->type == SCSI_AHA1542C) + { + if ((scsi->command > 0xd && scsi->command < 0x1a) || (scsi->command > 0x2a && scsi->command != 0x82)) + invalid = 1; + else + fatal("Bad AHA154x command %02x\n", scsi->command); + } + else + { + if (scsi->command > 0x22 && (scsi->command < 0xfa || scsi->command > 0xfc) && + !(scsi->command >= 0x81 && scsi->command <= 0x9d) && + scsi->command != 0xda && scsi->command != 0xdc) + invalid = 1; + else + fatal("Bad BT545S command %02x\n", scsi->command); + } + break; + } + + if (invalid) + { + scsi->status |= STATUS_INVDCMD; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + } + else if (!scsi->command_len) + scsi->cmd_state = CMD_STATE_CMD_IN_PROGRESS; + else + { + scsi->cmd_state = CMD_STATE_GET_PARAMS; + scsi->cur_param = 0; + } + } + if (scsi->cmd_state != CMD_STATE_CMD_IN_PROGRESS) + { +// pclog("Command not fallthrough\n"); + break; + } +// pclog("Command fallthrough\n"); + /*Fallthrough*/ + + case CMD_STATE_CMD_IN_PROGRESS: + switch (scsi->command) + { + case COMMAND_NOP: +// pclog("NOP complete\n"); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_MAILBOX_INITIALIZATION: + scsi->mbc = scsi->params[0]; + scsi->mba = scsi->params[3] | (scsi->params[2] << 8) | (scsi->params[1] << 16); + scsi->mba_i = scsi->mba + scsi->mbc*4; + scsi->mb_format = MB_FORMAT_4; + scsi->current_mbo = 0; + scsi->current_mbi = 0; + pclog("Mailbox init: MBC=%02x MBC=%06x\n", scsi->mbc, scsi->mba); + scsi->status &= ~STATUS_INIT; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_START_SCSI_COMMAND: + pclog("START_SCSI_COMMAND %i %i\n", scsi->ccb_state, scsi->scsi_state); + scsi->mbo_req++; + scsi->cmd_state = CMD_STATE_IDLE; + /*Don't send IRQ until we actually start processing a mailbox*/ + break; + + case COMMAND_START_BIOS_COMMAND: + if (scsi->ccb_state != CCB_STATE_IDLE) + break; + if (!scsi->bios_cmd_state) + pclog("Start BIOS command %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + scsi->params[0], scsi->params[1], scsi->params[2], scsi->params[3], scsi->params[4], + scsi->params[5], scsi->params[6], scsi->params[7], scsi->params[8], scsi->params[9]); + if (scsi->params[0] >= 0x16) + { + /*Only commands below 0x16 are implemented*/ + scsi->status |= STATUS_INVDCMD; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + } + else switch (scsi->params[0]) + { + case 0x00: /*Reset Disk System*/ + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case 0x01: /*Get Status of Last Operation*/ + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case 0x02: /*Read Sector(s) Into Memory*/ + switch (scsi->bios_cmd_state) + { + case 0: + { + int sector = scsi->params[5]; + int head = (scsi->params[4] & 0xf) | ((scsi->params[3] & 3) << 4); + int cylinder = (scsi->params[3] >> 2) | ((scsi->params[2] & 0xf) << 6); + + pclog("Cylinder=%i head=%i sector=%i\n", cylinder, head, sector); + addr = sector + (head * 32) + (cylinder * 64 * 32); + } + scsi->ccb.cdb[0] = SCSI_READ_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = addr >> 24; + scsi->ccb.cdb[3] = addr >> 16; + scsi->ccb.cdb[4] = addr >> 8; + scsi->ccb.cdb[5] = addr & 0xff; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = scsi->params[6]; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16);; + scsi->ccb.data_len = 512 * scsi->params[6]; + scsi->ccb.req_sense_len = CCB_SENSE_14; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + pclog("Read sector %08x %06x\n", addr, scsi->ccb.data_pointer); + scsi->bios_cmd_state++; + break; + case 1: + if (scsi->ccb.status) + fatal("Read sector fail %02x\n", scsi->ccb.status); + scsi->data_in = 0x00; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + case 0x03: /*Write Disk Sector(s)*/ + switch (scsi->bios_cmd_state) + { + case 0: + { + int sector = scsi->params[5]; + int head = (scsi->params[4] & 0xf) | ((scsi->params[3] & 3) << 4); + int cylinder = (scsi->params[3] >> 2) | ((scsi->params[2] & 0xf) << 6); + + addr = sector + (head * 32) + (cylinder * 64 * 32); + } + scsi->ccb.cdb[0] = SCSI_WRITE_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = addr >> 24; + scsi->ccb.cdb[3] = addr >> 16; + scsi->ccb.cdb[4] = addr >> 8; + scsi->ccb.cdb[5] = addr & 0xff; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = scsi->params[6]; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16);; + scsi->ccb.data_len = 512 * scsi->params[6]; + scsi->ccb.req_sense_len = CCB_SENSE_14; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + pclog("Write sector %08x %06x\n", addr, scsi->ccb.data_pointer); + scsi->bios_cmd_state++; + break; + case 1: + if (scsi->ccb.status) + fatal("Write sector fail %02x\n", scsi->ccb.status); + scsi->data_in = 0x00; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + case 0x04: /*Verify Disk Sector(s)*/ + switch (scsi->bios_cmd_state) + { + case 0: + { + int sector = scsi->params[5]; + int head = (scsi->params[4] & 0xf) | ((scsi->params[3] & 3) << 4); + int cylinder = (scsi->params[3] >> 2) | ((scsi->params[2] & 0xf) << 6); + + addr = sector + (head * 32) + (cylinder * 64 * 32); + } + scsi->ccb.cdb[0] = SCSI_VERIFY_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = addr >> 24; + scsi->ccb.cdb[3] = addr >> 16; + scsi->ccb.cdb[4] = addr >> 8; + scsi->ccb.cdb[5] = addr & 0xff; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = scsi->params[6]; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16);; + scsi->ccb.data_len = 512 * scsi->params[6]; + scsi->ccb.req_sense_len = CCB_SENSE_14; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + pclog("Verify sector %08x %06x\n", addr, scsi->ccb.data_pointer); + scsi->bios_cmd_state++; + break; + case 1: + if (scsi->ccb.status) + fatal("Verify sector fail %02x\n", scsi->ccb.status); + scsi->data_in = 0x00; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + /*AHA1542C firmware just fails all of these*/ + case 0x05: case 0x06: case 0x07: + case 0x0a: case 0x0b: + case 0x12: case 0x13: + scsi->status |= STATUS_INVDCMD; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case 0x08: /*Get Drive Parameters*/ + switch (scsi->bios_cmd_state) + { + case 0: + scsi->ccb.cdb[0] = SCSI_READ_CAPACITY_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = 0; + scsi->ccb.cdb[3] = 0; + scsi->ccb.cdb[4] = 0; + scsi->ccb.cdb[5] = 0; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = 0; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = -1; + scsi->ccb.data_len = 8; + scsi->ccb.req_sense_len = CCB_SENSE_NONE; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->bios_cmd_state++; + break; + case 1: + addr = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16); + mem_writeb_phys(addr, scsi->int_buffer[0]); + mem_writeb_phys(addr+1, scsi->int_buffer[1]); + mem_writeb_phys(addr+2, scsi->int_buffer[2]); + mem_writeb_phys(addr+3, scsi->int_buffer[3]); + pclog("Got size %06x %02x%02x%02x%02x\n", addr, scsi->int_buffer[3],scsi->int_buffer[2],scsi->int_buffer[1],scsi->int_buffer[0]); + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + case 0x09: /*Initialize Drive Parameters*/ + case 0x0c: /*Seek To Cylinder*/ + case 0x0d: /*Reset Hard Disks*/ + case 0x0e: /*Read Sector Buffer*/ + case 0x0f: /*Write Sector Buffer*/ + case 0x10: /*Check If Drive Ready*/ + case 0x11: /*Recalibrate Drive*/ + case 0x14: /*Controller Internal Diagnostic*/ + pclog("Unimplemented AHA1542 BIOS command - 0x%02x\n", scsi->params[0]); + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case 0x15: /*Get Disk Type*/ + switch (scsi->bios_cmd_state) + { + case 0: + scsi->ccb.cdb[0] = SCSI_INQUIRY; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = 0; + scsi->ccb.cdb[3] = 0; + scsi->ccb.cdb[4] = 36; + scsi->ccb.cdb[5] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 6; + scsi->ccb.data_pointer = -1; + scsi->ccb.data_len = 36; + scsi->ccb.req_sense_len = CCB_SENSE_NONE; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->ccb.from_mailbox = 0; + scsi->bios_cmd_state++; + break; + case 1: + if (scsi->int_buffer[0] & 0x1f) + { + /*Not a direct-access device*/ + fatal("Not a direct-access device\n"); + } + scsi->ccb.cdb[0] = SCSI_READ_CAPACITY_10; + scsi->ccb.cdb[1] = 0; + scsi->ccb.cdb[2] = 0; + scsi->ccb.cdb[3] = 0; + scsi->ccb.cdb[4] = 0; + scsi->ccb.cdb[5] = 0; + scsi->ccb.cdb[6] = 0; + scsi->ccb.cdb[7] = 0; + scsi->ccb.cdb[8] = 0; + scsi->ccb.cdb[9] = 0; + scsi->ccb.lun = 0; + scsi->ccb.target_id = scsi->params[1] & 7; + scsi->ccb.scsi_cmd_len = 10; + scsi->ccb.data_pointer = -1; + scsi->ccb.data_len = 8; + scsi->ccb.req_sense_len = CCB_SENSE_NONE; + scsi->ccb_state = CCB_STATE_SEND_COMMAND; + scsi->bios_cmd_state++; + break; + case 2: + addr = scsi->params[9] | (scsi->params[8] << 8) | (scsi->params[7] << 16); + mem_writeb_phys(addr, scsi->int_buffer[0]); + mem_writeb_phys(addr+1, scsi->int_buffer[1]); + mem_writeb_phys(addr+2, scsi->int_buffer[2]); + mem_writeb_phys(addr+3, scsi->int_buffer[3]); + pclog("Got size %06x %02x%02x%02x%02x\n", addr, scsi->int_buffer[3],scsi->int_buffer[2],scsi->int_buffer[1],scsi->int_buffer[0]); + scsi->data_in = 0; + set_irq(scsi, ISR_HACC); + scsi->status |= STATUS_DF; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + default: + fatal("Get Disk Type state %i\n", scsi->bios_cmd_state); + } + //fatal("data_pointer %06x\n", scsi->ccb.data_pointer); + break; + + default: + scsi->status |= STATUS_INVDCMD; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + } + break; + + case COMMAND_ADAPTER_INQUIRY: + if (scsi->type == SCSI_BT545S) + { + scsi->result[0] = 0x41; + scsi->result[1] = 0x41; /*Standard model*/ + scsi->result[2] = 0x33; /*Firmware revision*/ + scsi->result[3] = 0x33; + } + else + { + scsi->result[0] = 0x44; /*AHA-1542CF*/ + scsi->result[1] = 0x30; + scsi->result[2] = 0x30; /*Firmware revision*/ + scsi->result[3] = 0x31; + } + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 4; + break; + + case COMMAND_MAILBOX_OUT_IRQ_ENA: + scsi->mbo_irq_enable = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_SET_SELECTION_TIMEOUT: + scsi->e_d = scsi->params[0]; + scsi->to = (scsi->params[1] << 8) | scsi->params[2]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_SET_BUS_ON_TIME: + scsi->bon = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_SET_BUS_OFF_TIME: + scsi->boff = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_SET_AT_BUS_SPEED: + scsi->atbs = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_INQUIRE_INSTALLED_DEVICES: + for (c = 0; c < 8; c++) + scsi->result[c] = scsi->bus.devices[c] ? 1 : 0; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 8; + break; + + case COMMAND_RETURN_CONFIG_DATA: + scsi->result[0] = 1 << scsi->dma; + scsi->result[1] = 1 << (scsi->irq-9); + scsi->result[2] = scsi->host_id; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 3; + break; + + case COMMAND_ECHO: + pclog("ECHO\n"); + scsi->result[0] = scsi->params[0]; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 1; + break; + + case COMMAND_RETURN_SETUP_DATA: + pclog("Return setup data %i %02x %06x\n", scsi->params[0], scsi->mbc, scsi->mba); + scsi->result[0] = 0x00; /*SPS*/ + scsi->result[1] = scsi->atbs; /*AT bus speed*/ + scsi->result[2] = scsi->bon; /*BON*/ + scsi->result[3] = scsi->boff; /*BOFF*/ + scsi->result[4] = scsi->mbc; /*DS:E8 - mailbox count*/ + scsi->result[5] = scsi->mba >> 16; /*DS:DA - set by command 0x81?*/ + scsi->result[6] = scsi->mba >> 8; /*DS:DB*/ + scsi->result[7] = scsi->mba & 0xff; /*DS:DC*/ + scsi->result[8] = 0x00; /*STA0*/ + scsi->result[9] = 0x00; /*STA1*/ + scsi->result[10] = 0x00; /*STA2*/ + scsi->result[11] = 0x00; /*STA3*/ + scsi->result[12] = 0x00; /*STA4*/ + scsi->result[13] = 0x00; /*STA5*/ + scsi->result[14] = 0x00; /*STA6*/ + scsi->result[15] = 0x00; /*STA7*/ + scsi->result[16] = 0x00; /*DS (DS:1e5b)*/ + if (scsi->type == SCSI_BT545S) + { + scsi->result[17] = 0x42; /*Firmware version*/ + scsi->result[18] = 0x44; + scsi->result[19] = 0x41; + } + else + { + for (c = 0; c < 20; c++) + scsi->result[c+17] = 0; /*Customer signature*/ + scsi->result[37] = 0; /*Auto-retry*/ + scsi->result[38] = 0; /*Board switches*/ + scsi->result[39] = 0xa3; /*Checksum*/ + scsi->result[40] = 0xc2; + scsi->result[41] = scsi->bios_mba >> 16; + scsi->result[42] = scsi->bios_mba >> 8; + scsi->result[43] = scsi->bios_mba & 0xff; + } + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = MIN(scsi->params[0], 20); + for (; scsi->result_len < scsi->params[0]; scsi->result_len++) + scsi->result[scsi->result_len] = 0; + break; + + case COMMAND_WRITE_CHANNEL_2_BUF: + addr = scsi->params[2] | (scsi->params[1] << 8) | (scsi->params[0] << 16); + pclog("WRITE_CHANNEL_2_BUF %06x\n", addr); + for (c = 0; c < 64; c++) + scsi->dma_buffer[c] = mem_readb_phys(addr + c); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + pclog("Command complete\n"); + break; + + case COMMAND_READ_CHANNEL_2_BUF: + addr = scsi->params[2] | (scsi->params[1] << 8) | (scsi->params[0] << 16); + pclog("READ_CHANNEL_2_BUF %06x\n", addr); + for (c = 0; c < 64; c++) + mem_writeb_phys(addr + c, scsi->dma_buffer[c]); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + pclog("Command complete\n"); + break; + + case 0x22: + if (scsi->type == SCSI_AHA1542C) + { + /*COMMAND_ADAPTEC_PROGRAM_EEPROM*/ + for (c = 0; c < scsi->params[1]; c++) + { + pclog("EEPROM %02x = %02x\n", (scsi->params[2] + c) & 0xff, scsi->params[c+3]); + scsi->eeprom[(scsi->params[2] + c) & 0xff] = scsi->params[c+3]; + } + scsi->host_id = scsi->eeprom[0] & 7; + scsi->dma = (scsi->eeprom[1] >> 4) & 7; + scsi->irq = (scsi->eeprom[1] & 7) + 9; + pclog("Program EEPROM: IRQ=%i DMA=%i host_id=%i\n", scsi->irq, scsi->dma, scsi->host_id); + + aha1542c_eeprom_save(scsi); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + } + else + { + /*COMMAND_BUSLOGIC_22*/ + pclog("BUSLOGIC_22\n"); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + primed = 1; +// scsi->result[0] = 1 << scsi->dma; /*DMA7*/ +// scsi->result[1] = 1 << (scsi->irq-9); /*IRQ10*/ +// scsi->result[2] = scsi->host_id; /*SCSI ID*/ +// scsi->cmd_state = CMD_STATE_SEND_RESULT; +// scsi->result_pos = 0; +// scsi->result_len = 3; + } + break; + + case COMMAND_ADAPTEC_RETURN_EEPROM_DATA: + pclog("Return EEPROM data %02x %02x %02x\n", scsi->params[0], scsi->params[1], scsi->params[2]); + for (c = 0; c < scsi->params[1]; c++) + { + scsi->result[c] = scsi->eeprom[(scsi->params[2] + c) & 0xff]; + pclog(" EEPROM data %02x %02x\n", (scsi->params[2] + c) & 0xff, scsi->result[c]); + } + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = c; + break; + + case COMMAND_ADAPTEC_SET_SHADOW_PARAMS: + pclog("Set shadow params %02x\n", scsi->params[0]); + scsi->shadow = scsi->params[0]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_BIOS_MAILBOX_INIT: + scsi->bios_mbc = scsi->params[0]; + scsi->bios_mba = scsi->params[3] | (scsi->params[2] << 8) | (scsi->params[1] << 16); + scsi->bios_mbo_inited = 1; + pclog("BIOS mailbox init: MBC=%02x MBC=%06x\n", scsi->bios_mbc, scsi->bios_mba); + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_SET_BIOS_BANK_1: + mem_mapping_set_exec(&scsi->mapping, &scsi->bios_rom.rom[0]); + scsi->bios_bank = 0x0000; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_SET_BIOS_BANK_2: + mem_mapping_set_exec(&scsi->mapping, &scsi->bios_rom.rom[0x4000]); + scsi->bios_bank = 0x4000; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_GET_EXT_BIOS_INFO: + scsi->result[0] = 0; + scsi->result[1] = scsi->mblt; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 2; + break; + + case COMMAND_ENABLE_MAILBOX_INTERFACE: + scsi->mbu = scsi->params[0]; + scsi->mblt = scsi->params[1]; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_ADAPTEC_START_BIOS_SCSI_CMD: + pclog("START_BIOS_SCSI_COMMAND %02x %08x %i\n", scsi->bios_mbc, scsi->bios_mba, scsi->ccb_state); + scsi->bios_mbo_req++; + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_BUSLOGIC_81: + scsi->mbc = scsi->params[0]; + scsi->mba = scsi->params[1] | (scsi->params[2] << 8) | (scsi->params[3] << 16) | (scsi->params[4] << 24); + scsi->mba_i = scsi->mba + scsi->mbc*8; + scsi->mb_format = MB_FORMAT_8; + scsi->current_mbo = 0; + scsi->current_mbi = 0; + pclog("Mailbox init: MBC=%02x MBC=%08x\n", scsi->mbc, scsi->mba); + scsi->status &= ~STATUS_INIT; + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_BUSLOGIC_84: + scsi->result[0] = 0x31; /*Firmware sub-version?*/ + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 1; + break; + + case COMMAND_BUSLOGIC_85: + scsi->result[0] = 0x20; /*???*/ + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = 1; + break; + + case COMMAND_BUSLOGIC_ADAPTER_MODEL_NR: + scsi->result[0] = '5'; + scsi->result[1] = '4'; + scsi->result[2] = '2'; + scsi->result[3] = 'B'; + scsi->result[4] = 'H'; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = MIN(scsi->params[0], 5); + for (; scsi->result_len < scsi->params[0]; scsi->result_len++) + scsi->result[scsi->result_len] = 0; + break; + + case COMMAND_BUSLOGIC_INQUIRY_SYNC_PERIOD: + for (c = 0; c < 8; c++) + scsi->result[c] = 0; + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = MIN(scsi->params[0], 8); + for (; scsi->result_len < scsi->params[0]; scsi->result_len++) + scsi->result[scsi->result_len] = 0; + break; + + + case COMMAND_BUSLOGIC_EXTENDED_SETUP_INFO: + pclog("Extended setup info %i\n", scsi->params[0]); + scsi->result[0] = 0x41; + scsi->result[1] = scsi->bios_addr >> 12; /*BIOS addr*/ + scsi->result[2] = 0x00; + scsi->result[3] = 0x20; + scsi->result[4] = 0x00; /*DS:E8 >> 3*/ + scsi->result[5] = 0x00; /*DS:DA - set by command 0x81?*/ + scsi->result[6] = 0x00; /*DS:DB*/ + scsi->result[7] = 0x00; /*DS:DC*/ + scsi->result[8] = 0x00; /*DS:DD*/ + scsi->result[9] = 0x33; /*FFFF:9*/ + scsi->result[10] = 0x33; /*FFFF:A*/ + scsi->result[11] = 0x31; /*FFFF:B*/ + scsi->cmd_state = CMD_STATE_SEND_RESULT; + scsi->result_pos = 0; + scsi->result_len = MIN(scsi->params[0], 12); + for (; scsi->result_len < scsi->params[0]; scsi->result_len++) + scsi->result[scsi->result_len] = 0; + break; + + case COMMAND_BUSLOGIC_STRICT_RR: + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + case COMMAND_BUSLOGIC_SET_CCB_FORMAT: + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + break; + + default: + fatal("Bad AHA154x command in progress %02x\n", scsi->command); + } + break; + + case CMD_STATE_GET_PARAMS: + if (scsi->status & STATUS_CDF) + { + scsi->status &= ~STATUS_CDF; + + scsi->params[scsi->cur_param++] = scsi->cmd_data; + + if (scsi->cur_param == scsi->command_len) + scsi->cmd_state = CMD_STATE_CMD_IN_PROGRESS; + } + break; + + case CMD_STATE_SEND_RESULT: + if (!(scsi->status & STATUS_DF)) + { + if (scsi->result_pos == scsi->result_len) + { + set_irq(scsi, ISR_HACC); + scsi->cmd_state = CMD_STATE_IDLE; + pclog("Command complete\n"); + } + else + { + scsi->status |= STATUS_DF; + scsi->data_in = scsi->result[scsi->result_pos++]; + pclog("Return data %02x %i %i\n", scsi->data_in, scsi->result_pos-1, scsi->result_len); + } + } + break; + + default: + fatal("Unknown state %d\n", scsi->cmd_state); + } +} + +static void process_ccb(aha154x_t *scsi) +{ + int c; + + switch (scsi->ccb_state) + { + case CCB_STATE_IDLE: + if (!(scsi->status & STATUS_INIT) && scsi->mbo_req) + { +// pclog("mbo_req %i\n", scsi->mbc); + for (c = 0; c < scsi->mbc; c++) + { + uint32_t ccb; + uint8_t command; + + if (scsi->mb_format == MB_FORMAT_4) + { + uint32_t mbo = mem_readl_phys(scsi->mba + c*4); + command = mbo & 0xff; + ccb = (mbo >> 24) | ((mbo >> 8) & 0xff00) | ((mbo << 8) & 0xff0000); +// pclog("MBO%02x = %08x\n", c, mbo); + } + else + { + ccb = mem_readl_phys(scsi->mba + c*8); + command = mem_readb_phys(scsi->mba + c*8 + 7); +// pclog("MBO%02x = %08x %02x\n", c, ccb, command); + } + + if (command == COMMAND_START_CCB) + { + pclog("Start CCB %08x %i\n", ccb, c); + + scsi->current_mbo = c; + scsi->current_mbo_is_bios = 0; + scsi->ccb.addr = ccb; + + process_cdb(scsi); + + scsi->mbo_req--; + + //set_irq(scsi, ISR_HACC); + break; + } + else if (command == COMMAND_ABORT_CCB) + { +// fatal("Abort command\n"); + scsi->mbo_req--; + + if (scsi->mb_format == MB_FORMAT_4) + { + mem_writeb_phys(scsi->mba + c*8, 0); + + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_ABORTED); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 1, ccb >> 16); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 2, ccb >> 8); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 3, ccb & 0xff); + } + else + { + mem_writeb_phys(scsi->mba + c*8 + 7, 0); + + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8, ccb); + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_ABORTED); + } + + scsi->current_mbi++; + if (scsi->current_mbi >= scsi->mbc) + scsi->current_mbi = 0; + set_irq(scsi, (scsi->mbo_irq_enable ? ISR_MBOA : 0) | ISR_MBIF | ISR_HACC); + break; + } + } + } + if (scsi->bios_mbo_inited && scsi->bios_mbo_req) + { + for (c = 0; c < scsi->bios_mbc; c++) + { + uint32_t ccb; + uint8_t command; + + uint32_t mbo = mem_readl_phys(scsi->bios_mba + c*4); + command = mbo & 0xff; + ccb = (mbo >> 24) | ((mbo >> 8) & 0xff00) | ((mbo << 8) & 0xff0000); + + if (command == COMMAND_START_CCB) + { + pclog("Start BIOS CCB %08x %i\n", ccb, c); + + scsi->current_mbo = c; + scsi->current_mbo_is_bios = 1; + scsi->ccb.addr = ccb; + + process_cdb(scsi); + + scsi->bios_mbo_req--; + set_irq(scsi, ISR_HACC); + break; + } + } + } + break; + + case CCB_STATE_SEND_COMMAND: + if (scsi->scsi_state != SCSI_STATE_IDLE) + break; /*Wait until SCSI state machine is ready for new command*/ + for (c = 0; c < scsi->ccb.scsi_cmd_len; c++) + { + scsi->cdb.data[c] = scsi->ccb.cdb[c]; +// pclog(" CDB[%02x]=%02x\n", c, scsi->cdb.data[c]); + } + scsi->cdb.len = scsi->ccb.scsi_cmd_len; + scsi->cdb.idx = 0; + if (scsi->ccb.opcode == CCB_INITIATOR_SCATTER_GATHER || scsi->ccb.opcode == CCB_INITIATOR_SCATTER_GATHER_RESIDUAL) + { + scsi->cdb.data_seg_list_len = scsi->ccb.data_seg_list_len; + scsi->cdb.data_seg_list_pointer = scsi->ccb.data_seg_list_pointer; + scsi->cdb.data_seg_list_idx = 0; + scsi->cdb.scatter_gather = 1; + scsi->cdb.data_len = 0; + scsi->cdb.data_idx = 0; + } + else + { + scsi->cdb.data_pointer = scsi->ccb.data_pointer; + scsi->cdb.data_len = scsi->ccb.data_len; + scsi->cdb.scatter_gather = 0; + } + scsi->cdb.bytes_transferred = 0; + scsi->cdb.data_idx = 0; + scsi->scsi_state = SCSI_STATE_SELECT; + /*SCSI will now select the device and execute the command*/ + scsi->ccb_state = CCB_STATE_WAIT_COMMAND; + break; + + case CCB_STATE_WAIT_COMMAND: + if (scsi->scsi_state == SCSI_STATE_SELECT_FAILED) + { + pclog("Command select has failed\n"); + if (scsi->ccb.from_mailbox) + { + mem_writeb_phys(scsi->ccb.addr + 0xe, HOST_STATUS_SELECTION_TIME_OUT); + + if (scsi->mb_format == MB_FORMAT_4) + { + if (scsi->current_mbo_is_bios) + { + mem_writeb_phys(scsi->bios_mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE_WITH_ERROR); + } + else + { + mem_writeb_phys(scsi->mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE_WITH_ERROR); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 1, scsi->ccb.addr >> 16); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 2, scsi->ccb.addr >> 8); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 3, scsi->ccb.addr & 0xff); + } + } + else + { + if (scsi->current_mbo_is_bios) + fatal("MBO_IS_BIOS MB_FORMAT_8\n"); + mem_writeb_phys(scsi->mba + scsi->current_mbo*8 + 7, COMMAND_FREE_CCB); + + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8, scsi->ccb.addr); + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_COMPLETE_WITH_ERROR << 24); + } + + if (!scsi->current_mbo_is_bios) + { + scsi->current_mbi++; + if (scsi->current_mbi >= scsi->mbc) + scsi->current_mbi = 0; + set_irq(scsi, (scsi->mbo_irq_enable ? ISR_MBOA : 0) | ISR_MBIF); + } + else if (scsi->mbo_irq_enable) + set_irq(scsi, ISR_MBOA); + } +// set_irq(scsi, ISR_HACC); + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + break; + } + if (scsi->scsi_state != SCSI_STATE_IDLE) + break; /*Wait until SCSI state machine has completed command*/ + scsi->ccb.status = scsi->cdb.last_status; + scsi->ccb.bytes_transferred = scsi->cdb.bytes_transferred; + scsi->ccb_state = CCB_STATE_SEND_REQUEST_SENSE; + break; + + case CCB_STATE_SEND_REQUEST_SENSE: + if (scsi->ccb.req_sense_len == CCB_SENSE_NONE) + { +// pclog("No sense data\n"); + if (scsi->ccb.from_mailbox) + { + uint32_t residue = scsi->ccb.total_data_len - scsi->ccb.bytes_transferred; + +// pclog("Residue=%08x %x %x %i MBI=%i\n", residue, scsi->ccb.total_data_len, scsi->ccb.bytes_transferred, scsi->ccb.residual, scsi->current_mbi); + mem_writeb_phys(scsi->ccb.addr + 0xe, HOST_STATUS_COMMAND_COMPLETE); + mem_writeb_phys(scsi->ccb.addr + 0xf, scsi->ccb.status); + + if (scsi->mb_format == MB_FORMAT_4) + { + if (scsi->ccb.residual) + { + mem_writeb_phys(scsi->ccb.addr + 0x4, residue >> 16); + mem_writeb_phys(scsi->ccb.addr + 0x5, residue >> 8); + mem_writeb_phys(scsi->ccb.addr + 0x6, residue & 0xff); + } + + if (scsi->current_mbo_is_bios) + { + mem_writeb_phys(scsi->bios_mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + + if (scsi->ccb.status == STATUS_GOOD) + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE); + else + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE_WITH_ERROR); + } + else + { + mem_writeb_phys(scsi->mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + + if (scsi->ccb.status == STATUS_GOOD) + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE); + else + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE_WITH_ERROR); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 1, scsi->ccb.addr >> 16); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 2, scsi->ccb.addr >> 8); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 3, scsi->ccb.addr & 0xff); + } + } + else + { + if (scsi->current_mbo_is_bios) + fatal("MBO_IS_BIOS MB_FORMAT_8\n"); + + if (scsi->ccb.residual) + mem_writel_phys(scsi->ccb.addr + 0x4, residue); + + mem_writeb_phys(scsi->mba + scsi->current_mbo*8 + 7, COMMAND_FREE_CCB); + + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8, scsi->ccb.addr); + if (scsi->ccb.status == STATUS_GOOD) + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_COMPLETE << 24); + else + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, (MBI_CCB_COMPLETE_WITH_ERROR << 24) | (scsi->ccb.status << 8)); + } + + if (!scsi->current_mbo_is_bios) + { + scsi->current_mbi++; + if (scsi->current_mbi >= scsi->mbc) + scsi->current_mbi = 0; + set_irq(scsi, (scsi->mbo_irq_enable ? ISR_MBOA : 0) | ISR_MBIF); + } + else if (scsi->mbo_irq_enable) + set_irq(scsi, ISR_MBOA); + } + scsi->ccb_state = CCB_STATE_IDLE; + break; + } + /*Build request sense command*/ + scsi->cdb.data[0] = SCSI_REQUEST_SENSE; + scsi->cdb.data[1] = scsi->ccb.lun << 5; + scsi->cdb.data[2] = 0x00; + scsi->cdb.data[3] = 0x00; + if (scsi->ccb.req_sense_len == CCB_SENSE_14) + scsi->cdb.data[4] = 14; + else + scsi->cdb.data[4] = scsi->ccb.req_sense_len; + scsi->cdb.data[5] = 14; + scsi->cdb.len = 6; + scsi->cdb.idx = 0; + if (scsi->ccb.from_mailbox) + scsi->cdb.data_pointer = -1; + else + scsi->cdb.data_pointer = scsi->ccb.addr + 0x12 + scsi->ccb.scsi_cmd_len; + scsi->cdb.data_idx = 0; + scsi->cdb.data_len = scsi->cdb.data[4]; + scsi->cdb.scatter_gather = 0; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->ccb_state = CCB_STATE_WAIT_REQUEST_SENSE; + break; + + case CCB_STATE_WAIT_REQUEST_SENSE: + if (scsi->scsi_state != SCSI_STATE_IDLE) + break; /*Wait until SCSI state machine has completed command*/ + + if (scsi->ccb.from_mailbox) + { + uint32_t residue = scsi->ccb.total_data_len - scsi->ccb.bytes_transferred; +// pclog("residue=%x %x %x\n", residue, scsi->ccb.total_data_len, scsi->ccb.bytes_transferred); + mem_writeb_phys(scsi->ccb.addr + 0xe, HOST_STATUS_COMMAND_COMPLETE); + mem_writeb_phys(scsi->ccb.addr + 0xf, scsi->ccb.status); + + if (scsi->mb_format == MB_FORMAT_4) + { + if (scsi->ccb.residual) + { + mem_writeb_phys(scsi->ccb.addr + 0x4, residue >> 16); + mem_writeb_phys(scsi->ccb.addr + 0x5, residue >> 8); + mem_writeb_phys(scsi->ccb.addr + 0x6, residue & 0xff); + } + + if (scsi->current_mbo_is_bios) + { + mem_writeb_phys(scsi->bios_mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + + if (scsi->ccb.status == STATUS_GOOD) + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE); + else + mem_writeb_phys(scsi->ccb.addr + 0xd, MBI_CCB_COMPLETE_WITH_ERROR); + } + else + { + mem_writeb_phys(scsi->mba + scsi->current_mbo*4, COMMAND_FREE_CCB); + +// pclog("CCB status %02x\n", scsi->ccb.status); + if (scsi->ccb.status == STATUS_GOOD) + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE); + else + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4, MBI_CCB_COMPLETE_WITH_ERROR); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 1, scsi->ccb.addr >> 16); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 2, scsi->ccb.addr >> 8); + mem_writeb_phys(scsi->mba_i + scsi->current_mbi*4 + 3, scsi->ccb.addr & 0xff); + } + } + else + { + if (scsi->current_mbo_is_bios) + fatal("MBO_IS_BIOS MB_FORMAT_8\n"); + + if (scsi->ccb.residual) + mem_writel_phys(scsi->ccb.addr + 0x4, residue); + + mem_writeb_phys(scsi->mba + scsi->current_mbo*8 + 7, COMMAND_FREE_CCB); + + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8, scsi->ccb.addr); + if (scsi->ccb.status == STATUS_GOOD) + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, MBI_CCB_COMPLETE << 24); + else + mem_writel_phys(scsi->mba_i + scsi->current_mbi*8 + 4, (MBI_CCB_COMPLETE_WITH_ERROR << 24) | (scsi->ccb.status << 8)); + } + + if (!scsi->current_mbo_is_bios) + { + scsi->current_mbi++; + if (scsi->current_mbi >= scsi->mbc) + scsi->current_mbi = 0; + set_irq(scsi, (scsi->mbo_irq_enable ? ISR_MBOA : 0) | ISR_MBIF); + } + else if (scsi->mbo_irq_enable) + set_irq(scsi, ISR_MBOA); + } +// pclog("CCB_STATE_WAIT_REQUEST_SENSE over %i\n", scsi->ccb.from_mailbox); + scsi->ccb_state = CCB_STATE_IDLE; + break; + + default: + fatal("Unknown CCB_state %d\n", scsi->ccb_state); + } +} + +static void process_scsi(aha154x_t *scsi) +{ + int c; + int bytes_transferred = 0; + + switch (scsi->scsi_state) + { + case SCSI_STATE_IDLE: + break; + + case SCSI_STATE_SELECT: + scsi->cdb.last_status = 0; +// pclog("Select target ID %i\n", scsi->ccb.target_id); + scsi_bus_update(&scsi->bus, BUS_SEL | BUS_SETDATA(1 << scsi->ccb.target_id)); + if (!(scsi_bus_read(&scsi->bus) & BUS_BSY) || scsi->ccb.target_id > 6) + { + pclog("STATE_SCSI_SELECT failed to select target %i\n", scsi->ccb.target_id); + scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + break; + } + + scsi_bus_update(&scsi->bus, 0); + if (!(scsi_bus_read(&scsi->bus) & BUS_BSY)) + { + pclog("STATE_SCSI_SELECT failed to select target %i 2\n", scsi->ccb.target_id); + scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + break; + } + + /*Device should now be selected*/ + if (!wait_for_bus(&scsi->bus, BUS_CD, 1)) + { + pclog("Device failed to request command\n"); + scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + break; + } + + scsi->scsi_state = SCSI_STATE_SEND_COMMAND; + break; + + case SCSI_STATE_SELECT_FAILED: + break; + + case SCSI_STATE_SEND_COMMAND: + while (scsi->cdb.idx < scsi->cdb.len && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus_out; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + fatal("SEND_COMMAND - bus phase incorrect\n"); + if (bus_state & BUS_REQ) + break; + } + if (c == 20) + { + pclog("SEND_COMMAND timed out\n"); + break; + } + + bus_out = BUS_SETDATA(scsi->cdb.data[scsi->cdb.idx]); +// pclog(" Command send %02x %i\n", scsi->cdb.data[scsi->cdb.idx], scsi->cdb.len); +// if (!scsi->cdb.idx && scsi->cdb.data[scsi->cdb.idx] == 0x25 && scsi->current_mbo == 1) +// output = 3; + scsi->cdb.idx++; + bytes_transferred++; + + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + } + if (scsi->cdb.idx == scsi->cdb.len) + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + + case SCSI_STATE_NEXT_PHASE: + /*Wait for SCSI command to move to next phase*/ + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("NEXT_PHASE - dropped BSY waiting\n"); + + if (bus_state & BUS_REQ) + { + int bus_out; +// pclog("SCSI next phase - %x\n", bus_state); + switch (bus_state & (BUS_IO | BUS_CD | BUS_MSG)) + { + case 0: +// pclog("Move to write data\n"); + scsi->scsi_state = SCSI_STATE_WRITE_DATA; + break; + + case BUS_IO: +// pclog("Move to read data\n"); + scsi->scsi_state = SCSI_STATE_READ_DATA; + break; + + case (BUS_CD | BUS_IO): +// pclog("Move to read status\n"); + scsi->scsi_state = SCSI_STATE_READ_STATUS; + break; + + case (BUS_CD | BUS_IO | BUS_MSG): +// pclog("Move to read message\n"); + scsi->scsi_state = SCSI_STATE_READ_MESSAGE; + break; + + case BUS_CD: + bus_out = BUS_SETDATA(0); + + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + break; + + default: + fatal(" Bad new phase %x\n", bus_state); + } + break; + } + } + break; + + case SCSI_STATE_END_PHASE: + /*Wait for SCSI command to move to next phase*/ + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + { + pclog("END_PHASE - dropped BSY waiting\n"); +// if (scsi->ccb.req_sense_len == CCB_SENSE_NONE) +// fatal("No sense data\n"); + scsi->scsi_state = SCSI_STATE_IDLE; + break; + } + + if (bus_state & BUS_REQ) + fatal("END_PHASE - unexpected REQ\n"); + } + break; + + case SCSI_STATE_READ_DATA: +//pclog("READ_DATA %i,%i %i\n", scsi->cdb.data_idx,scsi->cdb.data_len, scsi->cdb.scatter_gather); + while (scsi->cdb.data_idx < scsi->cdb.data_len && scsi->scsi_state == SCSI_STATE_READ_DATA && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int d; + + for (d = 0; d < 20; d++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_DATA - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO) + { + pclog("READ_DATA - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data = BUS_GETDATA(bus_state); + int bus_out = 0; + + if (scsi->cdb.data_pointer == -1) + scsi->int_buffer[scsi->cdb.data_idx] = data; + else + mem_writeb_phys(scsi->cdb.data_pointer + scsi->cdb.data_idx, data); + scsi->cdb.data_idx++; + scsi->cdb.bytes_transferred++; + +// pclog("Read data %02x %i %06x\n", data, scsi->cdb.data_idx, scsi->cdb.data_pointer + scsi->cdb.data_idx); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + break; + } + } + + bytes_transferred++; + } + if (scsi->cdb.data_idx == scsi->cdb.data_len) + { + if (scsi->cdb.scatter_gather) + { + if (scsi->cdb.data_seg_list_idx >= scsi->cdb.data_seg_list_len) + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + else + { + if (scsi->mb_format == MB_FORMAT_4) + { + scsi->cdb.data_len = mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 2) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 1) << 8) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx) << 16); + scsi->cdb.data_pointer = mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 5) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 4) << 8) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 3) << 16); + scsi->cdb.data_idx = 0; + scsi->cdb.data_seg_list_idx += 6; + } + else + { + scsi->cdb.data_len = mem_readl_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx); + scsi->cdb.data_pointer = mem_readl_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 4); + scsi->cdb.data_idx = 0; + scsi->cdb.data_seg_list_idx += 8; +// output = 3; + } + pclog("Got scatter gather %08x %08x\n", scsi->cdb.data_pointer, scsi->cdb.data_len); + } + } + else + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + } + break; + + case SCSI_STATE_WRITE_DATA: + while (scsi->cdb.data_idx < scsi->cdb.data_len && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int d; + + for (d = 0; d < 20; d++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("WRITE_DATA - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != 0) + { + pclog("WRITE_DATA - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data;// = BUS_GETDATA(bus_state); + int bus_out; + + if (scsi->cdb.data_pointer == -1) + data = scsi->int_buffer[scsi->cdb.data_idx]; + else + data = mem_readb_phys(scsi->cdb.data_pointer + scsi->cdb.data_idx); + scsi->cdb.data_idx++; + scsi->cdb.bytes_transferred++; + +// pclog("Write data %02x %i\n", data, scsi->cdb.data_idx); + bus_out = BUS_SETDATA(data); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + break; + } + } + + bytes_transferred++; + } + if (scsi->cdb.data_idx == scsi->cdb.data_len) + { + if (scsi->cdb.scatter_gather) + { + if (scsi->cdb.data_seg_list_idx >= scsi->cdb.data_seg_list_len) + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + else + { + if (scsi->mb_format == MB_FORMAT_4) + { + scsi->cdb.data_len = mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 2) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 1) << 8) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx) << 16); + scsi->cdb.data_pointer = mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 5) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 4) << 8) | + (mem_readb_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 3) << 16); + scsi->cdb.data_idx = 0; + scsi->cdb.data_seg_list_idx += 6; + } + else + { + scsi->cdb.data_len = mem_readl_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx); + scsi->cdb.data_pointer = mem_readl_phys(scsi->cdb.data_seg_list_pointer + scsi->cdb.data_seg_list_idx + 4); + scsi->cdb.data_idx = 0; + scsi->cdb.data_seg_list_idx += 8; + } + pclog("Got scatter gather %08x %08x\n", scsi->cdb.data_pointer, scsi->cdb.data_len); + } + } + else + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + } + break; + + case SCSI_STATE_READ_STATUS: + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_STATUS - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO)) + { + pclog("READ_STATUS - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t status = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read status %02x\n", status); + if (scsi->ccb.from_mailbox) + mem_writeb_phys(scsi->ccb.addr + 0xf, status); + scsi->cdb.last_status = status; + + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + } + break; + + case SCSI_STATE_READ_MESSAGE: + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + fatal("READ_MESSAGE - dropped BSY waiting\n"); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO | BUS_MSG)) + { + pclog("READ_MESSAGE - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t msg = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read message %02x\n", msg); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + + switch (msg) + { + case MSG_COMMAND_COMPLETE: + scsi->scsi_state = SCSI_STATE_END_PHASE; + break; + + default: + fatal("READ_MESSAGE - unknown message %02x\n", msg); + } + break; + } + } + break; + + default: + fatal("Unknown SCSI_state %d\n", scsi->scsi_state); + } +} + +static void aha154x_callback(void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + + timer_advance_u64(&scsi->timer, TIMER_USEC * POLL_TIME_US); + +// pclog("poll %i\n", scsi->cmd_state); + process_cmd(scsi); + process_ccb(scsi); + process_scsi(scsi); +} + +static uint8_t aha1542c_read(uint32_t addr, void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + uint8_t temp = 0xff; + + addr &= 0x3fff; + + + if (addr == 0x3f7e) /*DIP switches*/ + temp = scsi->dipsw; + else if (addr == 0x3f7f) /*Negation of DIP switches, to satisfy BIOS checksum!*/ + temp = (scsi->dipsw ^ 0xff) + 1; + else if (addr >= 0x3f80 && (scsi->shadow & 2)) + temp = scsi->shadow_ram[addr]; + else + temp = scsi->bios_rom.rom[addr | scsi->bios_bank]; + + return temp; +} +static void aha1542c_write(uint32_t addr, uint8_t val, void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + + addr &= 0x3fff; + + if (addr >= 0x3f80 && (scsi->shadow & 1)) + scsi->shadow_ram[addr] = val; +} + +static void aha1542c_eeprom_load(aha154x_t *scsi, char *fn) +{ + FILE *f; + + strcpy(scsi->fn, fn); + f = nvrfopen(scsi->fn, "rb"); + if (!f) + { + memset(scsi->eeprom, 0, 35); + return; + } + fread(scsi->eeprom, 1, 32, f); + fclose(f); +} + +static void aha1542c_eeprom_save(aha154x_t *scsi) +{ + FILE *f = nvrfopen(scsi->fn, "wb"); + + if (!f) + return; + fwrite(scsi->eeprom, 1, 32, f); + fclose(f); +} + +static uint16_t port_sw_mapping[8] = +{ + 0x330, 0x334, 0x230, 0x234, 0x130, 0x134, -1, -1 +}; + +static void *scsi_aha1542c_init(char *bios_fn) +{ + aha154x_t *scsi = malloc(sizeof(aha154x_t)); + uint32_t addr; + int c; + memset(scsi, 0, sizeof(aha154x_t)); + + rom_init(&scsi->bios_rom, "adaptec_aha1542c_bios_534201-00.bin", 0xd8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&scsi->bios_rom.mapping); + + addr = device_get_config_int("bios_addr"); + mem_mapping_add(&scsi->mapping, addr, 0x4000, + aha1542c_read, NULL, NULL, + aha1542c_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + + scsi->status = 0; + scsi->cmd_state = CMD_STATE_IDLE; + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + + timer_add(&scsi->timer, aha154x_callback, scsi, 1); + + addr = device_get_config_int("addr"); + io_sethandler(addr, 0x0004, + aha154x_in, NULL, NULL, + aha154x_out, NULL, NULL, + scsi); + for (c = 0; c < 8; c++) + { + if (port_sw_mapping[c] == addr) + { + scsi->dipsw = c; + break; + } + } + + scsi_bus_init(&scsi->bus); + + scsi->type = SCSI_AHA1542C; + + aha1542c_eeprom_load(scsi, "aha1542c.nvr"); + + scsi->host_id = scsi->eeprom[0] & 7; + scsi->dma = (scsi->eeprom[1] >> 4) & 7; + scsi->irq = (scsi->eeprom[1] & 7) + 9; + pclog("Init IRQ=%i DMA=%i ID=%i\n", scsi->irq, scsi->dma, scsi->host_id); + + return scsi; +} + +static void *scsi_bt545s_init(char *bios_fn) +{ + aha154x_t *scsi = malloc(sizeof(aha154x_t)); + uint32_t addr; + memset(scsi, 0, sizeof(aha154x_t)); + + addr = device_get_config_int("bios_addr"); + rom_init(&scsi->bios_rom, "BusLogic_BT-545S_U15_27128_5002026-4.50.bin", addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + scsi->bios_addr = addr; + + scsi->status = 0; + scsi->cmd_state = CMD_STATE_IDLE; + scsi->ccb_state = CCB_STATE_IDLE; + scsi->scsi_state = SCSI_STATE_IDLE; + + timer_add(&scsi->timer, aha154x_callback, scsi, 1); + + addr = device_get_config_int("addr"); + io_sethandler(addr, 0x0004, + aha154x_in, NULL, NULL, + aha154x_out, NULL, NULL, + scsi); + + scsi_bus_init(&scsi->bus); + + scsi->type = SCSI_BT545S; + + scsi->host_id = device_get_config_int("host_id"); + scsi->dma = device_get_config_int("dma"); + scsi->irq = device_get_config_int("irq"); + + return scsi; +} + +static void scsi_aha1542c_close(void *p) +{ + aha154x_t *scsi = (aha154x_t *)p; + + scsi_bus_close(&scsi->bus); + + free(scsi); +} + +static int scsi_aha1542c_available() +{ + return rom_present("adaptec_aha1542c_bios_534201-00.bin"); +} + +static int scsi_bt545s_available() +{ + return rom_present("BusLogic_BT-545S_U15_27128_5002026-4.50.bin"); +} + +static device_config_t aha1542c_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "130", + .value = 0x130 + }, + { + .description = "134", + .value = 0x134 + }, + { + .description = "230", + .value = 0x230 + }, + { + .description = "234", + .value = 0x234 + }, + { + .description = "330", + .value = 0x330 + }, + { + .description = "334", + .value = 0x334 + }, + { + .description = "" + } + }, + .default_int = 0x334 + }, + { + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "C8000", + .value = 0xc8000 + }, + { + .description = "CC000", + .value = 0xcc000 + }, + { + .description = "D0000", + .value = 0xd0000 + }, + { + .description = "D4000", + .value = 0xd4000 + }, + { + .description = "D8000", + .value = 0xd8000 + }, + { + .description = "DC000", + .value = 0xdc000 + }, + { + .description = "" + } + }, + .default_int = 0xdc000 + }, + { + .type = -1 + } +}; + +static device_config_t bt545s_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "130", + .value = 0x130 + }, + { + .description = "134", + .value = 0x134 + }, + { + .description = "230", + .value = 0x230 + }, + { + .description = "234", + .value = 0x234 + }, + { + .description = "330", + .value = 0x330 + }, + { + .description = "334", + .value = 0x334 + }, + { + .description = "" + } + }, + .default_int = 0x334 + }, + { + .name = "bios_addr", + .description = "BIOS address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "C8000", + .value = 0xc8000 + }, + { + .description = "D8000", + .value = 0xd8000 + }, + { + .description = "DC000", + .value = 0xdc000 + }, + { + .description = "" + } + }, + .default_int = 0xdc000 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 9", + .value = 9 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "IRQ 11", + .value = 11 + }, + { + .description = "IRQ 12", + .value = 12 + }, + { + .description = "IRQ 14", + .value = 14 + }, + { + .description = "IRQ 15", + .value = 15 + }, + { + .description = "" + } + }, + .default_int = 10 + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DMA 5", + .value = 5 + }, + { + .description = "DMA 6", + .value = 6 + }, + { + .description = "DMA 7", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .name = "host_id", + .description = "Host ID", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "ID 0", + .value = 0 + }, + { + .description = "ID 1", + .value = 1 + }, + { + .description = "ID 2", + .value = 2 + }, + { + .description = "ID 3", + .value = 3 + }, + { + .description = "ID 4", + .value = 4 + }, + { + .description = "ID 5", + .value = 5 + }, + { + .description = "ID 6", + .value = 6 + }, + { + .description = "ID 7", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .type = -1 + } +}; + +device_t scsi_aha1542c_device = +{ + "Adaptec AHA-1542C (SCSI)", + DEVICE_AT, + scsi_aha1542c_init, + scsi_aha1542c_close, + scsi_aha1542c_available, + NULL, + NULL, + NULL, + aha1542c_config +}; +device_t scsi_bt545s_device = +{ + "BusLogic BT-545S (SCSI)", + DEVICE_AT, + scsi_bt545s_init, + scsi_aha1542c_close, + scsi_bt545s_available, + NULL, + NULL, + NULL, + bt545s_config +}; diff --git a/src/scsi_aha1540.h b/src/scsi_aha1540.h new file mode 100644 index 0000000..d4db67d --- /dev/null +++ b/src/scsi_aha1540.h @@ -0,0 +1,2 @@ +extern device_t scsi_aha1542c_device; +extern device_t scsi_bt545s_device; diff --git a/src/scsi_cd.c b/src/scsi_cd.c new file mode 100644 index 0000000..5a56550 --- /dev/null +++ b/src/scsi_cd.c @@ -0,0 +1,1716 @@ +#include +#include +#include +#include +#include "ibm.h" +#include "ide.h" +#include "ide_atapi.h" +#include "scsi.h" +#include "scsi_cd.h" +#include "timer.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define BUFFER_SIZE (256*1024) + +#define MAX_NR_SECTORS 16 + +enum +{ + CMD_POS_IDLE = 0, + CMD_POS_WAIT, + CMD_POS_START_SECTOR, + CMD_POS_TRANSFER, + CMD_POS_COMPLETE +}; + +/* 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_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_SEND_DVD_STRUCTURE 0xad +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe + +/* 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 + +#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 + +/* 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 + +/* Table of all ATAPI commands and their flags, needed for the new disc change / not ready handler. */ +static uint8_t atapi_cmd_table[0x100] = +{ + [GPCMD_TEST_UNIT_READY] = CHECK_READY, + [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, + [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, + [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 + +static 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 +}; + +uint8_t mode_pages_in[256][256]; +#define PAGE_CHANGEABLE 1 +#define PAGE_CHANGED 2 +static 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, +}; + +extern int cd_status; + +typedef struct scsi_cd_data_t +{ + uint8_t data_in[BUFFER_SIZE]; + uint8_t data_out[BUFFER_SIZE]; + + int blocks; + + int cmd_pos, new_cmd_pos; + pc_timer_t callback_timer; + int wait_time; + scsi_bus_t *bus; + + int addr, len; + int sector_pos; + + uint8_t buf[512]; + + uint8_t status; + + int data_pos_read, data_pos_write; + int data_bytes_read, bytes_expected; + + int cdlen, cdpos; + + int bytes_received, bytes_required; + + + int sense_key, asc, ascq; + + int id; + + + int received_cdb; + uint8_t cdb[CDB_MAX_LEN]; + + int prev_status; + int cd_status; + + uint8_t prefix_len; + uint8_t page_current; + + int is_atapi; + atapi_device_t *atapi_dev; + + int pio_mode, mdma_mode; + + int short_seek, long_seek; + int max_speed, cur_speed; + + int cur_model; +} scsi_cd_data_t; + +static scsi_cd_data_t *cd_data = NULL; + +/*Note - all transfer speeds currently assume CAV behaviour. Drives above about 8x + should use CLV instead, but this is not currently supported.*/ +static struct +{ + int speed; + int short_seek; + int long_seek; +} cd_speeds[] = +{ + {1, 240, 1446}, + {2, 160, 1000}, + {3, 150, 900}, + {4, 112, 675}, + {6, 112, 675}, + {8, 112, 675}, + {12, 75, 400}, + {16, 58, 350}, + {20, 50, 300}, + {24, 45, 270}, + {32, 45, 270}, + {40, 50, 300}, + {44, 50, 300}, + {48, 50, 300}, + {52, 45, 270}, + {56, 45, 270}, + {72, 45, 270}, +}; + +int cd_speed; + +int cd_get_speed(int i) +{ + return cd_speeds[i].speed; +} + +void cd_set_speed(int speed) +{ + if (cd_data) + { + int c = 0; + + while (1) + { + if (cd_speeds[c].speed == speed) + break; + if (cd_speeds[c].speed >= MAX_CD_SPEED) + break; + + c++; + } + + cd_data->max_speed = speed; + cd_data->cur_speed = speed; + cd_data->short_seek = cd_speeds[c].short_seek; + cd_data->long_seek = cd_speeds[c].long_seek; + } +} + +static struct +{ + // suffix numbers are sizes from the specs + char *vendor_8; + char *model_and_firmware_40; + char *serial_20; + char *model_16; + char *firmware_4; + + char *serial2_20; + char *firmware2_8; + char *model2_40; + + // for PCem config only + char *model_string_40; + char *model_config_string_40; + int interfaces; + int speed; // Not an index, but a "speed" value. -1 == allow override +} const cd_models[] = +{ + { + // Generic PCem CD + "PCem", + "PCemCD v1.0", + "53R141", + "PCemCD", + "1.0", + + "", + "v1.0", + "PCemCD", + "PCemCD", + "pcemcd", + CD_MODEL_INTERFACE_ALL, + -1, + }, + { + // A 4x CD-ROM drive from Aztech. Choose if your system image has the SGIDECD.SYS driver + "AZT", + "AZT 46802I v1.15", + "53R141", // TODO: clone serial from my real one + "46802I", + "1.15", + + "", + "v1.15", + "CDA46802I", + "AZT CDA 468-02I 4X", + "azt_cda_468_02i_4x", + CD_MODEL_INTERFACE_IDE, + 4, + }, +}; + +char *cd_model = NULL; + +char *cd_get_model(int i) +{ + return cd_models[i].model_string_40; +} + +char *cd_get_config_model(int i) +{ + return cd_models[i].model_config_string_40; +} + +void cd_set_model(char *model) +{ + if (cd_data) + { + int c = 0; + + while (1) + { + if (!model) + break; + if (c > MAX_CD_MODEL) + break; + if (!strncmp(cd_models[c].model_string_40, model, 40)) + break; + + c++; + } + + cd_data->cur_model = c; + } +} + +int cd_get_model_interfaces(int i) +{ + return cd_models[i].interfaces; +} + +int cd_get_model_speed(int i) +{ + return cd_models[i].speed; +} + +char *cd_model_to_config(char *model) +{ + int c = 0; + + while (1) + { + if (!model) + break; + if (c > MAX_CD_MODEL) + { + c = 0; // default + break; + } + if (!strncmp(cd_models[c].model_string_40, model, 40)) + break; + + c++; + } + return cd_models[c].model_config_string_40; +} + +char *cd_model_from_config(char *config) +{ + int c = 0; + + while (1) + { + if (!config) + break; + if (c > MAX_CD_MODEL) + { + c = 0; // default + break; + } + if (!strncmp(cd_models[c].model_config_string_40, config, 40)) + break; + + c++; + } + return cd_models[c].model_string_40; +} + +static void scsi_cd_callback(void *p) +{ + scsi_cd_data_t *data = p; + + if (data->cmd_pos == CMD_POS_WAIT) + { + data->wait_time--; + if (!data->wait_time) + { + data->cmd_pos = data->new_cmd_pos; + scsi_bus_kick(data->bus); + } + else + timer_advance_u64(&data->callback_timer, 1000 * TIMER_USEC); + } +} + +//#define SECTOR_TIME 13333 /*Time between sectors on 1x drive*/ +#define SECTOR_TIME 12000 /*Adjusted from above value to account for transfer time on current SCSI/ATAPI code*/ + +/*The seek model is currently very basic. Seeks of less than MIN_SEEK sectors are treated as + immediate. Seeks between MIN_SEEK and MAX_SEEK sectors scale linearly between short_seek and + long seek. + + This really shouldn't be a linear scale, but this is a good enough approximation for now.*/ +#define MIN_SEEK 2000 +#define MAX_SEEK 333000 + +static int get_seek_time(scsi_cd_data_t *data, uint32_t start, uint32_t dest) +{ + uint32_t diff = ABS((int)(start - dest)); + + if (diff < MIN_SEEK) + return 0; + if (diff > MAX_SEEK) + diff = MAX_SEEK; + + diff -= MIN_SEEK; + + return data->short_seek + ((data->long_seek * diff) / (MAX_SEEK - MIN_SEEK)); +} + +static void scsi_add_data(scsi_cd_data_t *data, uint8_t val) +{ + data->data_in[data->data_pos_write++] = val; + data->bytes_expected++; +} + +static void atapi_cmd_error(scsi_cd_data_t *data, int sensekey, int asc, int ascq) +{ + data->status = STATUS_CHECK_CONDITION; + data->sense_key = sensekey; + data->asc = asc; + data->ascq = ascq; +} + +static void atapi_sense_clear(scsi_cd_data_t *data, int command, int ignore_ua) +{ + if ((data->sense_key == SENSE_UNIT_ATTENTION) || ignore_ua) + { + data->sense_key = 0; + data->asc = 0; + data->ascq = 0; + } +} + +static int atapi_event_status(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 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] = ' '; + } + } +} + +static void *scsi_cd_init(scsi_bus_t *bus, int id) +{ + scsi_cd_data_t *data = malloc(sizeof(scsi_cd_data_t)); + memset(data, 0, sizeof(scsi_cd_data_t)); + + data->bus = bus; + data->id = id; + + 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. */ + page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; + + timer_add(&data->callback_timer, scsi_cd_callback, data, 0); + + cd_data = data; + cd_set_speed(cd_speed); + cd_set_model(cd_model); + + return data; +} + +static void *scsi_cd_atapi_init(scsi_bus_t *bus, int id, atapi_device_t *atapi_dev) +{ + scsi_cd_data_t *data = scsi_cd_init(bus, id); + + data->is_atapi = 1; + data->atapi_dev = atapi_dev; + + return data; +} + +static void scsi_cd_close(void *p) +{ + scsi_cd_data_t *data = p; + + cd_data = NULL; + free(data); +} + +static void scsi_cd_reset(void *p) +{ + scsi_cd_data_t *data = p; + + timer_disable(&data->callback_timer); + data->cmd_pos = CMD_POS_IDLE; +} + +static void scsi_cd_illegal(scsi_cd_data_t *data) +{ + atapi_cmd_error(data, KEY_ILLEGAL_REQ, ASC_INVALID_LUN, 0); +} + +/** + * 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(scsi_cd_data_t *data, uint32_t pos, uint8_t type) +{ + uint8_t *buf = (uint8_t *)data->data_in; +// 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++] = 5; /* Reserved */ + buf[pos++] = 4; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0x80; /* 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++] = 0x03; /* Some other stuff not supported */ + buf[pos++] = (uint8_t) ((data->max_speed * 176) >> 8); + buf[pos++] = (uint8_t) (data->max_speed * 176); /* Maximum speed */ + buf[pos++] = 1; buf[pos++] = 0; /* Number of audio levels - on and off only */ + buf[pos++] = 0; buf[pos++] = 0; /* Buffer size - none */ + buf[pos++] = (uint8_t) ((data->cur_speed * 176) >> 8); + buf[pos++] = (uint8_t) (data->cur_speed * 176); /* Current speed */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Drive digital format */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + return pos; +} + +static void cdrom_mode_select(scsi_cd_data_t *data, int data_len) +{ + int len = data->data_out[1] | (data->data_out[0] << 8); + int pos = 8 + len; /*Skip over mode parameter header*/ + + while (pos < data_len) + { + int page_code = data->data_out[pos] & 0x3f; + len = data->data_out[pos+1]; + + pos += 2; + + switch (page_code) + { + case GPMODE_CDROM_AUDIO_PAGE: + if (len != 0xe) + { + atapi_cmd_error(data, KEY_ILLEGAL_REQ, ASC_INV_FIELD_IN_CMD_PACKET, 0); + return; + } + memcpy(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], &data->data_out[pos], 0xe); + page_flags[GPMODE_CDROM_AUDIO_PAGE] |= PAGE_CHANGED; + pos += len; + break; + + case GPMODE_R_W_ERROR_PAGE: + if (len != 0x6) + { + atapi_cmd_error(data, KEY_ILLEGAL_REQ, ASC_INV_FIELD_IN_CMD_PACKET, 0); + return; + } + pos += len; + break; + + case GPMODE_CDROM_PAGE: + if (len != 0x6) + { + atapi_cmd_error(data, KEY_ILLEGAL_REQ, ASC_INV_FIELD_IN_CMD_PACKET, 0); + return; + } + pos += len; + break; + + case GPMODE_CAPABILITIES_PAGE: + if (len != 0x12) + { + atapi_cmd_error(data, KEY_ILLEGAL_REQ, ASC_INV_FIELD_IN_CMD_PACKET, 0); + return; + } + pos += len; + break; + + default: + atapi_cmd_error(data, KEY_ILLEGAL_REQ, ASC_INV_FIELD_IN_CMD_PACKET, 0); + return; + } + } +} + +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 ? 9 : 7] : 0xFF; +} +static int scsi_cd_command(uint8_t *cdb, void *p) +{ + scsi_cd_data_t *data = p; + 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; + int changed; + + if (!data->received_cdb) + memcpy(data->cdb, cdb, CDB_MAX_LEN); + + if ((cdb[0] != SCSI_REQUEST_SENSE/* && cdb[0] != SCSI_INQUIRY*/) && (cdb[1] & 0xe0)) + { + pclog("non-zero LUN\n"); + /*Non-zero LUN - abort command*/ + scsi_cd_illegal(data); + return BUS_CD | BUS_IO; + } + + pclog("New CD command %02X %i\n", cdb[0], ins); + msf = cdb[1] & 2; + + is_error = 0; + changed = atapi->medium_changed(); + + /*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[cdb[0]] & ALLOW_UA) && data->sense_key == SENSE_UNIT_ATTENTION) + { +// fatal("atapi_cmd_error(ide, data->sense_key, data->asc);\n"); + 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 ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[0] != GPCMD_TEST_UNIT_READY)) + { + /* GPCMD_TEST_UNIT_READY is NOT supposed to clear sense! */ + atapi_sense_clear(data, cdb[0], 1); + } + + /*If our state has been set to errored, clear it, and return.*/ + if (is_error) + { +// fatal("Clear error state\n"); + is_error = 0; + return SCSI_PHASE_STATUS; + } + + if ((atapi_cmd_table[cdb[0]] & CHECK_READY) && !atapi->ready()) + { + atapi_cmd_error(data, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); + return SCSI_PHASE_STATUS; + } + if ((atapi_cmd_table[cdb[0]] & CHECK_READY) && changed) + { + pclog("Medium changed\n"); + atapi_cmd_error(data, SENSE_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + return SCSI_PHASE_STATUS; + } + + data->prev_status = data->cd_status; + data->cd_status = atapi->status(); + if (((data->prev_status == CD_STATUS_PLAYING) || (data->prev_status == CD_STATUS_PAUSED)) && ((data->cd_status != CD_STATUS_PLAYING) && (data->cd_status != CD_STATUS_PAUSED))) + completed = 1; + else + completed = 0; + +// pclog(" msf %i completed %i\n", msf, completed); + + data->status = STATUS_GOOD; + + switch (cdb[0]) + { + case GPCMD_TEST_UNIT_READY: + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case SCSI_REZERO_UNIT: + if (data->cmd_pos == CMD_POS_IDLE) + { + uint32_t old_pos = data->cdpos; + int seek_time; + + data->cdpos = 0; + + seek_time = get_seek_time(data, old_pos, data->cdpos); + if (seek_time) + { + data->cmd_pos = CMD_POS_WAIT; + data->new_cmd_pos = CMD_POS_COMPLETE; + data->wait_time = seek_time; + timer_set_delay_u64(&data->callback_timer, 1000 * TIMER_USEC); + return SCSI_PHASE_COMMAND; + } + } + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case SCSI_REQUEST_SENSE: /* Used by ROS 4+ */ +// pclog("CD REQ SENSE\n"); + alloc_length = cdb[4]; + temp_command = cdb[0]; + //atapi_command_send_init(ide, temp_command, 18, alloc_length); + + /*Will return 18 bytes of 0*/ + memset(data->data_in, 0, 512); + + data->data_in[0] = 0x80 | 0x70; + + if ((data->sense_key > 0) || (data->cd_status < CD_STATUS_PLAYING)) + { + if (completed) + { +// pclog("completed\n"); + data->data_in[2] = SENSE_ILLEGAL_REQUEST; + data->data_in[12] = ASC_AUDIO_PLAY_OPERATION; + data->data_in[13] = ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } + else + { +// pclog("!completed %02x %02x %02x\n", data->sense_key, data->asc, data->ascq); + data->data_in[2] = data->sense_key; + data->data_in[12] = data->asc; + data->data_in[13] = data->ascq; + } + } + else + { + data->data_in[2] = SENSE_ILLEGAL_REQUEST; + data->data_in[12] = ASC_AUDIO_PLAY_OPERATION; + data->data_in[13] = (data->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } + + data->data_in[7] = 0; + + /* Clear the sense stuff as per the spec. */ + atapi_sense_clear(data, temp_command, 0); + + data->bytes_expected = data->data_pos_write = MIN(alloc_length, 18); + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + case SCSI_SEEK_6: + if (data->cmd_pos == CMD_POS_IDLE) + { + uint32_t old_pos = data->cdpos; + int seek_time; + + data->cdpos = (((uint32_t)cdb[1] & 0x1f) << 16) | ((uint32_t)cdb[2] << 8) | (uint32_t)cdb[3]; + + seek_time = get_seek_time(data, old_pos, data->cdpos); + if (seek_time) + { + data->cmd_pos = CMD_POS_WAIT; + data->new_cmd_pos = CMD_POS_COMPLETE; + data->wait_time = seek_time; + timer_set_delay_u64(&data->callback_timer, 1000 * TIMER_USEC); + return SCSI_PHASE_COMMAND; + } + } + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case GPCMD_SET_SPEED: + data->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; + if (data->cur_speed < 1) + data->cur_speed = 1; + else if (data->cur_speed > data->max_speed) + data->cur_speed = data->max_speed; + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case GPCMD_MECHANISM_STATUS: /*0xbd*/ + alloc_length = (cdb[7]<<16) | (cdb[8]<<8) | cdb[9]; + + if (alloc_length == 0) + fatal("Zero allocation length to MECHANISM STATUS not impl.\n"); + + data->data_in[0] = 0; + data->data_in[1] = 0; + data->data_in[2] = 0; + data->data_in[3] = 0; + data->data_in[4] = 0; + data->data_in[5] = 1; + data->data_in[6] = 0; + data->data_in[7] = 0; + // len = 8; + + data->data_pos_read = 0; + data->bytes_expected = data->data_pos_write = MIN(alloc_length, 8); + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + case GPCMD_READ_TOC_PMA_ATIP: +// pclog("Read TOC ready? %08X\n",ide); + toc_format = cdb[2] & 0xf; + if (toc_format == 0) + toc_format = (cdb[9] >> 6) & 3; + alloc_length = cdb[8] + (cdb[7] << 8); + switch (toc_format) + { + case 0: /*Normal*/ +// pclog("ATAPI: READ TOC type requested: Normal\n"); + len = atapi->readtoc(data->data_in, cdb[6], msf, alloc_length, 0); + break; + case 1: /*Multi session*/ +// pclog("ATAPI: READ TOC type requested: Multi-session\n"); + len = atapi->readtoc_session(data->data_in, msf, alloc_length); + data->data_in[0] = 0; + data->data_in[1] = 0xA; + break; + case 2: /*Raw*/ +// pclog("ATAPI: READ TOC type requested: Raw TOC\n"); + len = atapi->readtoc_raw(data->data_in, alloc_length); + break; + default: + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_LBA_OUT_OF_RANGE, 0); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + } + data->data_pos_read = 0; + data->bytes_expected = data->data_pos_write = MIN(alloc_length, len); + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + case GPCMD_READ_CD: +// pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",cdb[2],cdb[3],cdb[4],cdb[5],cdb[6],cdb[7],cdb[8],cdb[9]); + rcdmode = cdb[9] & 0xF8; + if ((rcdmode != 0x10) && (rcdmode != 0xF8)) + { + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + } + + if (data->cmd_pos == CMD_POS_IDLE) + { + uint32_t old_pos = data->cdpos; + int seek_time; + + data->cdlen = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + data->cdpos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + data->cmd_pos = CMD_POS_START_SECTOR; + data->bytes_expected = data->cdlen * ((rcdmode == 0x10) ? 2048 : 2352); + if (data->is_atapi) + { + if (rcdmode == 0x10) + atapi_set_transfer_granularity(data->atapi_dev, 2048); + else + atapi_set_transfer_granularity(data->atapi_dev, 2352); + } + + seek_time = get_seek_time(data, old_pos, data->cdpos); + if (seek_time) + { + data->cmd_pos = CMD_POS_WAIT; + data->new_cmd_pos = CMD_POS_START_SECTOR; + data->wait_time = seek_time; + timer_set_delay_u64(&data->callback_timer, 1000 * TIMER_USEC); + return SCSI_PHASE_COMMAND; + } + } + if (data->cmd_pos == CMD_POS_WAIT) + return SCSI_PHASE_COMMAND; + if (!data->cdlen) + { + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + } + if (data->cmd_pos == CMD_POS_START_SECTOR) + { + uint64_t time = (((uint64_t)SECTOR_TIME * TIMER_USEC) / data->cur_speed) * (uint64_t)data->cdlen; + + data->cmd_pos = CMD_POS_WAIT; + data->new_cmd_pos = CMD_POS_TRANSFER; + + if (time > (TIMER_USEC * 1000ull)) + { + data->wait_time = (int)(time / (TIMER_USEC * 1000ull)); + timer_set_delay_u64(&data->callback_timer, time % (TIMER_USEC * 1000ull)); + } + else + { + timer_set_delay_u64(&data->callback_timer, time); + data->wait_time = 1; + } + return SCSI_PHASE_COMMAND; + } + + if (rcdmode == 0x10) + { + c = MIN(data->cdlen, MAX_NR_SECTORS); + if (atapi->readsector(data->data_in, data->cdpos, c)) + { +// pclog("Read sector failed\n"); + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_LBA_OUT_OF_RANGE, 0); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + } + data->cdpos += c; + data->cdlen -= c; + } + else + { + for (c = 0; c < MAX_NR_SECTORS; c++) + { + atapi->readsector_raw(&data->data_in[c*2352], data->cdpos); + + data->cdpos++; + data->cdlen--; + if (!data->cdlen) + { + c++; + break; + } + } + } + readflash_set(READFLASH_HDC, data->id); + + data->data_pos_read = 0; + data->data_pos_write = c * ((rcdmode == 0x10) ? 2048 : 2352); + return SCSI_PHASE_DATA_IN; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: +// pclog("Read: cmd_pos=%i cdlen=%i %p\n", data->cmd_pos, data->cdlen, &data->data_in[0]); + +// readcdmode = 0; + if (data->cmd_pos == CMD_POS_IDLE) + { + uint32_t old_pos = data->cdpos; + int seek_time; + + if (cdb[0] == GPCMD_READ_6) + { + data->cdlen = cdb[4]; + data->cdpos = (((uint32_t)cdb[1] & 0x1f) << 16) | ((uint32_t)cdb[2] << 8) | (uint32_t)cdb[3]; + } + else if (cdb[0] == GPCMD_READ_10) + { + data->cdlen = (cdb[7] << 8) | cdb[8]; + data->cdpos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + } + else + { + data->cdlen = ((uint32_t)cdb[6] << 24) | ((uint32_t)cdb[7] << 16) | ((uint32_t)cdb[8] << 8) | (uint32_t)cdb[9]; + data->cdpos = ((uint32_t)cdb[2] << 24) | ((uint32_t)cdb[3] << 16) | ((uint32_t)cdb[4] << 8) | (uint32_t)cdb[5]; + } +// pclog("cdpos=%08x cdlen=%08x\n", data->cdpos, data->cdlen); + + data->cmd_pos = CMD_POS_START_SECTOR; + data->bytes_expected = data->cdlen * 2048; + if (data->is_atapi) + atapi_set_transfer_granularity(data->atapi_dev, 2048); + + seek_time = get_seek_time(data, old_pos, data->cdpos); + + if (seek_time) + { + data->cmd_pos = CMD_POS_WAIT; + data->new_cmd_pos = CMD_POS_START_SECTOR; + data->wait_time = seek_time; + timer_set_delay_u64(&data->callback_timer, 1000 * TIMER_USEC); + return SCSI_PHASE_COMMAND; + } + } + if (data->cmd_pos == CMD_POS_WAIT) + return SCSI_PHASE_COMMAND; + if (!data->cdlen) + { + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + } + if (data->cmd_pos == CMD_POS_START_SECTOR) + { + uint64_t time = (((uint64_t)SECTOR_TIME * TIMER_USEC) / data->cur_speed) * (uint64_t)data->cdlen; + + data->cmd_pos = CMD_POS_WAIT; + data->new_cmd_pos = CMD_POS_TRANSFER; + + if (time > (TIMER_USEC * 1000ull)) + { + data->wait_time = (int)(time / (TIMER_USEC * 1000ull)); + timer_set_delay_u64(&data->callback_timer, time % (TIMER_USEC * 1000ull)); + } + else + { + timer_set_delay_u64(&data->callback_timer, time); + data->wait_time = 1; + } + return SCSI_PHASE_COMMAND; + } + + readflash_set(READFLASH_HDC, data->id); + c = MIN(data->cdlen, MAX_NR_SECTORS); + if (atapi->readsector(data->data_in, data->cdpos, c)) + { +// pclog("Read sector failed\n"); + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_LBA_OUT_OF_RANGE, 0); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + } + data->cdpos += c; + data->cdlen -= c; + + data->data_pos_read = 0; + data->data_pos_write = c * 2048; + return SCSI_PHASE_DATA_IN; + + case GPCMD_READ_HEADER: + alloc_length = cdb[8] | (cdb[7] << 8); + if (msf) + { + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + return SCSI_PHASE_STATUS; + } + for (c = 0; c < 4; c++) + data->data_in[c+4] = cdb[c+2]; + data->data_in[0] = 1; /*2048 bytes user data*/ + data->data_in[1] = data->data_in[2] = data->data_in[3] = 0; + + data->bytes_expected = data->data_pos_write = MIN(6, alloc_length); + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + temp_command = cdb[0]; + + if (temp_command == GPCMD_MODE_SENSE_6) + len = cdb[4]; + else + len = cdb[8] | (cdb[7] << 8); + + c = cdb[2] & 0x3F; + + memset(data->data_in, 0, len); + alloc_length = len; + // for (c=0;cdata_in[0] = len - 1; + data->data_in[1] = 3; /*120mm data CD-ROM*/ + } + else + { + len = ide_atapi_mode_sense(data, 8, c); + data->data_in[0] = (len - 2)>>8; + data->data_in[1] = (len - 2)&255; + data->data_in[2] = 3; /*120mm data CD-ROM*/ + } + + data->bytes_expected = data->data_pos_write = MIN(len, alloc_length); + data->cmd_pos = CMD_POS_IDLE; + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (data->cmd_pos == CMD_POS_IDLE) + { + int len; + + if (cdb[0] == GPCMD_MODE_SELECT_6) + { + len = cdb[4]; + data->prefix_len = 6; + } + else + { + len = (cdb[7]<<8) | cdb[8]; + data->prefix_len = 10; + } + + data->cmd_pos = CMD_POS_TRANSFER; + data->bytes_required = len; + return SCSI_PHASE_DATA_OUT; + } + if (data->bytes_received == data->bytes_required) + { + cdrom_mode_select(data, data->bytes_required); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + } + return SCSI_PHASE_DATA_OUT; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: /*0x4a*/ + temp_command = cdb[0]; + alloc_length = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + { + struct __attribute__((__packed__)) + { + 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 __attribute__((__packed__)) + { + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; + } *gesn_event_header; + unsigned int used_len; + + gesn_cdb = (void *)cdb; + gesn_event_header = (void *)data->data_in; + + /* It is fine by the MMC spec to not support async mode operations */ + if (!(gesn_cdb->polled & 0x01)) + { /* asynchronous mode */ + /* Only polling is supported, asynchronous mode is not. */ + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + return SCSI_PHASE_STATUS; + } + + /* 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(data->data_in); + } + else + { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + len = used_len; + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + } + + data->bytes_expected = data->data_pos_write = MIN(alloc_length, len); + data->cmd_pos = CMD_POS_IDLE; + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + case GPCMD_READ_DISC_INFORMATION: + alloc_length = cdb[8] | (cdb[7] << 8); + + data->data_in[1] = 32; + data->data_in[2] = 0xe; /* last session complete, disc finalized */ + data->data_in[3] = 1; /* first track on disc */ + data->data_in[4] = 1; /* # of sessions */ + data->data_in[5] = 1; /* first track of last session */ + data->data_in[6] = 1; /* last track of last session */ + data->data_in[7] = 0x20; /* unrestricted use */ + data->data_in[8] = 0x00; /* CD-ROM */ + + data->bytes_expected = data->data_pos_write = MIN(alloc_length, 34); + data->cmd_pos = CMD_POS_IDLE; + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + 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 (cdb[0] == GPCMD_PLAY_AUDIO_10) + { + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + } + else if (cdb[0] == GPCMD_PLAY_AUDIO_MSF) + { + pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + } + else + { + pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + } + + + if ((cdrom_drive < 1) || (data->cd_status <= CD_STATUS_DATA_ONLY) || + !atapi->is_track_audio(pos, (cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) + { + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_MODE_FOR_THIS_TRACK, 0); + return SCSI_PHASE_STATUS; + } + + atapi->playaudio(pos, len, (cdb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case GPCMD_READ_SUBCHANNEL: + alloc_length = cdb[8] | (cdb[7] << 8); + if (cdb[3] != 1) + { + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + return SCSI_PHASE_STATUS; + } + pos = 0; + data->data_in[pos++] = 0; + data->data_in[pos++] = 0; /*Audio status*/ + data->data_in[pos++] = 0; data->data_in[pos++] = 0; /*Subchannel length*/ + data->data_in[pos++] = 1; /*Format code*/ + data->data_in[1] = atapi->getcurrentsubchannel(&data->data_in[5], msf); +// pclog("Read subchannel complete - audio status %02X\n",idebufferb[1]); + len = 11+5; + if (!(cdb[2] & 0x40)) len=4; + + data->bytes_expected = data->data_pos_write = MIN(alloc_length, len); + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + case GPCMD_START_STOP_UNIT: + if (!cdb[4]) atapi->stop(); + else if (cdb[4] == 2) atapi->eject(); + else if (cdb[4] == 3) atapi->load(); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case GPCMD_INQUIRY: + page_code = cdb[2]; + max_len = cdb[4]; + alloc_length = max_len; + temp_command = cdb[0]; + + if (cdb[1] & 1) + { + preamble_len = 4; + size_idx = 3; + + data->data_in[idx++] = 05; + data->data_in[idx++] = page_code; + data->data_in[idx++] = 0; + + idx++; + + switch (page_code) + { + case 0x00: + data->data_in[idx++] = 0x00; + data->data_in[idx++] = 0x83; + break; + + case 0x83: + if (idx + 24 > max_len) + { + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR, 0); + return SCSI_PHASE_STATUS; + } + data->data_in[idx++] = 0x02; + data->data_in[idx++] = 0x00; + data->data_in[idx++] = 0x00; + data->data_in[idx++] = 20; + ide_padstr8(data->data_in + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > max_len) + { + goto atapi_out; + } + data->data_in[idx++] = 0x02; + data->data_in[idx++] = 0x01; + data->data_in[idx++] = 0x00; + data->data_in[idx++] = 68; + ide_padstr8(data->data_in + idx, 8, cd_models[cd_data->cur_model].vendor_8); /* Vendor */ + idx += 8; + ide_padstr8(data->data_in + idx, 40, cd_models[cd_data->cur_model].model_and_firmware_40); /* Product */ + idx += 40; + ide_padstr8(data->data_in + idx, 20, cd_models[cd_data->cur_model].serial_20); /* Product */ + idx += 20; + break; + + default: + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET, 0); + return SCSI_PHASE_STATUS; + } + } + else + { + preamble_len = 5; + size_idx = 4; + + data->data_in[0] = 5; /*CD-ROM*/ + data->data_in[1] = 0x80; /*Removable*/ + if (data->is_atapi) + { + data->data_in[2] = 0; /*Not ANSI compliant*/ + data->data_in[3] = 0x21; /*ATAPI compliant*/ + } + else + { + data->data_in[2] = 2; /*SCSI-2 compliant*/ + data->data_in[3] = 0x02; + } + data->data_in[4] = 31; + data->data_in[5] = 0; + data->data_in[6] = 0; + data->data_in[7] = 0; + + ide_padstr8(data->data_in + 8, 8, cd_models[cd_data->cur_model].vendor_8); /* Vendor */ + ide_padstr8(data->data_in + 16, 16, cd_models[cd_data->cur_model].model_16); /* Product */ + ide_padstr8(data->data_in + 32, 4, cd_models[cd_data->cur_model].firmware_4); /* Revision */ + + idx = 36; + } + +atapi_out: + data->data_in[size_idx] = idx - preamble_len; + + data->bytes_expected = data->data_pos_write = MIN(alloc_length, idx); + return alloc_length ? SCSI_PHASE_DATA_IN : SCSI_PHASE_STATUS; + + case GPCMD_PREVENT_REMOVAL: + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case GPCMD_PAUSE_RESUME: + if (cdb[8] & 1) atapi->resume(); + else atapi->pause(); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case GPCMD_SEEK: + if (data->cmd_pos == CMD_POS_IDLE) + { + uint32_t old_pos = data->cdpos; + int seek_time; + + data->cdpos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + atapi->seek(data->cdpos); + + seek_time = get_seek_time(data, old_pos, data->cdpos); + if (seek_time) + { + data->cmd_pos = CMD_POS_WAIT; + data->new_cmd_pos = CMD_POS_COMPLETE; + data->wait_time = seek_time; + timer_set_delay_u64(&data->callback_timer, 1000 * TIMER_USEC); + return SCSI_PHASE_COMMAND; + } + } + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case GPCMD_READ_CDROM_CAPACITY: + size = atapi->size(); + scsi_add_data(data, (size >> 24) & 0xff); + scsi_add_data(data, (size >> 16) & 0xff); + scsi_add_data(data, (size >> 8) & 0xff); + scsi_add_data(data, size & 0xff); + scsi_add_data(data, (2048 >> 24) & 0xff); + scsi_add_data(data, (2048 >> 16) & 0xff); + scsi_add_data(data, (2048 >> 8) & 0xff); + scsi_add_data(data, 2048 & 0xff); + pclog("READ_CDROM_CAPACITY %08x\n", size); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_DATA_IN; + + case GPCMD_STOP_PLAY_SCAN: + atapi->stop(); + data->cmd_pos = CMD_POS_IDLE; + return SCSI_PHASE_STATUS; + + case GPCMD_SEND_DVD_STRUCTURE: + default: + atapi_cmd_error(data, SENSE_ILLEGAL_REQUEST, ASC_ILLEGAL_OPCODE, 0); + return SCSI_PHASE_STATUS; + } +} + +static uint8_t scsi_cd_read(void *p) +{ + scsi_cd_data_t *data = p; + uint8_t temp; + + data->data_bytes_read++; + temp = data->data_in[data->data_pos_read++]; + + if (data->data_pos_read == data->data_pos_write && data->data_bytes_read < data->bytes_expected) + scsi_cd_command(data->cdb, data); + + return temp; +} + +static void scsi_cd_write(uint8_t val, void *p) +{ + scsi_cd_data_t *data = p; + + data->data_out[data->data_pos_write++] = val; + + data->bytes_received++; + + if (data->data_pos_write > BUFFER_SIZE) + fatal("Exceeded data_out buffer size\n"); +} + +static int scsi_cd_read_complete(void *p) +{ + scsi_cd_data_t *data = p; + + return (data->data_bytes_read == data->bytes_expected); +} +static int scsi_cd_write_complete(void *p) +{ + scsi_cd_data_t *data = p; + + return (data->bytes_received == data->bytes_required); +} + +static void scsi_cd_start_command(void *p) +{ + scsi_cd_data_t *data = p; + + data->bytes_received = 0; + data->bytes_required = 0; + data->data_pos_read = data->data_pos_write = 0; + data->data_bytes_read = data->bytes_expected = 0; + + data->received_cdb = 0; + + data->cmd_pos = CMD_POS_IDLE; + memset(data->data_in, 0, 256); +} + +static uint8_t scsi_cd_get_status(void *p) +{ + scsi_cd_data_t *data = p; + + return data->status; +} + +static uint8_t scsi_cd_get_sense_key(void *p) +{ + scsi_cd_data_t *data = p; + + return data->sense_key; +} + +static int scsi_cd_get_bytes_required(void *p) +{ + scsi_cd_data_t *data = p; + + return data->bytes_required - data->bytes_received; +} + +static void scsi_cd_atapi_identify(uint16_t *buffer, void *p) +{ + scsi_cd_data_t *data = p; + + memset(buffer, 0, 512); + + buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *)(buffer + 10), cd_models[cd_data->cur_model].serial2_20, 20); /* Serial Number */ + ide_padstr((char *)(buffer + 23), cd_models[cd_data->cur_model].firmware2_8, 8); /* Firmware */ + ide_padstr((char *)(buffer + 27), cd_models[cd_data->cur_model].model2_40, 40); /* Model */ + buffer[49] = 0x300; /*DMA and LBA supported*/ + buffer[51] = 120; + buffer[52] = 120; + buffer[53] = 2; /*Words 64-70 are valid*/ + buffer[62] = 0x0000; + buffer[63] = 0x0007 | (0x100 << data->mdma_mode); /*Multi-word DMA 0, 1 & 2*/ + buffer[64] = 0x0003; /*PIO Modes 3 & 4*/ + if (data->pio_mode >= 3) + buffer[64] |= (0x100 << (data->pio_mode - 3)); + buffer[65] = 120; /*Minimum multi-word cycle time*/ + buffer[66] = 120; /*Recommended multi-word cycle time*/ + buffer[67] = 120; /*Minimum PIO cycle time*/ + buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ +} + +static int scsi_cd_atapi_set_feature(uint8_t feature, uint8_t val, void *p) +{ + scsi_cd_data_t *data = p; + + switch (feature) + { + case FEATURE_SET_TRANSFER_MODE: + if (!(val & 0xfe)) + { + /*Default transfer mode*/ + data->pio_mode = 0; + return 1; + } + else if ((val & 0xf8) == 0x08) + { + /*PIO transfer mode*/ + if ((val & 7) > 4) + return 0; + data->pio_mode = (val & 7); + return 1; + } + else if ((val & 0xf8) == 0x20) + { + /*Multi-word DMA transfer mode*/ + if ((val & 7) > 2) + return 0; + data->mdma_mode = (val & 7); + return 1; + } + return 0; /*Invalid data*/ + + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_REVERT: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + case FEATURE_ENABLE_REVERT: + return 1; + } + + return 0; /*Feature not supported*/ +} + +scsi_device_t scsi_cd = +{ + scsi_cd_init, + scsi_cd_atapi_init, + scsi_cd_close, + scsi_cd_reset, + + scsi_cd_start_command, + scsi_cd_command, + + scsi_cd_get_status, + scsi_cd_get_sense_key, + scsi_cd_get_bytes_required, + + scsi_cd_atapi_identify, + scsi_cd_atapi_set_feature, + + scsi_cd_read, + scsi_cd_write, + scsi_cd_read_complete, + scsi_cd_write_complete, +}; diff --git a/src/scsi_cd.h b/src/scsi_cd.h new file mode 100644 index 0000000..5b3f701 --- /dev/null +++ b/src/scsi_cd.h @@ -0,0 +1,23 @@ +extern scsi_device_t scsi_cd; + +#define MAX_CD_SPEED 72 +int cd_get_speed(int i); +void cd_set_speed(int speed); + +extern int cd_speed; + +#define MAX_CD_MODEL 1 + +#define CD_MODEL_INTERFACE_ALL 0 // even when controller is not IDE and not SCSI (to always have the PCemCD model as default, even when not selectable) +#define CD_MODEL_INTERFACE_IDE 1 +#define CD_MODEL_INTERFACE_SCSI 2 + +char *cd_get_model(int i); +char *cd_get_config_model(int i); +void cd_set_model(char *model); +int cd_get_model_interfaces(int i); +int cd_get_model_speed(int i); +char *cd_model_to_config(char *model); +char *cd_model_from_config(char *config); + +extern char *cd_model; diff --git a/src/scsi_hd.c b/src/scsi_hd.c new file mode 100644 index 0000000..2a064d5 --- /dev/null +++ b/src/scsi_hd.c @@ -0,0 +1,837 @@ +#include +#include +#include +#include +#include "ibm.h" +#include "hdd_file.h" +#include "scsi.h" +#include "scsi_hd.h" +#include "timer.h" + +extern char ide_fn[7][512]; + +#define BUFFER_SIZE (256*1024) + +#define RW_DELAY (TIMER_USEC * 500) + +enum +{ + CMD_POS_IDLE = 0, + CMD_POS_WAIT, + CMD_POS_START_SECTOR, + CMD_POS_TRANSFER +}; + +typedef struct scsi_hd_data +{ + int blocks; + + int cmd_pos, new_cmd_pos; + + int addr, len; + int sector_pos; + + uint8_t buf[512]; + + uint8_t status; + + uint8_t data_in[BUFFER_SIZE]; + uint8_t data_out[BUFFER_SIZE]; + int data_pos_read, data_pos_write; + + int bytes_received, bytes_required; + + hdd_file_t hdd; + + int sense_key, asc, ascq; + + int hd_id; + + pc_timer_t callback_timer; + + scsi_bus_t *bus; +} scsi_hd_data; + +static void scsi_hd_callback(void *p) +{ + scsi_hd_data *data = p; + + if (data->cmd_pos == CMD_POS_WAIT) + { + data->cmd_pos = data->new_cmd_pos; + scsi_bus_kick(data->bus); + } +} + +static void *scsi_hd_init(scsi_bus_t *bus, int id) +{ + scsi_hd_data *data = malloc(sizeof(scsi_hd_data)); + memset(data, 0, sizeof(scsi_hd_data)); + + hdd_load(&data->hdd, id, ide_fn[id]); + + if (!data->hdd.f) + { + free(data); + return NULL; + } + + data->hd_id = id; + data->bus = bus; + timer_add(&data->callback_timer, scsi_hd_callback, data, 0); + + return data; +} + +static void scsi_hd_close(void *p) +{ + scsi_hd_data *data = p; + + hdd_close(&data->hdd); + free(data); +} + +static int scsi_add_data(uint8_t val, void *p) +{ + scsi_hd_data *data = p; + +// pclog("scsi_add_data : %04x %02x\n", data->data_pos_write, val); + + data->data_in[data->data_pos_write++] = val; + +// if (data->bus_out & BUS_REQ) +// return -1; + +// data->bus_out = (data->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ; + + return 0; +} + +static int scsi_get_data(void *p) +{ + scsi_hd_data *data = p; + uint8_t val = data->data_out[data->data_pos_read++]; + + if (data->data_pos_read > BUFFER_SIZE) + fatal("scsi_get_data beyond buffer limits\n"); + + return val; +} + +static void scsi_hd_illegal(scsi_hd_data *data) +{ + data->status = STATUS_CHECK_CONDITION; + data->sense_key = KEY_ILLEGAL_REQ; + data->asc = ASC_INVALID_LUN; + data->ascq = 0; +} + +#define add_data_len(v) \ + if (i < len) \ + scsi_add_data(v, data); \ + i++; + + +static int scsi_hd_command(uint8_t *cdb, void *p) +{ + scsi_hd_data *data = p; + int /*addr, */len; + int i = 0; + int desc; + int bus_state = 0; + +// if (data->cmd_pos == CMD_POS_IDLE) +// pclog("SCSI HD command %02x\n", cdb[0]); + data->status = STATUS_GOOD; + data->data_pos_read = data->data_pos_write = 0; + + if ((cdb[0] != SCSI_REQUEST_SENSE/* && cdb[0] != SCSI_INQUIRY*/) && (cdb[1] & 0xe0)) + { +// pclog("non-zero LUN\n"); + /*Non-zero LUN - abort command*/ + scsi_hd_illegal(data); + bus_state = BUS_CD | BUS_IO; + return bus_state; + } + + switch (cdb[0]) + { + case SCSI_TEST_UNIT_READY: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_REZERO_UNIT: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_REQUEST_SENSE: + desc = cdb[1] & 1; + len = cdb[4]; + + if (!desc) + { + add_data_len(0x70); + add_data_len(0); + add_data_len(data->sense_key); /*Sense key*/ + add_data_len(0); /*Information (4 bytes)*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); /*Additional sense length*/ + add_data_len(0); /*Command specific information (4 bytes)*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(data->asc); /*ASC*/ + add_data_len(data->ascq); /*ASCQ*/ + add_data_len(0); /*FRU code*/ + add_data_len(0); /*Sense key specific (3 bytes)*/ + add_data_len(0); + add_data_len(0); + } + else + { + add_data_len(0x72); + add_data_len(data->sense_key); /*Sense Key*/ + add_data_len(data->asc); /*ASC*/ + add_data_len(data->ascq); /*ASCQ*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); /*additional sense length*/ + } + + data->sense_key = data->asc = data->ascq = 0; + + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + + case SCSI_INQUIRY: + len = cdb[4] | (cdb[3] << 8); +// pclog("INQUIRY %d %02x %02x %02x %02x %02x %02x %i\n", len, cdb[0],cdb[1],cdb[2],cdb[3],cdb[4],cdb[5], data->hd_id); + + if (cdb[1] & 0xe0) + { + add_data_len(0 | (3 << 5)); /*No physical device on this LUN*/ + } + else + { + add_data_len(0 | (0 << 5)); /*Hard disc*/ + } + add_data_len(0); /*Not removeable*/ + add_data_len(0); /*No version*/ + add_data_len(2); /*Response data*/ + add_data_len(0); /*Additional length*/ + add_data_len(0); + add_data_len(0); + add_data_len(2); + + add_data_len('P'); + add_data_len('C'); + add_data_len('e'); + add_data_len('m'); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + + add_data_len('S'); + add_data_len('C'); + add_data_len('S'); + add_data_len('I'); + add_data_len('_'); + add_data_len('H'); + add_data_len('D'); + add_data_len(' '); + + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + + add_data_len(0); /*Product revision level*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Drive serial number*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Vendor unique*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Vendor descriptor*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Reserved*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_MODE_SENSE_6: + len = cdb[4]; + + add_data_len(0); + add_data_len(0); + + add_data_len(0x08); + add_data_len(0); + + add_data_len((data->hdd.sectors >> 24) & 0xff); + add_data_len((data->hdd.sectors >> 16) & 0xff); + add_data_len((data->hdd.sectors >> 8) & 0xff); + add_data_len( data->hdd.sectors & 0xff); + add_data_len((512 >> 24) & 0xff); + add_data_len((512 >> 16) & 0xff); + add_data_len((512 >> 8) & 0xff); + add_data_len( 512 & 0xff); + + if ((cdb[2] & 0x3f) == 0x03 || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(3); + add_data_len(0x16); + add_data_len(0); add_data_len(1); /*Tracks per zone*/ + add_data_len(0); add_data_len(1); /*Alternate sectors per zone*/ + add_data_len(0); add_data_len(1); /*Alternate tracks per zone*/ + add_data_len(0); add_data_len(1); /*Alternate tracks per volume*/ + add_data_len(1); add_data_len(0); /*Sectors per track*/ + add_data_len(2); add_data_len(0); /*Data bytes per physical sector*/ + add_data_len(0); add_data_len(0); /*Interleave*/ + add_data_len(0); add_data_len(0); /*Track skew*/ + add_data_len(0); add_data_len(0); /*Cylinder skew*/ + add_data_len(0); /*Drive type*/ + add_data_len(0); add_data_len(0); add_data_len(0); + } + + if ((cdb[2] & 0x3f) == 0x04 || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(4); + add_data_len(0x16); + add_data_len(0); add_data_len(0x10); add_data_len(0); /*Cylinder count*/ + add_data_len(64); /*Heads*/ + add_data_len(0); add_data_len(0); add_data_len(0); /*Write recomp*/ + add_data_len(0); add_data_len(0); add_data_len(0); /*Reduced write current*/ + add_data_len(0); add_data_len(0); /*Drive step rate*/ + add_data_len(0); add_data_len(0); add_data_len(0); /*Landing zone cylinder*/ + add_data_len(0); /*RPL*/ + add_data_len(0); /*Rotational offset*/ + add_data_len(0); + add_data_len(0x10); add_data_len(0); /*Rotain rate*/ + add_data_len(0); add_data_len(0); + } + + if ((cdb[2] & 0x3f) == 0x30 || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(0xb0); + add_data_len(0x16); + add_data_len('P'); + add_data_len('C'); + add_data_len('E'); + add_data_len('M'); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + } + + for (; len >= 0; len--) + { + add_data_len(0); + } + + len = data->data_pos_write; + if (cdb[0] == SCSI_MODE_SENSE_6) + { + data->data_in[0] = len - 1; + } + else + { + data->data_in[0] = (len - 2) >> 8; + data->data_in[1] = (len - 2) & 255; + } +// scsi_illegal_field(); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_CAPACITY_10: + scsi_add_data((data->hdd.sectors >> 24) & 0xff, data); + scsi_add_data((data->hdd.sectors >> 16) & 0xff, data); + scsi_add_data((data->hdd.sectors >> 8) & 0xff, data); + scsi_add_data( data->hdd.sectors & 0xff, data); + scsi_add_data((512 >> 24) & 0xff, data); + scsi_add_data((512 >> 16) & 0xff, data); + scsi_add_data((512 >> 8) & 0xff, data); + scsi_add_data( 512 & 0xff, data); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_6: +// pclog("SCSI_READ_6 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + + if (data->cmd_pos == CMD_POS_IDLE) + { + readflash_set(READFLASH_HDC, data->hd_id); + data->addr = cdb[3] | (cdb[2] << 8) | ((cdb[1] & 0x1f) << 16); + data->len = cdb[4]; + if (!data->len) + data->len = 256; +// pclog("SCSI_READ_6: addr=%08x len=%04x\n", data->addr, data->len); + + data->cmd_pos = CMD_POS_WAIT; + timer_set_delay_u64(&data->callback_timer, RW_DELAY); + data->new_cmd_pos = CMD_POS_START_SECTOR; + data->sector_pos = 0; + + bus_state = BUS_CD; + break; + } +// else +// pclog("SCSI_READ_6 continue addr=%08x len=%04x sector_pos=%02x\n", data->addr, data->len, data->sector_pos); + while (data->len) + { + if (data->cmd_pos == CMD_POS_START_SECTOR) + { + hdd_read_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + } + + data->cmd_pos = CMD_POS_TRANSFER; + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_add_data(data->buf[data->sector_pos], data); + + if (ret == -1) + { + fatal("scsi_add_data -1\n"); + break; + } + if (ret & 0x100) + { + fatal("scsi_add_data 0x100\n"); + data->len = 1; + break; + } + } + data->cmd_pos = CMD_POS_START_SECTOR; + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_10: +// pclog("SCSI_READ_10 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + + if (data->cmd_pos == CMD_POS_IDLE) + { + readflash_set(READFLASH_HDC, data->hd_id); + data->addr = cdb[5] | (cdb[4] << 8) | (cdb[3] << 16) | (cdb[2] << 24); + data->len = cdb[8] | (cdb[7] << 8); +// pclog("SCSI_READ_10: addr=%08x len=%04x\n", data->addr, data->len); + + data->cmd_pos = CMD_POS_WAIT; + timer_set_delay_u64(&data->callback_timer, RW_DELAY); + data->new_cmd_pos = CMD_POS_START_SECTOR; + data->sector_pos = 0; + + bus_state = BUS_CD; + break; + } +// else +// pclog("SCSI_READ_10 continue addr=%08x len=%04x sector_pos=%02x\n", data->addr, data->len, data->sector_pos); + while (data->len) + { + if (data->cmd_pos == CMD_POS_START_SECTOR) + { + hdd_read_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + } + data->cmd_pos = CMD_POS_TRANSFER; + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_add_data(data->buf[data->sector_pos], data); +// pclog("SCSI_READ_10 sector_pos=%i\n", data->sector_pos); + if (ret == -1) + { + fatal("scsi_add_data -1\n"); + break; + } + if (ret & 0x100) + { + fatal("scsi_add_data 0x100\n"); + data->len = 1; + break; + } + } + data->cmd_pos = CMD_POS_START_SECTOR; + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_WRITE_6: +// pclog("SCSI_WRITE_6 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_IDLE) + { + data->addr = cdb[3] | (cdb[2] << 8) | ((cdb[1] & 0x1f) << 16); + data->len = cdb[4]; + if (!data->len) + data->len = 256; + readflash_set(READFLASH_HDC, data->hd_id); +// pclog("SCSI_WRITE_6: addr=%08x len=%04x\n", data->addr, data->len); + data->bytes_required = data->len * 512; + + data->cmd_pos = CMD_POS_WAIT; + timer_set_delay_u64(&data->callback_timer, RW_DELAY); + data->new_cmd_pos = CMD_POS_TRANSFER; + data->sector_pos = 0; + + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_TRANSFER && data->bytes_received != data->bytes_required) + { + bus_state = 0; + break; + } + + while (data->len) + { + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_get_data(data); + if (ret == -1) + { + fatal("scsi_get_data -1\n"); + break; + } + data->buf[data->sector_pos] = ret & 0xff; + if (ret & 0x100) + { + fatal("scsi_get_data 0x100\n"); + data->len = 1; + break; + } + } + + hdd_write_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_WRITE_10: +// pclog("SCSI_WRITE_10 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_IDLE) + { + data->addr = cdb[5] | (cdb[4] << 8) | (cdb[3] << 16) | (cdb[2] << 24); + data->len = cdb[8] | (cdb[7] << 8); + readflash_set(READFLASH_HDC, data->hd_id); +// pclog("SCSI_WRITE_10: addr=%08x len=%04x\n", data->addr, data->len); + data->bytes_required = data->len * 512; + + data->cmd_pos = CMD_POS_WAIT; + timer_set_delay_u64(&data->callback_timer, RW_DELAY); + data->new_cmd_pos = CMD_POS_TRANSFER; + data->sector_pos = 0; + + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_TRANSFER && data->bytes_received != data->bytes_required) + { + bus_state = 0; + break; + } + + while (data->len) + { + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_get_data(data); +// pclog("SCSI_WRITE_10 sector_pos=%i\n", data->sector_pos); + if (ret == -1) + { + fatal("scsi_get_data -1\n"); + break; + } + data->buf[data->sector_pos] = ret & 0xff; + if (ret & 0x100) + { + fatal("scsi_get_data 0x100\n"); + data->len = 1; + break; + } + } + + hdd_write_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; +// output = 3; + break; + + case SCSI_VERIFY_10: + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_MODE_SELECT_6: + if (!data->bytes_received) + { + data->bytes_required = cdb[4]; +// pclog("SCSI_MODE_SELECT_6 bytes_required=%i\n", data->bytes_required); + bus_state = 0; + break; + } +// pclog("SCSI_MODE_SELECT_6 complete\n"); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_FORMAT: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_START_STOP_UNIT: + bus_state = BUS_CD | BUS_IO; + break; + + /*These aren't really meaningful in a single initiator system, so just return*/ + case SCSI_RESERVE: + case SCSI_RELEASE: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_SEEK_6: + case SCSI_SEEK_10: + bus_state = BUS_CD | BUS_IO; + break; + + case SEND_DIAGNOSTIC: + if (cdb[1] & (1 << 2)) + { + /*Self-test*/ + /*Always passes*/ + bus_state = BUS_CD | BUS_IO; + } + else + { + /*Treat all other diagnostic requests as illegal*/ + scsi_hd_illegal(data); + bus_state = BUS_CD | BUS_IO; + } + break; + + default: + pclog("Bad SCSI HD command %02x\n", cdb[0]); + scsi_hd_illegal(data); + bus_state = BUS_CD | BUS_IO; + break; + } + + return bus_state; +} + +static uint8_t scsi_hd_read(void *p) +{ + scsi_hd_data *data = p; + + return data->data_in[data->data_pos_read++]; +} + +static void scsi_hd_write(uint8_t val, void *p) +{ + scsi_hd_data *data = p; + + data->data_out[data->data_pos_write++] = val; + + data->bytes_received++; + + if (data->data_pos_write > BUFFER_SIZE) + fatal("Exceeded data_out buffer size\n"); +} + +static int scsi_hd_read_complete(void *p) +{ + scsi_hd_data *data = p; + + return (data->data_pos_read == data->data_pos_write); +} +static int scsi_hd_write_complete(void *p) +{ + scsi_hd_data *data = p; + + return (data->bytes_received == data->bytes_required); +} + +static void scsi_hd_start_command(void *p) +{ + scsi_hd_data *data = p; + + data->bytes_received = 0; + data->bytes_required = 0; + data->data_pos_read = data->data_pos_write = 0; +} + +static uint8_t scsi_hd_get_status(void *p) +{ + scsi_hd_data *data = p; + + return data->status; +} + +static uint8_t scsi_hd_get_sense_key(void *p) +{ + scsi_hd_data *data = p; + + return data->sense_key; +} + +static int scsi_hd_get_bytes_required(void *p) +{ + scsi_hd_data *data = p; + + return data->bytes_required - data->bytes_received; +} + +scsi_device_t scsi_hd = +{ + scsi_hd_init, + NULL, + scsi_hd_close, + NULL, + + scsi_hd_start_command, + scsi_hd_command, + + scsi_hd_get_status, + scsi_hd_get_sense_key, + scsi_hd_get_bytes_required, + + NULL, + NULL, + + scsi_hd_read, + scsi_hd_write, + scsi_hd_read_complete, + scsi_hd_write_complete, +}; diff --git a/src/scsi_hd.h b/src/scsi_hd.h new file mode 100644 index 0000000..9f0bdf5 --- /dev/null +++ b/src/scsi_hd.h @@ -0,0 +1 @@ +extern scsi_device_t scsi_hd; diff --git a/src/scsi_ibm.c b/src/scsi_ibm.c new file mode 100644 index 0000000..708c24e --- /dev/null +++ b/src/scsi_ibm.c @@ -0,0 +1,1278 @@ +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "mca.h" +#include "mem.h" +#include "pic.h" +#include "rom.h" +#include "scsi.h" +#include "timer.h" + +#include "scsi_ibm.h" + +#define SCSI_TIME (20) +#define POLL_TIME (TIMER_USEC * 10) +#define MAX_BYTES_TRANSFERRED_PER_POLL 50 + +extern char ide_fn[4][512]; + +typedef enum +{ + SCB_STATE_IDLE, + SCB_STATE_START, + SCB_STATE_WAIT, + SCB_STATE_COMPLETE +} sbc_state_t; + +typedef enum +{ + SCSI_STATE_IDLE, + SCSI_STATE_SELECT, + SCSI_STATE_SELECT_FAILED, + SCSI_STATE_SEND_COMMAND, + SCSI_STATE_NEXT_PHASE, + SCSI_STATE_END_PHASE, + SCSI_STATE_READ_DATA, + SCSI_STATE_WRITE_DATA, + SCSI_STATE_READ_STATUS, + SCSI_STATE_READ_MESSAGE +} scsi_state_t; + +typedef struct scb_t +{ + uint16_t command; + uint16_t enable; + uint32_t lba_addr; + uint32_t sys_buf_addr; + uint32_t sys_buf_byte_count; + uint32_t term_status_block_addr; + uint32_t scb_chain_addr; + uint16_t block_count; + uint16_t block_length; +} scb_t; + +typedef struct scsi_ibm_t +{ + rom_t bios_rom; + + uint8_t pos_regs[8]; + + uint8_t basic_ctrl; + uint32_t command; + + uint8_t attention; + uint8_t attention_pending; + int attention_waiting; + + uint8_t cir[4]; + uint8_t cir_pending[4]; + + uint8_t irq_status; + + uint32_t scb_addr; + + uint8_t status; + + int in_invalid; + int in_reset; + sbc_state_t scb_state; + + scb_t scb; + int scb_id; + + int cmd_status; + int cir_status; + + uint8_t pacing; + + uint8_t buf[0x600]; + + uint8_t int_buffer[512]; + + struct + { + int phys_id; + int lun_id; + } dev_id[16]; + + struct + { + int idx, len; + uint8_t data[256]; + + int data_idx, data_len; + uint32_t data_pointer; + + uint8_t last_status; + + int bytes_transferred; + + int target_id; + } cdb; + + int irq_requests[16]; + + int cmd_timer; + pc_timer_t callback_timer; + + scsi_state_t scsi_state; + scsi_bus_t bus; +} scsi_ibm_t; + +#define CTRL_RESET (1 << 7) +#define CTRL_DMA_ENA (1 << 1) +#define CTRL_IRQ_ENA (1 << 0) + +#define STATUS_CMD_FULL (1 << 3) +#define STATUS_CMD_EMPTY (1 << 2) +#define STATUS_IRQ (1 << 1) +#define STATUS_BUSY (1 << 0) + +#define ENABLE_PT (1 << 12) + +#define CMD_MASK 0xff3f +#define CMD_ASSIGN 0x040e +#define CMD_DEVICE_INQUIRY 0x1c0b +#define CMD_DMA_PACING_CONTROL 0x040d +#define CMD_FEATURE_CONTROL 0x040c +#define CMD_GET_POS_INFO 0x1c0a +#define CMD_INVALID_412 0x0412 +#define CMD_GET_COMPLETE_STATUS 0x1c07 +#define CMD_READ_DATA 0x1c01 +#define CMD_READ_DEVICE_CAPACITY 0x1c09 +#define CMD_REQUEST_SENSE 0x1c08 +#define CMD_RESET 0x0400 +#define CMD_SEND_OTHER_SCSI 0x241f +#define CMD_UNKNOWN_1c10 0x1c10 +#define CMD_UNKNOWN_1c11 0x1c11 +#define CMD_WRITE_DATA 0x1c02 +#define CMD_VERIFY 0x1c03 + +#define IRQ_TYPE_NONE 0x0 +#define IRQ_TYPE_SCB_COMPLETE 0x1 +#define IRQ_TYPE_SCB_COMPLETE_RETRY 0x5 +#define IRQ_TYPE_ADAPTER_HW_FAILURE 0x7 +#define IRQ_TYPE_IMM_CMD_COMPLETE 0xa +#define IRQ_TYPE_COMMAND_FAIL 0xc +#define IRQ_TYPE_COMMAND_ERROR 0xe +#define IRQ_TYPE_SW_SEQ_ERROR 0xf +#define IRQ_TYPE_RESET_COMPLETE 0x10 + +static void scsi_rethink_irqs(scsi_ibm_t *scsi) +{ + int irq_pending = 0; + int c; + +/* pclog("scsi_rethink_irqs: basic_ctrl=%02x status=%02x\n", scsi->basic_ctrl, scsi->irq_status); + pclog(" "); + for (c = 0; c < 16; c++) + pclog(" %02x", scsi->irq_requests[c]); + pclog("\n");*/ + + if (!scsi->irq_status) + { + for (c = 0; c < 16; c++) + { + if (scsi->irq_requests[c] != IRQ_TYPE_NONE) + { +// pclog(" Found IRQ on %i\n", c); + /*Found IRQ*/ + scsi->irq_status = c | (scsi->irq_requests[c] << 4); + scsi->status |= STATUS_IRQ; + irq_pending = 1; + break; + } + } + } + else + irq_pending = 1; + + if (scsi->basic_ctrl & CTRL_IRQ_ENA) + { + if (irq_pending) + { + picintlevel(1 << 14); +// pclog(" SCSI assert INT\n"); + } + else + { + /*No IRQs pending, clear IRQ state*/ + scsi->irq_status = 0; + scsi->status &= ~STATUS_IRQ; + picintc(1 << 14); +// pclog(" SCSI clear INT - no IRQ\n"); + } + } + else + { + picintc(1 << 14); +// pclog(" SCSI clear INT - IRQs disabled\n"); + } +} + +static inline void scsi_ibm_set_irq(scsi_ibm_t *scsi, int id, int type) +{ +// pclog("scsi_ibm_set_irq id=%i type=%x %02x\n", id, type, scsi->irq_status); + scsi->irq_requests[id] = type; + if (!scsi->irq_status) /*Don't change IRQ status if one is currently being processed*/ + scsi_rethink_irqs(scsi); +} +static inline void scsi_clear_irq(scsi_ibm_t *scsi, int id) +{ + scsi->irq_requests[id] = IRQ_TYPE_NONE; + scsi_rethink_irqs(scsi); +} + +static uint8_t scsi_read(uint16_t port, void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + uint8_t temp = 0xff; + + switch (port & 7) + { + case 0: case 1: case 2: case 3: /*Command Interface Register*/ + temp = scsi->cir_pending[port & 3]; + break; + + case 4: /*Attention Register*/ + temp = scsi->attention_pending; + break; + case 5: /*Basic Control Register*/ + temp = scsi->basic_ctrl; + break; + case 6: /*IRQ status*/ + temp = scsi->irq_status; + break; + case 7: /*Status*/ + temp = scsi->status; + if (scsi->cir_status == 0) + temp |= STATUS_CMD_EMPTY; + if (scsi->cir_status == 3) + temp |= STATUS_CMD_FULL; + break; + } + +// pclog("scsi_read: port=%04x val=%02x %04x(%05x):%04x %i %02x\n", port, temp,CS,cs,cpu_state.pc, 0/*scsi->callback*/, BH); + return temp; +} + +static void scsi_write(uint16_t port, uint8_t val, void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + +// pclog("scsi_write: port=%04x val=%02x %04x:%04x\n", port, val,CS,cpu_state.pc); + + switch (port & 7) + { + case 0: case 1: case 2: case 3: /*Command Interface Register*/ + scsi->cir_pending[port & 3] = val; + if (port & 2) + scsi->cir_status |= 2; + else + scsi->cir_status |= 1; + break; + + case 4: /*Attention Register*/ + scsi->attention_pending = val; + scsi->attention_waiting = 2; + scsi->status |= STATUS_BUSY; + break; + + case 5: /*Basic Control Register*/ + if ((scsi->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) + { +// pclog("SCSI reset\n"); + scsi->in_reset = 1; + scsi->cmd_timer = SCSI_TIME*2; + scsi->status |= STATUS_BUSY; + } + scsi->basic_ctrl = val; + scsi_rethink_irqs(scsi); + break; + +// default: +// fatal("scsi_write port=%04x val=%02x\n", port, val); + } +} + +static uint16_t scsi_readw(uint16_t port, void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + uint16_t temp = 0xffff; + + switch (port & 7) + { + case 0: /*Command Interface Register*/ + temp = scsi->cir_pending[0] | (scsi->cir_pending[1] << 8); + break; + case 2: /*Command Interface Register*/ + temp = scsi->cir_pending[2] | (scsi->cir_pending[3] << 8); + break; + +// default: +// fatal("scsi_readw port=%04x\n", port); + } + +// pclog("scsi_readw: port=%04x val=%04x\n", port, temp); + return temp; +} + +static void scsi_writew(uint16_t port, uint16_t val, void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + + switch (port & 7) + { + case 0: /*Command Interface Register*/ + scsi->cir_pending[0] = val & 0xff; + scsi->cir_pending[1] = val >> 8; + scsi->cir_status |= 1; + break; + case 2: /*Command Interface Register*/ + scsi->cir_pending[2] = val & 0xff; + scsi->cir_pending[3] = val >> 8; + scsi->cir_status |= 2; + break; + +// default: +// fatal("scsi_writew port=%04x val=%04x\n", port, val); + } + +// pclog("scsi_writew: port=%04x val=%04x\n", port, val); +} + +static void sg_fetch_next(scsi_ibm_t *scsi) +{ + if (scsi->scb.sys_buf_byte_count > 0) + { + scsi->cdb.data_idx = 0; + scsi->cdb.data_pointer = mem_readl_phys(scsi->scb.sys_buf_addr); + scsi->cdb.data_len = mem_readl_phys(scsi->scb.sys_buf_addr + 4); +// pclog("SG list: from %08x addr=%08x len=%08x\n", scsi->scb.sys_buf_addr, scsi->cdb.data_pointer, scsi->cdb.data_len); + scsi->scb.sys_buf_addr += 8; + scsi->scb.sys_buf_byte_count -= 8; + } +} + +static void process_ibm_cmd(void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + scb_t *scb = &scsi->scb; + int c; + int old_scb_state; + +// pclog("scsi_callback: in_reset=%i command=%x\n", scsi->in_reset, scsi->command); + if (scsi->in_reset) + { + scsi->status &= ~STATUS_BUSY; + + scsi->irq_status = 0; + for (c = 0; c < 16; c++) + scsi_clear_irq(scsi, c); + if (scsi->in_reset == 1) + { + scsi->basic_ctrl |= CTRL_IRQ_ENA; + scsi_ibm_set_irq(scsi, 0xf, IRQ_TYPE_RESET_COMPLETE); + } + else + scsi_ibm_set_irq(scsi, 0xf, IRQ_TYPE_RESET_COMPLETE); + + /*Reset device mappings*/ + for (c = 0; c < 7; c++) + { + scsi->dev_id[c].phys_id = c; + scsi->dev_id[c].lun_id = 0; + } + for (; c < 15; c++) + scsi->dev_id[c].phys_id = -1; + + scsi->in_reset = 0; +// pclog("scsi reset complete\n"); + return; + } + if (scsi->in_invalid) + { + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_ERROR); + scsi->in_invalid = 0; + return; + } + do + { + old_scb_state = scsi->scb_state; + +// pclog("scb_state=%i\n", scsi->scb_state); + switch (scsi->scb_state) + { + case SCB_STATE_IDLE: + break; + + case SCB_STATE_START: + if (scsi->dev_id[scsi->scb_id].phys_id == -1) + { + scsi_ibm_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); + scsi->scb_state = SCB_STATE_IDLE; + mem_writew_phys(scb->term_status_block_addr + 0x7*2, (0xe << 8) | 0); + mem_writew_phys(scb->term_status_block_addr + 0x8*2, (0xa << 8) | 0); + break; + } + + scb->command = mem_readw_phys(scsi->scb_addr); + scb->enable = mem_readw_phys(scsi->scb_addr + 0x02); + scb->lba_addr = mem_readl_phys(scsi->scb_addr + 0x04); + scb->sys_buf_addr = mem_readl_phys(scsi->scb_addr + 0x08); + scb->sys_buf_byte_count = mem_readl_phys(scsi->scb_addr + 0x0c); + scb->term_status_block_addr = mem_readl_phys(scsi->scb_addr + 0x10); + scb->scb_chain_addr = mem_readl_phys(scsi->scb_addr + 0x14); + scb->block_count = mem_readw_phys(scsi->scb_addr + 0x18); + scb->block_length = mem_readw_phys(scsi->scb_addr + 0x1a); + +/* pclog("SCB : \n" + " Command = %04x\n" + " Enable = %04x\n" + " LBA addr = %08x\n" + " System buffer addr = %08x\n" + " System buffer byte count = %08x\n" + " Terminate status block addr = %08x\n" + " SCB chain address = %08x\n" + " Block count = %04x\n" + " Block length = %04x\n", + scb->command, scb->enable, scb->lba_addr, + scb->sys_buf_addr, scb->sys_buf_byte_count, + scb->term_status_block_addr, scb->scb_chain_addr, + scb->block_count, scb->block_length);*/ + + if (scb->enable & ENABLE_PT) + sg_fetch_next(scsi); + else + { + scsi->cdb.data_idx = 0; + scsi->cdb.data_pointer = scb->sys_buf_addr; + scsi->cdb.data_len = scb->sys_buf_byte_count; + } + + switch (scb->command & CMD_MASK) + { + case CMD_GET_COMPLETE_STATUS: + mem_writew_phys(scb->sys_buf_addr + 0x0*2, 0x201); /*SCB status*/ + mem_writew_phys(scb->sys_buf_addr + 0x1*2, 0); /*Retry counts*/ + mem_writel_phys(scb->sys_buf_addr + 0x2*2, 0); /*Residual byte count*/ + mem_writel_phys(scb->sys_buf_addr + 0x4*2, 0); /*Scatter/gather list element address*/ + mem_writew_phys(scb->sys_buf_addr + 0x6*2, 0xc); /*Device dependent status length*/ + mem_writew_phys(scb->sys_buf_addr + 0x7*2, scsi->cmd_status << 8); + mem_writew_phys(scb->sys_buf_addr + 0x8*2, 0); /*Error*/ + mem_writew_phys(scb->sys_buf_addr + 0x9*2, 0); /*Reserved*/ + mem_writew_phys(scb->sys_buf_addr + 0xa*2, 0); /*Cache information status*/ + mem_writel_phys(scb->sys_buf_addr + 0xb*2, scsi->scb_addr); + scsi->scb_state = SCB_STATE_COMPLETE; + break; + + case CMD_UNKNOWN_1c10: + for (c = 0; c < 0x600 && c < scb->sys_buf_byte_count; c++) + scsi->buf[c] = mem_readb_phys(scb->sys_buf_addr + c); + scsi->scb_state = SCB_STATE_COMPLETE; + break; + case CMD_UNKNOWN_1c11: + for (c = 0; c < 0x600 && c < scb->sys_buf_byte_count; c++) + mem_writeb_phys(scb->sys_buf_addr + c, scsi->buf[c]); + scsi->scb_state = SCB_STATE_COMPLETE; + break; + + case CMD_GET_POS_INFO: + mem_writew_phys(scb->sys_buf_addr + 0x0*2, 0x8eff); + mem_writew_phys(scb->sys_buf_addr + 0x1*2, scsi->pos_regs[3] | (scsi->pos_regs[2] << 8)); + mem_writew_phys(scb->sys_buf_addr + 0x2*2, 0x0e | (scsi->pos_regs[4] << 8)); + mem_writew_phys(scb->sys_buf_addr + 0x3*2, 1 << 12); + mem_writew_phys(scb->sys_buf_addr + 0x4*2, (7 << 8) | 8); + mem_writew_phys(scb->sys_buf_addr + 0x5*2, (16 << 8) | scsi->pacing); + mem_writew_phys(scb->sys_buf_addr + 0x6*2, (30 << 8) | 1); + mem_writew_phys(scb->sys_buf_addr + 0x7*2, 0); + mem_writew_phys(scb->sys_buf_addr + 0x8*2, 0); + scsi->scb_state = SCB_STATE_COMPLETE; + break; + + case CMD_DEVICE_INQUIRY: + scsi->cdb.data[0] = SCSI_INQUIRY; + scsi->cdb.data[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ + scsi->cdb.data[2] = 0; /*Page code*/ + scsi->cdb.data[3] = 0; + scsi->cdb.data[4] = scb->sys_buf_byte_count; /*Allocation length*/ + scsi->cdb.data[5] = 0; /*Control*/ + scsi->cdb.idx = 0; + scsi->cdb.len = 6; + scsi->cdb.target_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->cdb.data_pointer = scb->sys_buf_addr; + scsi->cdb.data_idx = 0; + scsi->cdb.data_len = scb->sys_buf_byte_count; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->scb_state = SCB_STATE_WAIT; + return; + + case CMD_SEND_OTHER_SCSI: +// pclog("SEND_OTHER_SCSI:"); + for (c = 0; c < 12; c++) + { + scsi->cdb.data[c] = mem_readb_phys(scsi->scb_addr + 0x18 + c); +// pclog(" %02x", scsi->cdb.data[c]); + } +// pclog("\n"); + scsi->cdb.data[1] = (scsi->cdb.data[1] & 0x1f) | (scsi->dev_id[scsi->scb_id].lun_id << 5); /*Patch correct LUN into command*/ + scsi->cdb.idx = 0; + scsi->cdb.len = (scb->lba_addr & 0xff) ? (scb->lba_addr & 0xff) : 6; +// pclog("SEND_OTHER_SCSI: %04x\n", scb->lba_addr & 0xffff); + scsi->cdb.target_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->scb_state = SCB_STATE_WAIT; + return; + + case CMD_READ_DEVICE_CAPACITY: + scsi->cdb.data[0] = SCSI_READ_CAPACITY_10; + scsi->cdb.data[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ + scsi->cdb.data[2] = 0; /*LBA*/ + scsi->cdb.data[3] = 0; + scsi->cdb.data[4] = 0; + scsi->cdb.data[5] = 0; + scsi->cdb.data[6] = 0; /*Reserved*/ + scsi->cdb.data[7] = 0; + scsi->cdb.data[8] = 0; + scsi->cdb.data[9] = 0; /*Control*/ + scsi->cdb.idx = 0; + scsi->cdb.len = 10; + scsi->cdb.target_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->scb_state = SCB_STATE_WAIT; + return; + + case CMD_READ_DATA: + scsi->cdb.data[0] = SCSI_READ_10; + scsi->cdb.data[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ + scsi->cdb.data[2] = (scb->lba_addr >> 24) & 0xff; /*LBA*/ + scsi->cdb.data[3] = (scb->lba_addr >> 16) & 0xff; + scsi->cdb.data[4] = (scb->lba_addr >> 8) & 0xff; + scsi->cdb.data[5] = scb->lba_addr & 0xff; + scsi->cdb.data[6] = 0; /*Reserved*/ + scsi->cdb.data[7] = (scb->block_count >> 8) & 0xff; + scsi->cdb.data[8] = scb->block_count & 0xff; + scsi->cdb.data[9] = 0; /*Control*/ + scsi->cdb.idx = 0; + scsi->cdb.len = 10; + scsi->cdb.target_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->scb_state = SCB_STATE_WAIT; + return; + + case CMD_REQUEST_SENSE: + scsi->cdb.data[0] = SCSI_REQUEST_SENSE; + scsi->cdb.data[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ + scsi->cdb.data[2] = 0; + scsi->cdb.data[3] = 0; + scsi->cdb.data[4] = scb->block_count & 0xff; /*Allocation length*/ + scsi->cdb.data[5] = 0; + scsi->cdb.idx = 0; + scsi->cdb.len = 6; + scsi->cdb.target_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->scb_state = SCB_STATE_WAIT; + return; + + case CMD_WRITE_DATA: + scsi->cdb.data[0] = SCSI_WRITE_10; + scsi->cdb.data[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ + scsi->cdb.data[2] = (scb->lba_addr >> 24) & 0xff; /*LBA*/ + scsi->cdb.data[3] = (scb->lba_addr >> 16) & 0xff; + scsi->cdb.data[4] = (scb->lba_addr >> 8) & 0xff; + scsi->cdb.data[5] = scb->lba_addr & 0xff; + scsi->cdb.data[6] = 0; /*Reserved*/ + scsi->cdb.data[7] = (scb->block_count >> 8) & 0xff; + scsi->cdb.data[8] = scb->block_count & 0xff; + scsi->cdb.data[9] = 0; /*Control*/ + scsi->cdb.idx = 0; + scsi->cdb.len = 10; + scsi->cdb.target_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->scb_state = SCB_STATE_WAIT; + return; + + case CMD_VERIFY: + scsi->cdb.data[0] = SCSI_VERIFY_10; + scsi->cdb.data[1] = scsi->dev_id[scsi->scb_id].lun_id << 5; /*LUN*/ + scsi->cdb.data[2] = (scb->lba_addr >> 24) & 0xff; /*LBA*/ + scsi->cdb.data[3] = (scb->lba_addr >> 16) & 0xff; + scsi->cdb.data[4] = (scb->lba_addr >> 8) & 0xff; + scsi->cdb.data[5] = scb->lba_addr & 0xff; + scsi->cdb.data[6] = 0; /*Reserved*/ + scsi->cdb.data[7] = (scb->block_count >> 8) & 0xff; + scsi->cdb.data[8] = scb->block_count & 0xff; + scsi->cdb.data[9] = 0; /*Control*/ + scsi->cdb.idx = 0; + scsi->cdb.len = 10; + scsi->cdb.target_id = scsi->dev_id[scsi->scb_id].phys_id; + scsi->cdb.data_len = 0; + scsi->scsi_state = SCSI_STATE_SELECT; + scsi->scb_state = SCB_STATE_WAIT; + return; + +#ifndef RELEASE_BUILD + default: + fatal("SCB command %04x\n", scb->command); +#endif + } + break; + + case SCB_STATE_WAIT: + if (scsi->scsi_state == SCSI_STATE_IDLE) + { + if (scsi->cdb.last_status == STATUS_GOOD) + scsi->scb_state = SCB_STATE_COMPLETE; + else if (scsi->cdb.last_status == STATUS_CHECK_CONDITION) + { + scsi_ibm_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); + scsi->scb_state = SCB_STATE_IDLE; + mem_writew_phys(scb->term_status_block_addr + 0x7*2, (0xc << 8) | 2); + mem_writew_phys(scb->term_status_block_addr + 0x8*2, 0x20); + mem_writew_phys(scb->term_status_block_addr + 0xb*2, scsi->scb_addr & 0xffff); + mem_writew_phys(scb->term_status_block_addr + 0xc*2, scsi->scb_addr >> 16); + } +#ifndef RELEASE_BUILD + else + fatal("SCB unknown result %02x\n", scsi->cdb.last_status); +#endif + } + else if (scsi->scsi_state == SCSI_STATE_SELECT_FAILED) + { +// pclog("SCB_STATE_WAIT SELECT_FAILED\n"); + scsi_ibm_set_irq(scsi, scsi->scb_id, IRQ_TYPE_COMMAND_FAIL); + scsi->scb_state = SCB_STATE_IDLE; + mem_writew_phys(scb->term_status_block_addr + 0x7*2, (0xc << 8) | 2); + mem_writew_phys(scb->term_status_block_addr + 0x8*2, 0x10); + } +#ifndef RELEASE_BUILD + else + fatal("SCB_STATE_WAIT other %i\n", scsi->scsi_state); +#endif + break; + + case SCB_STATE_COMPLETE: + if (scb->enable & 1) + { + scsi->scb_state = SCB_STATE_START; + scsi->scb_addr = scb->scb_chain_addr; +// pclog("Next SCB - %08x\n", scsi->scb_addr); + } + else + { + scsi_ibm_set_irq(scsi, scsi->scb_id, IRQ_TYPE_SCB_COMPLETE); + scsi->scb_state = SCB_STATE_IDLE; + } + break; + } + } while (scsi->scb_state != old_scb_state); +} + +static void process_immediate_command(scsi_ibm_t *scsi) +{ + switch (scsi->command & CMD_MASK) + { + case CMD_ASSIGN: +// pclog("Assign: adapter dev=%x scsi ID=%i LUN=%i\n", (scsi->command >> 16) & 0xf, (scsi->command >> 20) & 7, (scsi->command >> 24) & 7); + if (((scsi->command >> 16) & 0xf) == 0xf && ((scsi->command >> 20) & 7) == 7) /*Device 15 always adapter*/ + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + else if (((scsi->command >> 16) & 0xf) == 0xf) /*Can not re-assign device 15 (always adapter)*/ + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_FAIL); + else if (scsi->command & (1 << 23)) + { + scsi->dev_id[(scsi->command >> 16) & 0xf].phys_id = -1; + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + } + else if (((scsi->command >> 20) & 7) == 7) /*Can not assign adapter*/ + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_COMMAND_FAIL); + else + { + scsi->dev_id[(scsi->command >> 16) & 0xf].phys_id = (scsi->command >> 20) & 7; + scsi->dev_id[(scsi->command >> 16) & 0xf].lun_id = (scsi->command >> 24) & 7; + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + } + break; + + case CMD_DMA_PACING_CONTROL: + scsi->pacing = scsi->cir[2]; +// pclog("Pacing control: %i\n", scsi->pacing); + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + break; + + case CMD_FEATURE_CONTROL: +// pclog("Feature control: timeout=%is d-rate=%i\n", (scsi->command >> 16) & 0x1fff, scsi->command >> 29); + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + break; + + case CMD_INVALID_412: + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + break; + + case CMD_RESET: + if ((scsi->attention & 0xf) == 0xf) /*Adapter reset*/ + { + scsi_bus_reset(&scsi->bus); + scsi->scb_state = SCB_STATE_IDLE; + } + else /*Device reset*/ + { + } + scsi_ibm_set_irq(scsi, scsi->attention & 0x0f, IRQ_TYPE_IMM_CMD_COMPLETE); + break; + + default: + fatal("scsi_callback: Bad command %02x\n", scsi->command); + } +} + +static int wait_for_bus(scsi_bus_t *bus, int state, int req_needed) +{ + int c; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(bus); + + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) == state && (bus_state & BUS_BSY)) + { + if (!req_needed || (bus_state & BUS_REQ)) + return 1; + } + } + + return 0; +} + +static void process_scsi(scsi_ibm_t *scsi) +{ + int c; + int bytes_transferred = 0; + + switch (scsi->scsi_state) + { + case SCSI_STATE_IDLE: + break; + + case SCSI_STATE_SELECT: + scsi->cdb.last_status = 0; +// pclog("Select target ID %i\n", scsi->cdb.target_id); + scsi_bus_update(&scsi->bus, BUS_SEL | BUS_SETDATA(1 << scsi->cdb.target_id)); + if (!(scsi_bus_read(&scsi->bus) & BUS_BSY) || scsi->cdb.target_id > 6) + { +// pclog("STATE_SCSI_SELECT failed to select target %i\n", scsi->cdb.target_id); + scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + if (!scsi->cmd_timer) + scsi->cmd_timer = 1; + break; + } + + scsi_bus_update(&scsi->bus, 0); + if (!(scsi_bus_read(&scsi->bus) & BUS_BSY)) + { +// pclog("STATE_SCSI_SELECT failed to select target %i 2\n", scsi->cdb.target_id); + scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + if (!scsi->cmd_timer) + scsi->cmd_timer = 1; + break; + } + + /*Device should now be selected*/ + if (!wait_for_bus(&scsi->bus, BUS_CD, 1)) + { +// pclog("Device failed to request command\n"); + scsi->scsi_state = SCSI_STATE_SELECT_FAILED; + if (!scsi->cmd_timer) + scsi->cmd_timer = 1; + break; + } + + scsi->scsi_state = SCSI_STATE_SEND_COMMAND; + break; + + case SCSI_STATE_SELECT_FAILED: + break; + + case SCSI_STATE_SEND_COMMAND: + while (scsi->cdb.idx < scsi->cdb.len && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int bus_out; + + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + +#ifndef RELEASE_BUILD + if (!(bus_state & BUS_BSY)) + fatal("SEND_COMMAND - dropped BSY\n"); + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_CD) + fatal("SEND_COMMAND - bus phase incorrect\n"); +#endif + if (bus_state & BUS_REQ) + break; + } + if (c == 20) + { +// pclog("SEND_COMMAND timed out\n"); + break; + } + + bus_out = BUS_SETDATA(scsi->cdb.data[scsi->cdb.idx]); +// pclog(" Command send %02x %i\n", scsi->cdb.data[scsi->cdb.idx], scsi->cdb.len); + scsi->cdb.idx++; + bytes_transferred++; + + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + } + if (scsi->cdb.idx == scsi->cdb.len) + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + + case SCSI_STATE_NEXT_PHASE: + /*Wait for SCSI command to move to next phase*/ + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); +#ifndef RELEASE_BUILD + if (!(bus_state & BUS_BSY)) + fatal("NEXT_PHASE - dropped BSY waiting\n"); +#endif + if (bus_state & BUS_REQ) + { + int bus_out; +// pclog("SCSI next phase - %x\n", bus_state); + switch (bus_state & (BUS_IO | BUS_CD | BUS_MSG)) + { + case 0: +// pclog("Move to write data\n"); + scsi->scsi_state = SCSI_STATE_WRITE_DATA; + break; + + case BUS_IO: +// pclog("Move to read data\n"); + scsi->scsi_state = SCSI_STATE_READ_DATA; + break; + + case (BUS_CD | BUS_IO): +// pclog("Move to read status\n"); + scsi->scsi_state = SCSI_STATE_READ_STATUS; + break; + + case (BUS_CD | BUS_IO | BUS_MSG): +// pclog("Move to read message\n"); + scsi->scsi_state = SCSI_STATE_READ_MESSAGE; + break; + + case BUS_CD: + bus_out = BUS_SETDATA(0); + + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + break; + +#ifndef RELEASE_BUILD + default: + fatal(" Bad new phase %x\n", bus_state); +#endif + } + break; + } + } + break; + + case SCSI_STATE_END_PHASE: + /*Wait for SCSI command to move to next phase*/ + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); + + if (!(bus_state & BUS_BSY)) + { +// pclog("END_PHASE - dropped BSY waiting\n"); +// if (scsi->ccb.req_sense_len == CCB_SENSE_NONE) +// fatal("No sense data\n"); + scsi->scsi_state = SCSI_STATE_IDLE; +// pclog("End of command\n"); + if (!scsi->cmd_timer) + scsi->cmd_timer = 1; + break; + } +#ifndef RELEASE_BUILD + if (bus_state & BUS_REQ) + fatal("END_PHASE - unexpected REQ\n"); +#endif + } + break; + + case SCSI_STATE_READ_DATA: + while (scsi->scsi_state == SCSI_STATE_READ_DATA && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int d; + + for (d = 0; d < 20; d++) + { + int bus_state = scsi_bus_read(&scsi->bus); +#ifndef RELEASE_BUILD + if (!(bus_state & BUS_BSY)) + fatal("READ_DATA - dropped BSY waiting\n"); +#endif + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO) + { +// pclog("READ_DATA - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data = BUS_GETDATA(bus_state); + int bus_out = 0; + + if (scsi->cdb.data_idx < scsi->cdb.data_len) + { + if (scsi->cdb.data_pointer == -1) + scsi->int_buffer[scsi->cdb.data_idx] = data; + else + mem_writeb_phys(scsi->cdb.data_pointer + scsi->cdb.data_idx, data); + scsi->cdb.data_idx++; + + if ((scsi->scb.enable & ENABLE_PT) && scsi->cdb.data_idx == scsi->cdb.data_len) + sg_fetch_next(scsi); + } + scsi->cdb.bytes_transferred++; + +// pclog("Read data %02x %i %06x\n", data, scsi->cdb.data_idx, scsi->cdb.data_pointer + scsi->cdb.data_idx); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + break; + } + } + + bytes_transferred++; + } + break; + + case SCSI_STATE_WRITE_DATA: + while (scsi->scsi_state == SCSI_STATE_WRITE_DATA && bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) + { + int d; + + for (d = 0; d < 20; d++) + { + int bus_state = scsi_bus_read(&scsi->bus); +#ifndef RELEASE_BUILD + if (!(bus_state & BUS_BSY)) + fatal("WRITE_DATA - dropped BSY waiting\n"); +#endif + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != 0) + { +// pclog("WRITE_DATA - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t data;// = BUS_GETDATA(bus_state); + int bus_out; + + if (scsi->cdb.data_idx < scsi->cdb.data_len) + { + if (scsi->cdb.data_pointer == -1) + data = scsi->int_buffer[scsi->cdb.data_idx]; + else + data = mem_readb_phys(scsi->cdb.data_pointer + scsi->cdb.data_idx); + + scsi->cdb.data_idx++; + if ((scsi->scb.enable & ENABLE_PT) && scsi->cdb.data_idx == scsi->cdb.data_len) + sg_fetch_next(scsi); + } + else + data = 0xff; + scsi->cdb.bytes_transferred++; + +// pclog("Write data %02x %i\n", data, scsi->cdb.data_idx); + bus_out = BUS_SETDATA(data); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + break; + } + } + + bytes_transferred++; + } +// if (scsi->cdb.data_idx == scsi->cdb.data_len) +// scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + + case SCSI_STATE_READ_STATUS: + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); +#ifndef RELEASE_BUILD + if (!(bus_state & BUS_BSY)) + fatal("READ_STATUS - dropped BSY waiting\n"); +#endif + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO)) + { +// pclog("READ_STATUS - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t status = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read status %02x\n", status); + scsi->cdb.last_status = status; + + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + } + break; + + case SCSI_STATE_READ_MESSAGE: + for (c = 0; c < 20; c++) + { + int bus_state = scsi_bus_read(&scsi->bus); +#ifndef RELEASE_BUILD + if (!(bus_state & BUS_BSY)) + fatal("READ_MESSAGE - dropped BSY waiting\n"); +#endif + if ((bus_state & (BUS_IO | BUS_CD | BUS_MSG)) != (BUS_CD | BUS_IO | BUS_MSG)) + { +// pclog("READ_MESSAGE - changed phase\n"); + scsi->scsi_state = SCSI_STATE_NEXT_PHASE; + break; + } + + if (bus_state & BUS_REQ) + { + uint8_t msg = BUS_GETDATA(bus_state); + int bus_out = 0; + +// pclog("Read message %02x\n", msg); + scsi_bus_update(&scsi->bus, bus_out | BUS_ACK); + scsi_bus_update(&scsi->bus, bus_out & ~BUS_ACK); + + switch (msg) + { + case MSG_COMMAND_COMPLETE: + scsi->scsi_state = SCSI_STATE_END_PHASE; + break; +#ifndef RELEASE_BUILD + default: + fatal("READ_MESSAGE - unknown message %02x\n", msg); +#endif + } + break; + } + } + break; + +#ifndef RELEASE_BUILD + default: + fatal("Unknown SCSI_state %d\n", scsi->scsi_state); +#endif + } +} + +static void scsi_callback(void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + + timer_advance_u64(&scsi->callback_timer, POLL_TIME); + +// pclog("poll %i\n", scsi->cmd_state); + if (scsi->cmd_timer) + { + scsi->cmd_timer--; + if (!scsi->cmd_timer) + process_ibm_cmd(scsi); + } + if (scsi->attention_waiting && + (scsi->scb_state == SCB_STATE_IDLE || (scsi->attention_pending & 0xf0) == 0xe0)) + { + scsi->attention_waiting--; + if (!scsi->attention_waiting) + { +// pclog("Process attention request\n"); + scsi->attention = scsi->attention_pending; + scsi->status &= ~STATUS_BUSY; + scsi->cir[0] = scsi->cir_pending[0]; + scsi->cir[1] = scsi->cir_pending[1]; + scsi->cir[2] = scsi->cir_pending[2]; + scsi->cir[3] = scsi->cir_pending[3]; + scsi->cir_status = 0; + + switch (scsi->attention >> 4) + { + case 0x1: /*Immediate command*/ + scsi->cmd_status = 0xa; + scsi->command = scsi->cir[0] | (scsi->cir[1] << 8) | (scsi->cir[2] << 16) | (scsi->cir[3] << 24); + switch (scsi->command & CMD_MASK) + { + case CMD_ASSIGN: + case CMD_DMA_PACING_CONTROL: + case CMD_FEATURE_CONTROL: + case CMD_INVALID_412: + case CMD_RESET: + process_immediate_command(scsi); + break; + +#ifndef RELEASE_BUILD + default: + fatal("Unknown immediate command %08x\n", scsi->command); +#endif + } + break; + + case 0x3: case 0x4: case 0xf: /*Start SCB*/ + scsi->cmd_status = 0x1; + scsi->scb_addr = scsi->cir[0] | (scsi->cir[1] << 8) | (scsi->cir[2] << 16) | (scsi->cir[3] << 24); + scsi->scb_state = SCB_STATE_START; + scsi->scb_id = scsi->attention & 0xf; + scsi->cmd_timer = SCSI_TIME*2; +// pclog("Start SCB at %08x\n", scsi->scb_addr); + break; + + case 5: /*Invalid*/ + case 0xa: /*Invalid*/ + scsi->in_invalid = 1; + scsi->cmd_timer = SCSI_TIME*2; + break; + + case 0xe: /*EOI*/ + scsi->irq_status = 0; + scsi_clear_irq(scsi, scsi->attention & 0xf); + break; +#ifndef RELEASE_BUILD + default: + fatal("Attention Register 5 %02x\n", scsi->attention); +#endif + } + } + } + process_scsi(scsi); +} + +static uint8_t scsi_ibm_mca_read(int port, void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + +// pclog("scsi_mca_read: port=%04x %02x %04x:%04x\n", port, scsi->pos_regs[port & 7], CS,cpu_state.pc); + + return scsi->pos_regs[port & 7]; +} + +static void scsi_ibm_mca_write(int port, uint8_t val, void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + + if (port < 0x102) + return; + +// pclog("scsi_mca_write: port=%04x val=%02x %04x:%04x\n", port, val, CS, cpu_state.pc); + + io_removehandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, scsi_read, scsi_readw, NULL, scsi_write, scsi_writew, NULL, scsi); + mem_mapping_disable(&scsi->bios_rom.mapping); + + scsi->pos_regs[port & 7] = val; + + if (scsi->pos_regs[2] & 1) + { +// pclog(" scsi io = %04x\n", (((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540); + io_sethandler((((scsi->pos_regs[2] >> 1) & 7) * 8) + 0x3540, 0x0008, scsi_read, scsi_readw, NULL, scsi_write, scsi_writew, NULL, scsi); + if ((scsi->pos_regs[2] & 0xf0) != 0xf0) + { + mem_mapping_enable(&scsi->bios_rom.mapping); + mem_mapping_set_addr(&scsi->bios_rom.mapping, ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, 0x8000); +// pclog("SCSI BIOS ROM at %05x %02x\n", ((scsi->pos_regs[2] >> 4) * 0x2000) + 0xc0000, scsi->pos_regs[2]); + } + } +} + +static void scsi_ibm_reset(void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + +// pclog("scsi_ibm_reset\n"); + scsi->in_reset = 2; + scsi->cmd_timer = SCSI_TIME * 50; + scsi->status = STATUS_BUSY; + scsi->scsi_state = SCSI_STATE_IDLE; + scsi->scb_state = SCB_STATE_IDLE; + scsi->in_invalid = 0; + scsi->attention_waiting = 0; + scsi->basic_ctrl = 0; + scsi_bus_reset(&scsi->bus); +} + +static void *scsi_ibm_init() +{ + int c; + scsi_ibm_t *scsi = malloc(sizeof(scsi_ibm_t)); + memset(scsi, 0, sizeof(scsi_ibm_t)); + + rom_init_interleaved(&scsi->bios_rom, "92F2244.U68", "92F2245.U69", 0xc8000, 0x8000, 0x7fff, 0x4000, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&scsi->bios_rom.mapping); + + timer_add(&scsi->callback_timer, scsi_callback, scsi, 1); + + mca_add(scsi_ibm_mca_read, scsi_ibm_mca_write, scsi_ibm_reset, scsi); + + scsi->pos_regs[0] = 0xff; + scsi->pos_regs[1] = 0x8e; + + scsi->in_reset = 2; + scsi->cmd_timer = SCSI_TIME * 50; + scsi->status = STATUS_BUSY; + + scsi_bus_init(&scsi->bus); + +/* for (c = 0; c < 7; c++) + { + scsi->dev_id[c].phys_id = c; + scsi->dev_id[c].lun_id = 0; + }*/ + for (c = 0; c < 15; c++) + scsi->dev_id[c].phys_id = -1; + scsi->dev_id[15].phys_id = 7; + + return scsi; +} + +static void scsi_ibm_close(void *p) +{ + scsi_ibm_t *scsi = (scsi_ibm_t *)p; + + free(scsi); +} + +static int scsi_ibm_available() +{ + return rom_present("92F2244.U68") && rom_present("92F2245.U69"); +} + +device_t scsi_ibm_device = +{ + "IBM SCSI Adapter with Cache (MCA)", + DEVICE_MCA, + scsi_ibm_init, + scsi_ibm_close, + scsi_ibm_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/scsi_ibm.h b/src/scsi_ibm.h new file mode 100644 index 0000000..b528486 --- /dev/null +++ b/src/scsi_ibm.h @@ -0,0 +1 @@ +extern device_t scsi_ibm_device; diff --git a/src/scsi_zip.c b/src/scsi_zip.c new file mode 100644 index 0000000..51dacb2 --- /dev/null +++ b/src/scsi_zip.c @@ -0,0 +1,1222 @@ +#include +#include +#include +#include +#include "ibm.h" +#include "hdd_file.h" +#include "ide.h" +#include "ide_atapi.h" +#include "scsi.h" +#include "scsi_zip.h" +#include "timer.h" + +#define BUFFER_SIZE (256*1024) + +#define ZIP_SECTORS (96*2048) + +#define RW_DELAY (TIMER_USEC * 500) + +#define SCSI_IOMEGA_SENSE 0x06 +#define SCSI_IOMEGA_EJECT 0x0d /*ATAPI only?*/ + + /*Page 1 - 0x58 bytes*/ + /*Page 2 (Disk Status Page) - 0x3d bytes + Byte 21 bits 0-3 - protection code + 0 - not write-protected + 2 - write-protected + 3 - password write-protected + Bytes 22 - 61 - serial number + */ +#define SCSI_IOMEGA_SET_PROTECTION_MODE 0x0c + /*cmd[1] = mode + cmd[6-x] = password*/ + +#define ATAPI_READ_FORMAT_CAPACITIES 0x23 + +enum +{ + CMD_POS_IDLE = 0, + CMD_POS_WAIT, + CMD_POS_START_SECTOR, + CMD_POS_TRANSFER +}; + +typedef struct scsi_zip_data +{ + int blocks; + + int cmd_pos, new_cmd_pos; + + int addr, len; + int sector_pos; + + uint8_t buf[512]; + + uint8_t status; + + uint8_t data_in[BUFFER_SIZE]; + uint8_t data_out[BUFFER_SIZE]; + int data_pos_read, data_pos_write; + + int bytes_received, bytes_required; + + hdd_file_t hdd; + int disc_loaded; + int disc_changed; + + int sense_key, asc, ascq; + + int hd_id; + + pc_timer_t callback_timer; + + scsi_bus_t *bus; + + int is_atapi; + atapi_device_t *atapi_dev; + + int read_only; + + int pio_mode, mdma_mode; +} scsi_zip_data; + +static scsi_zip_data *zip_data; + +#define CHECK_READY 2 + +static uint8_t scsi_zip_cmd_flags[0x100] = +{ + [SCSI_TEST_UNIT_READY] = CHECK_READY, + [SCSI_REQUEST_SENSE] = 0, + [SCSI_READ_6] = CHECK_READY, + [SCSI_INQUIRY] = 0, + [SCSI_MODE_SELECT_6] = 0, + [SCSI_MODE_SENSE_6] = 0, + [SCSI_START_STOP_UNIT] = 0, + [SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL] = CHECK_READY, + [SCSI_READ_10] = CHECK_READY, + [SCSI_SEEK_6] = CHECK_READY, + [SCSI_SEEK_10] = CHECK_READY, + [SCSI_IOMEGA_SENSE] = 0, + [SCSI_REZERO_UNIT] = CHECK_READY, + [SCSI_READ_CAPACITY_10] = CHECK_READY, + [SCSI_WRITE_6] = CHECK_READY, + [SCSI_WRITE_10] = CHECK_READY, + [SCSI_WRITE_AND_VERIFY] = CHECK_READY, + [SCSI_VERIFY_10] = CHECK_READY, + [SCSI_FORMAT] = CHECK_READY, + [SCSI_RESERVE] = 0, + [SCSI_RELEASE] = 0, + [SEND_DIAGNOSTIC] = 0 + +}; + +void zip_load(char *fn) +{ + if (zip_data) + { + FILE *f; + int read_only = 0; + + f = fopen(fn, "rb+"); + if (!f) + { + f = fopen(fn, "rb"); + read_only = 1; + } + if (f) + { + int size; + + fseek(f, -1, SEEK_END); + size = ftell(f)+1; + fclose(f); + + if (size != ZIP_SECTORS*512) + { + warning("File is incorrect size for Zip image\nMust be exactly %i bytes\n", ZIP_SECTORS*512); + return; + } + + if (zip_data->disc_loaded) + hdd_close(&zip_data->hdd); + + hdd_load_ext(&zip_data->hdd, fn, 2048,1,96, read_only); + + if (zip_data->hdd.f) + { + zip_data->disc_loaded = 1; + zip_data->disc_changed = 1; + zip_data->read_only = read_only; + } + } + } +} + +void zip_eject() +{ + if (zip_data) + { + if (zip_data->disc_loaded) + { + hdd_close(&zip_data->hdd); + zip_data->disc_loaded = 0; + } + } +} + +int zip_loaded() +{ + if (zip_data) + return zip_data->disc_loaded; + return 0; +} + +static void scsi_zip_callback(void *p) +{ + scsi_zip_data *data = p; + + if (data->cmd_pos == CMD_POS_WAIT) + { + data->cmd_pos = data->new_cmd_pos; + scsi_bus_kick(data->bus); + } +} + +static void *scsi_zip_init(scsi_bus_t *bus, int id) +{ + scsi_zip_data *data = malloc(sizeof(scsi_zip_data)); + memset(data, 0, sizeof(scsi_zip_data)); + + data->disc_loaded = 0; + + data->hd_id = id; + data->bus = bus; + timer_add(&data->callback_timer, scsi_zip_callback, data, 0); + + zip_data = data; + return data; +} + +static void *scsi_zip_atapi_init(scsi_bus_t *bus, int id, atapi_device_t *atapi_dev) +{ + scsi_zip_data *data = scsi_zip_init(bus, id); + + data->is_atapi = 1; + data->atapi_dev = atapi_dev; + + return data; +} + +static void scsi_zip_close(void *p) +{ + scsi_zip_data *data = p; + + if (data->disc_loaded) + hdd_close(&data->hdd); + free(data); + zip_data = NULL; +} + +static void scsi_zip_reset(void *p) +{ + scsi_zip_data *data = p; + + timer_disable(&data->callback_timer); + data->cmd_pos = CMD_POS_IDLE; +} + +static int scsi_add_data(uint8_t val, void *p) +{ + scsi_zip_data *data = p; + +// pclog("scsi_add_data : %04x %02x\n", data->data_pos_write, val); + + data->data_in[data->data_pos_write++] = val; + +// if (data->bus_out & BUS_REQ) +// return -1; + +// data->bus_out = (data->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ; + + return 0; +} + +static int scsi_get_data(void *p) +{ + scsi_zip_data *data = p; + uint8_t val = data->data_out[data->data_pos_read++]; + + if (data->data_pos_read > BUFFER_SIZE) + fatal("scsi_get_data beyond buffer limits\n"); + + return val; +} + +static void scsi_zip_illegal(scsi_zip_data *data) +{ + data->status = STATUS_CHECK_CONDITION; + data->sense_key = KEY_ILLEGAL_REQ; + data->asc = ASC_INVALID_LUN; + data->ascq = 0; +} + +static void scsi_zip_cmd_error(scsi_zip_data *data, int sensekey, int asc, int ascq) +{ + data->status = STATUS_CHECK_CONDITION; + data->sense_key = sensekey; + data->asc = asc; + data->ascq = ascq; +} + +#define add_data_len(v) \ + do \ + { \ + if (i < len) \ + scsi_add_data(v, data); \ + i++; \ + } while (0) + + +static int scsi_zip_command(uint8_t *cdb, void *p) +{ + scsi_zip_data *data = p; + int /*addr, */len; + int i = 0, c; + int desc; + int bus_state = 0; + + if (data->cmd_pos == CMD_POS_IDLE) + pclog("SCSI ZIP command %02x %i %p\n", cdb[0], data->disc_loaded, data); + data->status = STATUS_GOOD; + data->data_pos_read = data->data_pos_write = 0; + + if ((cdb[0] != SCSI_REQUEST_SENSE/* && cdb[0] != SCSI_INQUIRY*/) && (cdb[1] & 0xe0)) + { + pclog("non-zero LUN\n"); + /*Non-zero LUN - abort command*/ + scsi_zip_illegal(data); + bus_state = BUS_CD | BUS_IO; + return bus_state; + } + + if ((scsi_zip_cmd_flags[cdb[0]] & CHECK_READY) && !data->disc_loaded) + { + pclog("Disc not loaded\n"); + scsi_zip_cmd_error(data, KEY_NOT_READY, ASC_MEDIUM_NOT_PRESENT, 0); + bus_state = BUS_CD | BUS_IO; + return bus_state; + } + if ((scsi_zip_cmd_flags[cdb[0]] & CHECK_READY) && data->disc_changed) + { + pclog("Disc changed\n"); + scsi_zip_cmd_error(data, KEY_UNIT_ATTENTION, ASC_MEDIUM_MAY_HAVE_CHANGED, 0); + data->disc_changed = 0; + bus_state = BUS_CD | BUS_IO; + return bus_state; + } + + switch (cdb[0]) + { + case SCSI_TEST_UNIT_READY: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_IOMEGA_SENSE: + len = cdb[4]; + if (cdb[2] == 1) + { + pclog("SCSI_IOMEGA_SENSE 1 %02x\n", len); + add_data_len(0x58); + add_data_len(0); + /*This page is related to disc health status - setting this page to 0 + makes disc health read as 'marginal'*/ + for (c = 2; c < 0x58; c++) + add_data_len(0xff); + while (i < len) + add_data_len(0); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + } + else if (cdb[2] == 2) + { + pclog("SCSI_IOMEGA_SENSE 2 %02x\n", len); + add_data_len(0x3d); + add_data_len(0); + for (c = 0; c < 19; c++) + add_data_len(0); + if (data->read_only) + add_data_len(2); + else + add_data_len(0); + for (c = 0; c < 39; c++) + add_data_len(0); + while (i < len) + add_data_len(0); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + } + else + { + pclog("IOMEGA_SENSE %02x %02x\n", cdb[2], len); + scsi_zip_illegal(data); + bus_state = BUS_CD | BUS_IO; + } + break; + + case SCSI_REZERO_UNIT: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_REQUEST_SENSE: + desc = cdb[1] & 1; + len = cdb[4]; + + if (!desc) + { + add_data_len(0x70); + add_data_len(0); + add_data_len(data->sense_key); /*Sense key*/ + add_data_len(0); /*Information (4 bytes)*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); /*Additional sense length*/ + add_data_len(0); /*Command specific information (4 bytes)*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(data->asc); /*ASC*/ + add_data_len(data->ascq); /*ASCQ*/ + add_data_len(0); /*FRU code*/ + add_data_len(0); /*Sense key specific (3 bytes)*/ + add_data_len(0); + add_data_len(0); + } + else + { + add_data_len(0x72); + add_data_len(data->sense_key); /*Sense Key*/ + add_data_len(data->asc); /*ASC*/ + add_data_len(data->ascq); /*ASCQ*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); /*additional sense length*/ + } + + data->sense_key = data->asc = data->ascq = 0; + + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_INQUIRY: + len = cdb[4] | (cdb[3] << 8); +// pclog("INQUIRY %d %02x %02x %02x %02x %02x %02x %i\n", len, cdb[0],cdb[1],cdb[2],cdb[3],cdb[4],cdb[5], data->hd_id); + + if (cdb[1] & 0xe0) + { + add_data_len(0 | (3 << 5)); /*No physical device on this LUN*/ + } + else + { + add_data_len(0 | (0 << 5)); /*Hard disc*/ + } + add_data_len(0x80); /*Removeable device*/ + if (data->is_atapi) + { + add_data_len(0); /*Not ANSI compliant*/ + add_data_len(0x21); /*ATAPI compliant*/ + } + else + { + add_data_len(2); /*SCSI-2 compliant*/ + add_data_len(0x02); + } +// add_data_len(0); /*No version*/ +// add_data_len(2); /*Response data*/ + add_data_len(0); /*Additional length*/ + add_data_len(0); + add_data_len(0); + add_data_len(2); + + add_data_len('I'); + add_data_len('O'); + add_data_len('M'); + add_data_len('E'); + add_data_len('G'); + add_data_len('A'); + add_data_len(' '); + add_data_len(' '); + + add_data_len('Z'); + add_data_len('I'); + add_data_len('P'); + add_data_len(' '); + add_data_len('1'); + add_data_len('0'); + add_data_len('0'); + add_data_len(' '); + + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + add_data_len(' '); + + add_data_len('E'); /*Product revision level*/ + add_data_len('.'); + add_data_len('0'); + add_data_len('8'); + + add_data_len(0); /*Drive serial number*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Vendor unique*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Vendor descriptor*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + add_data_len(0); /*Reserved*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_MODE_SENSE_6: + case SCSI_MODE_SENSE_10: + pclog("MODE_SENSE_6 %02x %02x\n", cdb[2], cdb[4]); + if ((cdb[2] & 0x3f) != 0x01 && (cdb[2] & 0x3f) != 0x02 && (cdb[2] & 0x3f) != 0x2f && (cdb[2] & 0x3f) != 0x3f) + { + pclog("Invalid MODE_SENSE\n"); + scsi_zip_cmd_error(data, KEY_ILLEGAL_REQ, ASC_INV_FIELD_IN_CMD_PACKET, 0); + bus_state = BUS_CD | BUS_IO; + break; + } + if (cdb[0] == SCSI_MODE_SENSE_6) + { + len = cdb[4]; + + add_data_len(0); + add_data_len(0); + + if (data->read_only) + add_data_len(0x80); + else + add_data_len(0); + add_data_len(0x08); + } + else + { + len = cdb[8] | (cdb[7] << 8); + + add_data_len(0); + add_data_len(0); + add_data_len(0); + + if (data->read_only) + add_data_len(0x80); + else + add_data_len(0); + + add_data_len(0); + add_data_len(0); + + add_data_len(0); + add_data_len(0x08); + } + + add_data_len((ZIP_SECTORS >> 24) & 0xff); + add_data_len((ZIP_SECTORS >> 16) & 0xff); + add_data_len((ZIP_SECTORS >> 8) & 0xff); + add_data_len( ZIP_SECTORS & 0xff); + add_data_len((512 >> 24) & 0xff); + add_data_len((512 >> 16) & 0xff); + add_data_len((512 >> 8) & 0xff); + add_data_len( 512 & 0xff); + + if ((cdb[2] & 0x3f) == 0x01 || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(0x01); + add_data_len(0x0a); + add_data_len(0xc8); /*Automatic read and write allocation enable, most expedient error recovery*/ + add_data_len(22); /*Read retry count = 22*/ + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(90); /*Write retry count = 90*/ + add_data_len(0); + add_data_len(20512 >> 8); + add_data_len(20512 & 0xff); + } + + if ((cdb[2] & 0x3f) == 0x02 || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(0x02); + add_data_len(0x0e); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + add_data_len(0); + } + + if ((cdb[2] & 0x3f) == 0x2f || (cdb[2] & 0x3f) == 0x3f) + { + add_data_len(0x2f); + add_data_len(0x04); + add_data_len(0x5c); + add_data_len(0x0f); + add_data_len(0xff); + add_data_len(0x0f); + } + + while (i < len) + add_data_len(0); + + len = data->data_pos_write; + if (cdb[0] == SCSI_MODE_SENSE_6) + { + data->data_in[0] = len - 1; + } + else + { + data->data_in[0] = (len - 2) >> 8; + data->data_in[1] = (len - 2) & 255; + } + +// scsi_illegal_field(); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_CAPACITY_10: +// len = 96 * 2048; + scsi_add_data((ZIP_SECTORS >> 24) & 0xff, data); + scsi_add_data((ZIP_SECTORS >> 16) & 0xff, data); + scsi_add_data((ZIP_SECTORS >> 8) & 0xff, data); + scsi_add_data( ZIP_SECTORS & 0xff, data); + scsi_add_data((512 >> 24) & 0xff, data); + scsi_add_data((512 >> 16) & 0xff, data); + scsi_add_data((512 >> 8) & 0xff, data); + scsi_add_data( 512 & 0xff, data); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_6: +// pclog("SCSI_READ_6 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + + if (data->cmd_pos == CMD_POS_IDLE) + { + readflash_set(READFLASH_HDC, data->hd_id); + data->addr = cdb[3] | (cdb[2] << 8) | ((cdb[1] & 0x1f) << 16); + data->len = cdb[4]; + if (!data->len) + data->len = 256; +// pclog("SCSI_READ_6: addr=%08x len=%04x\n", data->addr, data->len); + + data->cmd_pos = CMD_POS_WAIT; + timer_set_delay_u64(&data->callback_timer, RW_DELAY); + data->new_cmd_pos = CMD_POS_START_SECTOR; + data->sector_pos = 0; + + bus_state = BUS_CD; + atapi_set_transfer_granularity(data->atapi_dev, 512); + break; + } +// else +// pclog("SCSI_READ_6 continue addr=%08x len=%04x sector_pos=%02x\n", data->addr, data->len, data->sector_pos); + while (data->len) + { + if (data->cmd_pos == CMD_POS_START_SECTOR) + { + hdd_read_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + } + + data->cmd_pos = CMD_POS_TRANSFER; + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_add_data(data->buf[data->sector_pos], data); + + if (ret == -1) + { + fatal("scsi_add_data -1\n"); + break; + } + if (ret & 0x100) + { + fatal("scsi_add_data 0x100\n"); + data->len = 1; + break; + } + } + data->cmd_pos = CMD_POS_START_SECTOR; + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_READ_10: +// pclog("SCSI_READ_10 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + + if (data->cmd_pos == CMD_POS_IDLE) + { + readflash_set(READFLASH_HDC, data->hd_id); + data->addr = cdb[5] | (cdb[4] << 8) | (cdb[3] << 16) | (cdb[2] << 24); + data->len = cdb[8] | (cdb[7] << 8); +// pclog("SCSI_READ_10: addr=%08x len=%04x\n", data->addr, data->len); + + data->cmd_pos = CMD_POS_WAIT; + timer_set_delay_u64(&data->callback_timer, RW_DELAY); + data->new_cmd_pos = CMD_POS_START_SECTOR; + data->sector_pos = 0; + + bus_state = BUS_CD; + atapi_set_transfer_granularity(data->atapi_dev, 512); + break; + } +// else +// pclog("SCSI_READ_10 continue addr=%08x len=%04x sector_pos=%02x\n", data->addr, data->len, data->sector_pos); + while (data->len) + { + if (data->cmd_pos == CMD_POS_START_SECTOR) + { + hdd_read_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + } + data->cmd_pos = CMD_POS_TRANSFER; + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_add_data(data->buf[data->sector_pos], data); +// pclog("SCSI_READ_10 sector_pos=%i\n", data->sector_pos); + if (ret == -1) + { + fatal("scsi_add_data -1\n"); + break; + } + if (ret & 0x100) + { + fatal("scsi_add_data 0x100\n"); + data->len = 1; + break; + } + } + data->cmd_pos = CMD_POS_START_SECTOR; + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + break; + + case SCSI_WRITE_6: + if (data->read_only) + { + pclog("zip read only\n"); + scsi_zip_cmd_error(data, KEY_DATA_PROTECT, ASC_WRITE_PROTECT, 0); + bus_state = BUS_CD | BUS_IO; + break; + } +// pclog("SCSI_WRITE_6 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_IDLE) + { + data->addr = cdb[3] | (cdb[2] << 8) | ((cdb[1] & 0x1f) << 16); + data->len = cdb[4]; + if (!data->len) + data->len = 256; + readflash_set(READFLASH_HDC, data->hd_id); +// pclog("SCSI_WRITE_6: addr=%08x len=%04x\n", data->addr, data->len); + data->bytes_required = data->len * 512; + + data->cmd_pos = CMD_POS_WAIT; + timer_set_delay_u64(&data->callback_timer, RW_DELAY); + data->new_cmd_pos = CMD_POS_TRANSFER; + data->sector_pos = 0; + + bus_state = BUS_CD; + atapi_set_transfer_granularity(data->atapi_dev, 512); + break; + } + if (data->cmd_pos == CMD_POS_TRANSFER && data->bytes_received != data->bytes_required) + { + bus_state = 0; + break; + } + + while (data->len) + { + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_get_data(data); + if (ret == -1) + { + fatal("scsi_get_data -1\n"); + break; + } + data->buf[data->sector_pos] = ret & 0xff; + if (ret & 0x100) + { + fatal("scsi_get_data 0x100\n"); + data->len = 1; + break; + } + } + + hdd_write_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_WRITE_10: + case SCSI_WRITE_AND_VERIFY: + if (data->read_only) + { + pclog("zip read only\n"); + scsi_zip_cmd_error(data, KEY_DATA_PROTECT, ASC_WRITE_PROTECT, 0); + bus_state = BUS_CD | BUS_IO; + break; + } +// pclog("SCSI_WRITE_10 %i\n", data->cmd_pos); + if (data->cmd_pos == CMD_POS_WAIT) + { + bus_state = BUS_CD; + break; + } + if (data->cmd_pos == CMD_POS_IDLE) + { + data->addr = cdb[5] | (cdb[4] << 8) | (cdb[3] << 16) | (cdb[2] << 24); + data->len = cdb[8] | (cdb[7] << 8); + readflash_set(READFLASH_HDC, data->hd_id); +// pclog("SCSI_WRITE_10: addr=%08x len=%04x\n", data->addr, data->len); + data->bytes_required = data->len * 512; + + data->cmd_pos = CMD_POS_WAIT; + timer_set_delay_u64(&data->callback_timer, RW_DELAY); + data->new_cmd_pos = CMD_POS_TRANSFER; + data->sector_pos = 0; + + bus_state = BUS_CD; + atapi_set_transfer_granularity(data->atapi_dev, 512); + break; + } + if (data->cmd_pos == CMD_POS_TRANSFER && data->bytes_received != data->bytes_required) + { + bus_state = 0; + break; + } + + while (data->len) + { + for (; data->sector_pos < 512; data->sector_pos++) + { + int ret = scsi_get_data(data); +// pclog("SCSI_WRITE_10 sector_pos=%i\n", data->sector_pos); + if (ret == -1) + { + fatal("scsi_get_data -1\n"); + break; + } + data->buf[data->sector_pos] = ret & 0xff; + if (ret & 0x100) + { + fatal("scsi_get_data 0x100\n"); + data->len = 1; + break; + } + } + + hdd_write_sectors(&data->hdd, data->addr, 1, data->buf); + readflash_set(READFLASH_HDC, data->hd_id); + + data->sector_pos = 0; + data->len--; + data->addr++; + } + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; +// output = 3; + break; + + case SCSI_VERIFY_10: + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_MODE_SELECT_6: + if (!data->bytes_received) + { + data->bytes_required = cdb[4]; +// pclog("SCSI_MODE_SELECT_6 bytes_required=%i\n", data->bytes_required); + bus_state = 0; + break; + } +// pclog("SCSI_MODE_SELECT_6 complete\n"); + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_FORMAT: + if (data->read_only) + { + scsi_zip_cmd_error(data, KEY_DATA_PROTECT, ASC_WRITE_PROTECT, 0); + bus_state = BUS_CD | BUS_IO; + break; + } + readflash_set(READFLASH_HDC, 0); + hdd_format_sectors(&data->hdd, 0, ZIP_SECTORS); + + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_START_STOP_UNIT: + /*if ((cdb[4] & (START_STOP_LOEJ | START_STOP_START)) == START_STOP_LOEJ)*/ + /*This is incorrect based on the SCSI spec, but it's what the Iomega Win9x drivers send to eject a disc*/ + if ((cdb[4] & (START_STOP_LOEJ | START_STOP_START)) == 0) + zip_eject(); + bus_state = BUS_CD | BUS_IO; + break; + + /*These aren't really meaningful in a single initiator system, so just return*/ + case SCSI_RESERVE: + case SCSI_RELEASE: + bus_state = BUS_CD | BUS_IO; + break; + + case SCSI_SEEK_6: + case SCSI_SEEK_10: + bus_state = BUS_CD | BUS_IO; + break; + + case SEND_DIAGNOSTIC: + if (cdb[1] & (1 << 2)) + { + /*Self-test*/ + /*Always passes*/ + bus_state = BUS_CD | BUS_IO; + } + else + { + /*Treat all other diagnostic requests as illegal*/ + scsi_zip_illegal(data); + bus_state = BUS_CD | BUS_IO; + } + break; + + case SCSI_IOMEGA_EJECT: + if (data->is_atapi) + zip_eject(); + else + scsi_zip_illegal(data); + + bus_state = BUS_CD | BUS_IO; + break; + + case ATAPI_READ_FORMAT_CAPACITIES: + if (data->is_atapi) + { + len = cdb[8] | (cdb[7] << 8); + + /*List header*/ + scsi_add_data(0, data); + scsi_add_data(0, data); + scsi_add_data(0, data); + scsi_add_data(16, data); /*list length*/ + + /*Current/Maximum capacity header*/ + scsi_add_data((ZIP_SECTORS >> 24) & 0xff, data); + scsi_add_data((ZIP_SECTORS >> 16) & 0xff, data); + scsi_add_data((ZIP_SECTORS >> 8) & 0xff, data); + scsi_add_data( ZIP_SECTORS & 0xff, data); + if (data->disc_loaded) + scsi_add_data(2, data); /*Formatted media - current media capacity*/ + else + scsi_add_data(3, data); /*Maximum formattable capacity*/ + scsi_add_data(512 >> 16, data); + scsi_add_data(512 >> 8, data); + scsi_add_data(512 & 0xff, data); + + /*Formattable capacity descriptor*/ + scsi_add_data((ZIP_SECTORS >> 24) & 0xff, data); + scsi_add_data((ZIP_SECTORS >> 16) & 0xff, data); + scsi_add_data((ZIP_SECTORS >> 8) & 0xff, data); + scsi_add_data( ZIP_SECTORS & 0xff, data); + scsi_add_data(0, data); + scsi_add_data(512 >> 16, data); + scsi_add_data(512 >> 8, data); + scsi_add_data(512 & 0xff, data); + + data->cmd_pos = CMD_POS_IDLE; + bus_state = BUS_IO; + } + else + { + scsi_zip_illegal(data); + bus_state = BUS_CD | BUS_IO; + } + break; + + default: + pclog("Bad SCSI ZIP command %02x\n", cdb[0]); + scsi_zip_illegal(data); + bus_state = BUS_CD | BUS_IO; + break; + } + + return bus_state; +} + +static uint8_t scsi_zip_read(void *p) +{ + scsi_zip_data *data = p; + + return data->data_in[data->data_pos_read++]; +} + +static void scsi_zip_write(uint8_t val, void *p) +{ + scsi_zip_data *data = p; + + data->data_out[data->data_pos_write++] = val; + + data->bytes_received++; + + if (data->data_pos_write > BUFFER_SIZE) + fatal("Exceeded data_out buffer size\n"); +} + +static int scsi_zip_read_complete(void *p) +{ + scsi_zip_data *data = p; + + return (data->data_pos_read == data->data_pos_write); +} +static int scsi_zip_write_complete(void *p) +{ + scsi_zip_data *data = p; + + return (data->bytes_received == data->bytes_required); +} + +static void scsi_zip_start_command(void *p) +{ + scsi_zip_data *data = p; + + data->bytes_received = 0; + data->bytes_required = 0; + data->data_pos_read = data->data_pos_write = 0; +} + +static uint8_t scsi_zip_get_status(void *p) +{ + scsi_zip_data *data = p; + + return data->status; +} + +static uint8_t scsi_zip_get_sense_key(void *p) +{ + scsi_zip_data *data = p; + + return data->sense_key; +} + +static int scsi_zip_get_bytes_required(void *p) +{ + scsi_zip_data *data = p; + + return data->bytes_required - data->bytes_received; +} + +static void scsi_zip_atapi_identify(uint16_t *buffer, void *p) +{ + scsi_zip_data *data = p; + + memset(buffer, 0, 512); + + buffer[0] = 0x8000 | (0<<8) | 0x80 | (2<<5); /* ATAPI device, direct-access device, removable media, accelerated DRQ */ + ide_padstr((char *)(buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *)(buffer + 23), "E.08", 8); /* Firmware */ + ide_padstr((char *)(buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ + buffer[49] = 0x300; /*DMA and LBA supported*/ + buffer[51] = 120; + buffer[52] = 120; + buffer[53] = 2; /*Words 64-70 are valid*/ + buffer[62] = 0x0000; + buffer[63] = 0x0003 | (0x100 << data->mdma_mode); /*Multi-word DMA 0 & 1*/ + buffer[64] = 0x0001; /*PIO Mode 3*/ + if (data->pio_mode >= 3) + buffer[64] |= (0x100 << (data->pio_mode - 3)); + buffer[65] = 120; /*Minimum multi-word cycle time*/ + buffer[66] = 120; /*Recommended multi-word cycle time*/ + buffer[67] = 120; /*Minimum PIO cycle time*/ + buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ +} + +static int scsi_zip_atapi_set_feature(uint8_t feature, uint8_t val, void *p) +{ + scsi_zip_data *data = p; + + switch (feature) + { + case FEATURE_SET_TRANSFER_MODE: + if (!(val & 0xfe)) + { + /*Default transfer mode*/ + data->pio_mode = 0; + return 1; + } + else if ((val & 0xf8) == 0x08) + { + /*PIO transfer mode*/ + if ((val & 7) > 3) + return 0; + data->pio_mode = (val & 7); + return 1; + } + else if ((val & 0xf8) == 0x20) + { + /*Multi-word DMA transfer mode*/ + if ((val & 7) > 1) + return 0; + data->mdma_mode = (val & 7); + return 1; + } + return 0; /*Invalid data*/ + + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_REVERT: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + case FEATURE_ENABLE_REVERT: + return 1; + } + + return 0; /*Feature not supported*/ +} + +scsi_device_t scsi_zip = +{ + scsi_zip_init, + scsi_zip_atapi_init, + scsi_zip_close, + scsi_zip_reset, + + scsi_zip_start_command, + scsi_zip_command, + + scsi_zip_get_status, + scsi_zip_get_sense_key, + scsi_zip_get_bytes_required, + + scsi_zip_atapi_identify, + scsi_zip_atapi_set_feature, + + scsi_zip_read, + scsi_zip_write, + scsi_zip_read_complete, + scsi_zip_write_complete, +}; diff --git a/src/scsi_zip.h b/src/scsi_zip.h new file mode 100644 index 0000000..16935fa --- /dev/null +++ b/src/scsi_zip.h @@ -0,0 +1,7 @@ +#include "scsi.h" + +extern scsi_device_t scsi_zip; + +void zip_load(char *fn); +void zip_eject(); +int zip_loaded(); diff --git a/src/serial.c b/src/serial.c index 5b40691..91cf7e8 100644 --- a/src/serial.c +++ b/src/serial.c @@ -35,7 +35,7 @@ void serial_update_ints(SERIAL *serial) stat = 1; serial->iir = 6; } - else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/ + else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Received data available*/ { stat = 1; serial->iir = 4; @@ -111,7 +111,8 @@ void serial_write(uint16_t addr, uint8_t val, void *p) serial_update_ints(serial); break; case 2: - serial->fcr = val; + if (serial->has_fifo) + serial->fcr = val; break; case 3: serial->lcr = val; @@ -185,7 +186,7 @@ uint8_t serial_read(uint16_t addr, void *p) serial_update_ints(serial); temp = serial_read_fifo(serial); if (serial->fifo_read != serial->fifo_write) - serial->recieve_delay = 1000 * TIMER_USEC; + timer_set_delay_u64(&serial->receive_timer, 1000 * TIMER_USEC); break; case 1: if (serial->lcr & 0x80) @@ -234,12 +235,10 @@ uint8_t serial_read(uint16_t addr, void *p) return temp; } -void serial_recieve_callback(void *p) +void serial_receive_callback(void *p) { SERIAL *serial = (SERIAL *)p; - serial->recieve_delay = 0; - if (serial->fifo_read != serial->fifo_write) { serial->lsr |= 1; @@ -249,46 +248,54 @@ void serial_recieve_callback(void *p) } /*Tandy might need COM1 at 2f8*/ -void serial1_init(uint16_t addr, int irq) +void serial1_init(uint16_t addr, int irq, int has_fifo) { memset(&serial1, 0, sizeof(serial1)); io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); serial1.irq = irq; + serial1.addr = addr; serial1.rcr_callback = NULL; - timer_add(serial_recieve_callback, &serial1.recieve_delay, &serial1.recieve_delay, &serial1); + timer_add(&serial1.receive_timer, serial_receive_callback, &serial1, 0); + serial1.has_fifo = has_fifo; } 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; + serial1.addr = addr; +} +void serial1_set_has_fifo(int has_fifo) +{ + serial1.has_fifo = has_fifo; } 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); + io_removehandler(serial1.addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); } -void serial2_init(uint16_t addr, int irq) +void serial2_init(uint16_t addr, int irq, int has_fifo) { memset(&serial2, 0, sizeof(serial2)); io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); serial2.irq = irq; + serial2.addr = addr; serial2.rcr_callback = NULL; - timer_add(serial_recieve_callback, &serial2.recieve_delay, &serial2.recieve_delay, &serial2); + timer_add(&serial2.receive_timer, serial_receive_callback, &serial2, 0); + serial2.has_fifo = has_fifo; } 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; + serial2.addr = addr; +} +void serial2_set_has_fifo(int has_fifo) +{ + serial2.has_fifo = has_fifo; } 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); + io_removehandler(serial2.addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); } diff --git a/src/serial.h b/src/serial.h index 748ad07..13cee6d 100644 --- a/src/serial.h +++ b/src/serial.h @@ -1,7 +1,11 @@ -void serial1_init(uint16_t addr, int irq); -void serial2_init(uint16_t addr, int irq); +#include "timer.h" + +void serial1_init(uint16_t addr, int irq, int has_fifo); +void serial2_init(uint16_t addr, int irq, int has_fifo); void serial1_set(uint16_t addr, int irq); void serial2_set(uint16_t addr, int irq); +void serial1_set_has_fifo(int has_fifo); +void serial2_set_has_fifo(int has_fifo); void serial1_remove(); void serial2_remove(); void serial_reset(); @@ -18,13 +22,15 @@ typedef struct uint8_t fcr; int irq; + uint16_t addr; void (*rcr_callback)(struct SERIAL *serial, void *p); void *rcr_callback_p; uint8_t fifo[256]; int fifo_read, fifo_write; + int has_fifo; - int recieve_delay; + pc_timer_t receive_timer; } SERIAL; void serial_write_fifo(SERIAL *serial, uint8_t dat); diff --git a/src/sio.c b/src/sio.c new file mode 100644 index 0000000..65c8980 --- /dev/null +++ b/src/sio.c @@ -0,0 +1,187 @@ +#include + +#include "ibm.h" +#include "ide.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "sio.h" + +typedef struct sio_t +{ + struct + { + uint8_t apmc, apms; + } pm; +} sio_t; +static sio_t sio; +static uint8_t card_sio[256]; +//static int pci_cards_ids[4]; + +#define REG_SMIEN 0xa2 +#define REG_SMIREQ 0xaa + +#define SMIEN_APMC (1 << 7) +#define SMIREQ_RAPMC (1 << 7) + +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, cpu_state.pc); + if (func > 0) + return; + + if (addr >= 0x0f && addr < 0x4c) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x08; + val |= 0x07; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x60: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x62: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x63: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + + case REG_SMIREQ: + card_sio[addr] &= val; + return; + case REG_SMIREQ+1: + card_sio[addr] &= val; + 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]; +} + +static uint8_t sio_apm_read(uint16_t port, void *p) +{ + sio_t *sio = (sio_t *)p; + uint8_t ret = 0xff; + + switch (port) + { + case 0xb2: + ret = sio->pm.apmc; + break; + + case 0xb3: + ret = sio->pm.apms; + break; + } +// pclog("sio_apm_read: port=%04x ret=%02x\n", port, ret); + return ret; +} + +static void sio_apm_write(uint16_t port, uint8_t val, void *p) +{ + sio_t *sio = (sio_t *)p; + +// pclog("sio_apm_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0xb2: + sio->pm.apmc = val; + if (card_sio[REG_SMIEN] & SMIEN_APMC) + { + card_sio[REG_SMIREQ] |= SMIREQ_RAPMC; +// pclog("APMC write causes SMI\n"); + x86_smi_trigger(); + } + break; + + case 0xb3: + sio->pm.apms = val; + break; + } +} + +void sio_init(int card, int pci_a, int pci_b, int pci_c, int pci_d) +{ + memset(&sio, 0, sizeof(sio_t)); + + 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; /*82378IB (SIO)*/ + card_sio[0x04] = 0x07; card_sio[0x05] = 0x00; + card_sio[0x06] = 0x00; card_sio[0x07] = 0x02; + card_sio[0x08] = 0x03; /*A0 stepping*/ + + card_sio[0x40] = 0x20; card_sio[0x41] = 0x00; + card_sio[0x42] = 0x04; card_sio[0x43] = 0x00; + card_sio[0x44] = 0x20; card_sio[0x45] = 0x10; + card_sio[0x46] = 0x0f; card_sio[0x47] = 0x00; + card_sio[0x48] = 0x01; card_sio[0x49] = 0x10; + 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[0x54] = 0x00; card_sio[0x55] = 0x00; card_sio[0x56] = 0x00; + card_sio[0x60] = 0x80; card_sio[0x61] = 0x80; card_sio[0x62] = 0x80; card_sio[0x63] = 0x80; + card_sio[0x80] = 0x78; card_sio[0x81] = 0x00; + card_sio[0xa0] = 0x08; + card_sio[0xa8] = 0x0f; + + if (pci_a) + pci_set_card_routing(pci_a, PCI_INTA); + if (pci_b) + pci_set_card_routing(pci_b, PCI_INTB); + if (pci_c) + pci_set_card_routing(pci_c, PCI_INTC); + if (pci_d) + pci_set_card_routing(pci_d, PCI_INTD); + + io_sethandler(0x00b2, 0x0002, sio_apm_read, NULL, NULL, sio_apm_write, NULL, NULL, &sio); +} diff --git a/src/sio.h b/src/sio.h new file mode 100644 index 0000000..6957aff --- /dev/null +++ b/src/sio.h @@ -0,0 +1 @@ +void sio_init(int card, int pci_a, int pci_b, int pci_c, int pci_d); diff --git a/src/sis496.c b/src/sis496.c index de9a246..6738ba5 100644 --- a/src/sis496.c +++ b/src/sis496.c @@ -4,6 +4,7 @@ #include "io.h" #include "mem.h" #include "pci.h" +#include "pic.h" #include "sis496.h" @@ -42,7 +43,6 @@ void sis496_recalcmapping(sis496_t *sis496) } flushmmucache(); - shadowbios = (sis496->pci_conf[0x44] & 0xf0); } void sis496_write(int func, int addr, uint8_t val, void *p) @@ -65,6 +65,35 @@ void sis496_write(int func, int addr, uint8_t val, void *p) sis496_recalcmapping(sis496); } break; + + case 0xc0: + // pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, val & 0xf); + else + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + break; + case 0xc1: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, val & 0xf); + else + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + break; + case 0xc2: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, val & 0xf); + else + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + break; + case 0xc3: +// pclog("IRQ routing %02x %02x\n", addr, val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, val & 0xf); + else + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + break; } if ((addr >= 4 && addr < 8) || addr >= 0x40) @@ -104,6 +133,12 @@ void *sis496_init() sis496->pci_conf[0x0e] = 0x00; /*Single function device*/ + pci_set_card_routing(15, PCI_INTA); + pci_set_card_routing(13, PCI_INTD); + pci_set_card_routing(11, PCI_INTC); + + pic_init_elcrx(); + return sis496; } diff --git a/src/sl82c460.c b/src/sl82c460.c new file mode 100644 index 0000000..8118b05 --- /dev/null +++ b/src/sl82c460.c @@ -0,0 +1,76 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "sl82c460.h" + +static struct +{ + int reg_idx; + uint8_t regs[256]; +} sl82c460; + +static void sl82c460_shadow_set(uint32_t base, uint32_t size, int state) +{ + switch (state) + { + case 0: + mem_set_mem_state(base, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(base, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(base, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 3: + mem_set_mem_state(base, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + +} + +static void sl82c460_shadow_recalc() +{ + sl82c460_shadow_set(0xc0000, 0x4000, sl82c460.regs[0x18] & 3); + sl82c460_shadow_set(0xc4000, 0x4000, (sl82c460.regs[0x18] >> 2) & 3); + sl82c460_shadow_set(0xc8000, 0x4000, (sl82c460.regs[0x18] >> 4) & 3); + sl82c460_shadow_set(0xcc000, 0x4000, (sl82c460.regs[0x18] >> 6) & 3); + sl82c460_shadow_set(0xd0000, 0x4000, sl82c460.regs[0x19] & 3); + sl82c460_shadow_set(0xd4000, 0x4000, (sl82c460.regs[0x19] >> 2) & 3); + sl82c460_shadow_set(0xd8000, 0x4000, (sl82c460.regs[0x19] >> 4) & 3); + sl82c460_shadow_set(0xdc000, 0x4000, (sl82c460.regs[0x19] >> 6) & 3); + sl82c460_shadow_set(0xe0000, 0x10000, (sl82c460.regs[0x1b] >> 4) & 3); + sl82c460_shadow_set(0xf0000, 0x10000, (sl82c460.regs[0x1b] >> 2) & 3); +} + +static void sl82c460_write(uint16_t addr, uint8_t val, void *p) +{ + if (!(addr & 1)) + sl82c460.reg_idx = val; + else + { +// pclog("SL82C460 write %02x %02x\n", sl82c460.reg_idx, val); + sl82c460.regs[sl82c460.reg_idx] = val; + + switch (sl82c460.reg_idx) + { + case 0x18: case 0x19: case 0x1b: + sl82c460_shadow_recalc(); + break; + } + } +} + +static uint8_t sl82c460_read(uint16_t addr, void *p) +{ + if (!(addr & 1)) + return sl82c460.reg_idx; + + return sl82c460.regs[sl82c460.reg_idx]; +} + +void sl82c460_init() +{ + memset(&sl82c460, 0, sizeof(sl82c460)); + io_sethandler(0x00a8, 0x0002, sl82c460_read, NULL, NULL, sl82c460_write, NULL, NULL, NULL); +} diff --git a/src/sl82c460.h b/src/sl82c460.h new file mode 100644 index 0000000..883a8aa --- /dev/null +++ b/src/sl82c460.h @@ -0,0 +1 @@ +void sl82c460_init(); diff --git a/src/slirp/COPYRIGHT.txt b/src/slirp/COPYRIGHT.txt new file mode 100644 index 0000000..01d4400 --- /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 0000000..e513410 --- /dev/null +++ b/src/slirp/Makefile @@ -0,0 +1,26 @@ +CC=gcc +CFLAGS=-I. -Ofast -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 0000000..0dd1c2b --- /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 0000000..34913b6 --- /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 0000000..0625161 --- /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 0000000..eeccb88 --- /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 0000000..90e7dd3 --- /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 0000000..09047ab --- /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 0000000..efac7cb --- /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 0000000..f6f244b --- /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 0000000..7b96c1a --- /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 0000000..8bacc63 --- /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 0000000..aa0cea9 --- /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 0000000..4f39951 --- /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 0000000..f11a847 --- /dev/null +++ b/src/slirp/ip.h @@ -0,0 +1,322 @@ +/* + * 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 */ + +struct mbuf_ptr { + union + { + struct mbuf *mptr; + uint64_t dummy; + } m; +}; + + +struct qlink { + void *next, *prev; +}; + +/* + * Overlay for ip header used by other protocols (tcp, udp). + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ipovly { + struct mbuf_ptr ih_mbuf; /* backpointer to mbuf */ + 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 { + struct qlink frag_link; /* to ip headers of fragments */ + struct qlink ip_link; /* 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 */ + struct in_addr ipq_src,ipq_dst; +}; + +/* + * Ip header, when holding a fragment. + * + * Note: ipf_link must be at same offset as frag_link above + */ +struct ipasfrag { + struct qlink ipf_link; + struct ip ipf_ip; +}; + +#define ipf_off ipf_ip.ip_off +#define ipf_tos ipf_ip.ip_tos +#define ipf_len ipf_ip.ip_len +#define ipf_next ipf_link.next +#define ipf_prev ipf_link.prev + +/* + * 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 0000000..396293d --- /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 0000000..2de52a1 --- /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 0000000..f6fc4a3 --- /dev/null +++ b/src/slirp/ip_input.c @@ -0,0 +1,694 @@ +/* + * 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" +#include + +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.ip_link.next = ipq.ip_link.prev = &ipq.ip_link; + 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) { + struct ipq *fp; + struct qlink *l; + /* + * Look for queue of fragments + * of this datagram. + */ + for (l = (struct qlink*)(ipq.ip_link.next); l != &ipq.ip_link; l = (struct qlink*)(l->next)) { + fp = container_of(l, struct ipq, ip_link); + 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 = NULL; + 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) + ip->ip_tos |= 1; + else + ip->ip_tos &= ~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 ((ip->ip_tos & 1) || ip->ip_off) { + ipstat.ips_fragments++; + ip = ip_reass(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; +} + +#define iptofrag(P) ((struct ipasfrag *)(((char*)(P)) - sizeof(struct qlink))) +#define fragtoip(P) ((struct ip*)(((char*)(P)) + sizeof(struct qlink))) + +/* + * 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(struct ip *ip, 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(&fp->ip_link, &ipq.ip_link); + fp->ipq_ttl = IPFRAGTTL; + fp->ipq_p = ip->ip_p; + fp->ipq_id = ip->ip_id; + fp->frag_link.next = fp->frag_link.prev = &fp->frag_link; + fp->ipq_src = ip->ip_src; + fp->ipq_dst = ip->ip_dst; + q = (struct ipasfrag *)fp; + goto insert; + } + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct ipasfrag*)fp->frag_link.next; q != (struct ipasfrag *)&fp->frag_link; q = (struct ipasfrag*)(q->ipf_next)) { + if (q->ipf_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 != &fp->frag_link) { + struct ipasfrag *pq = (struct ipasfrag*)(q->ipf_prev); + i = pq->ipf_off + pq->ipf_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->frag_link && + ip->ip_off + ip->ip_len > q->ipf_off) { + i = (ip->ip_off + ip->ip_len) - q->ipf_off; + if (i < q->ipf_len) { + q->ipf_len -= i; + q->ipf_off += i; + m_adj(dtom(q), i); + break; + } + q = (struct ipasfrag*)(q->ipf_next); + m_freem(dtom(q->ipf_prev)); + ip_deq((struct ipasfrag*)(q->ipf_prev)); + } + +insert: + /* + * Stick new segment in its place; + * check for complete reassembly. + */ + ip_enq(iptofrag(ip), (struct ipasfrag*)(q->ipf_prev)); + next = 0; + for (q = (struct ipasfrag*)(fp->frag_link.next); q != (struct ipasfrag*)&fp->frag_link; q = (struct ipasfrag*)(q->ipf_next)) { + if (q->ipf_off != next) + return 0; + next += q->ipf_len; + } + if (((struct ipasfrag *)(q->ipf_prev))->ipf_tos & 1) + return (0); + + /* + * Reassembly is complete; concatenate fragments. + */ + q = (struct ipasfrag*)(fp->frag_link.next); + m = dtom(q); + + q = (struct ipasfrag *) q->ipf_next; + while (q != (struct ipasfrag*)&fp->frag_link) { + struct mbuf *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. + */ + q = (struct ipasfrag*)(fp->frag_link.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; + q = (struct ipasfrag *)(m->m_ext + delta); + } + + /* DEBUG_ARG("ip = %lx", (long)ip); + * ip=(struct ipasfrag *)m->m_data; */ + + ip = fragtoip(q); + ip->ip_len = next; + ip->ip_tos &= ~1; + ip->ip_src = fp->ipq_src; + ip->ip_dst = fp->ipq_dst; + remque(&fp->ip_link); + (void) m_free(dtom(fp)); + m->m_len += (ip->ip_hl << 2); + m->m_data -= (ip->ip_hl << 2); + + return 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->frag_link.next); q != (struct ipasfrag*)&fp->frag_link; q = p) { + p = (struct ipasfrag*)(q->ipf_next); + ip_deq(q); + m_freem(dtom(q)); + } + remque(&fp->ip_link); + (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 = prev; + p->ipf_next = prev->ipf_next; + ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = p; + prev->ipf_next = 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() +{ + struct qlink *l; + + DEBUG_CALL("ip_slowtimo"); + + l = (struct qlink*)(ipq.ip_link.next); + + if (l == 0) + return; + + while (l != &ipq.ip_link) { + struct ipq *fp = container_of(l, struct ipq, ip_link); + l = (struct qlink*)(l->next); + if (--fp->ipq_ttl == 0) { + ipstat.ips_fragtimeout++; + ip_freef(fp); + } + } +} + +/* + * 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 0000000..214c031 --- /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 0000000..57a68cf --- /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 0000000..45e51cd --- /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 0000000..bf636e1 --- /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 0000000..840fa3b --- /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 0000000..e88567e --- /dev/null +++ b/src/slirp/misc.c @@ -0,0 +1,935 @@ +/* + * 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 +} + +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 0000000..4ab838d --- /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 0000000..39405dc --- /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 0000000..c75ec70 --- /dev/null +++ b/src/slirp/queue.h @@ -0,0 +1,101 @@ +/* + * 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); + +int QueuePeek(queueADT queue); + +#endif /* not defined _QUEUE_H */ diff --git a/src/slirp/sbuf.c b/src/slirp/sbuf.c new file mode 100644 index 0000000..259f627 --- /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 0000000..eff9481 --- /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 0000000..a53ceb8 --- /dev/null +++ b/src/slirp/slirp.c @@ -0,0 +1,681 @@ +#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) || (&ipq.ip_link != ipq.ip_link.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 0000000..6e15943 --- /dev/null +++ b/src/slirp/slirp.h @@ -0,0 +1,412 @@ +#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" + +#ifndef container_of +#define container_of(address, type, field) ((type *)( \ + (uintptr_t)(address) - \ + (uintptr_t)(&((type *)0)->field))) +#endif + +#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 +typedef char *SLIRPcaddr_t; +#endif + +#include +#ifdef HAVE_SYS_BITYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif + +#ifdef HAVE_UNISTD_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 *, ...)); + +#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((struct ip *, 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 0000000..850ddee --- /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 0000000..604c2bf --- /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 0000000..9e9f231 --- /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 0000000..36edc5c --- /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 0000000..f4c90bf --- /dev/null +++ b/src/slirp/tcp_input.c @@ -0,0 +1,1723 @@ +/* + * 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 && \ + tcpfrag_list_empty(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 && \ + tcpfrag_list_empty(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 = tcpfrag_list_first(tp); !tcpfrag_list_end(q, tp); + q = tcpiphdr_next(q)) + 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 (!tcpfrag_list_end(tcpiphdr_prev(q), tp)) { + int i; + q = tcpiphdr_prev(q); + /* 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 = tcpiphdr_next(q); + } + tcpstat.tcps_rcvoopack++; + tcpstat.tcps_rcvoobyte += ti->ti_len; + ti->ti_mbuf = m; + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (!tcpfrag_list_end(q, 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(q->ti_mbuf, i); + break; + } + q = tcpiphdr_next(q); + m = tcpiphdr_prev(q)->ti_mbuf; + remque(tcpiphdr2qlink(tcpiphdr_prev(q))); + m_freem(m); + } + + /* + * Stick new segment in its place. + */ + insque(tcpiphdr2qlink(ti), tcpiphdr2qlink(tcpiphdr_prev(q))); + +present: + /* + * Present data to user, advancing rcv_nxt through + * completed sequence space. + */ + if (!TCPS_HAVEESTABLISHED(tp->t_state)) + return (0); + ti = tcpfrag_list_first(tp); + if (tcpfrag_list_end(ti, 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(tcpiphdr2qlink(ti)); + m = ti->ti_mbuf; + ti = tcpiphdr_next(ti); +/* 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; + tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = 0; + memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr)); + 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 && + tcpfrag_list_empty(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 0000000..8bafb82 --- /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 0000000..70661c2 --- /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_mbuf = NULL; + 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_mbuf = 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 = (struct tcpiphdr*)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 = tcpfrag_list_first(tp); + while (!tcpfrag_list_end(t, tp)) { + t = tcpiphdr_next(t); + m = tcpiphdr_prev(t)->ti_mbuf; + remque(tcpiphdr2qlink(tcpiphdr_prev(t))); + 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 .......glc..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 .guxc..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 0000000..db0c0dd --- /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 0000000..e860b42 --- /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 0000000..a0281cb --- /dev/null +++ b/src/slirp/tcp_var.h @@ -0,0 +1,227 @@ +/* + * 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" + +/* + * Tcp control block, one per tcp; fields: + */ +struct tcpcb { + struct tcpiphdr *seg_next; /* sequencing queue */ + struct tcpiphdr *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) + +/* + * 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 0000000..5dbe0ff --- /dev/null +++ b/src/slirp/tcpip.h @@ -0,0 +1,77 @@ +/* + * 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_mbuf ti_i.ih_mbuf.m.mptr +#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 + +#define tcpiphdr2qlink(T) ((struct qlink*)(((char*)(T)) - sizeof(struct qlink))) +#define qlink2tcpiphdr(Q) ((struct tcpiphdr*)(((char*)(Q)) + sizeof(struct qlink))) +#define tcpiphdr_next(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->next) +#define tcpiphdr_prev(T) qlink2tcpiphdr(tcpiphdr2qlink(T)->prev) +#define tcpfrag_list_first(T) qlink2tcpiphdr((T)->seg_next) +#define tcpfrag_list_end(F, T) (tcpiphdr2qlink(F) == (struct qlink*)(T)) +#define tcpfrag_list_empty(T) ((T)->seg_next == (struct tcpiphdr*)(T)) + +/* + * 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 0000000..3a851a6 --- /dev/null +++ b/src/slirp/tftp.c @@ -0,0 +1,331 @@ +/* + * 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" + +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; + + fd = open(spt->filename, 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; + + 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; + + 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; + } + + /* do sanity checks on the filename */ + + if ((spt->filename[0] != '/') + || (spt->filename[strlen(spt->filename) - 1] == '/') + || strstr(spt->filename, "/../")) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + /* only allow exported prefixes */ + + if (!tftp_prefix + || (strncmp(spt->filename, tftp_prefix, strlen(tftp_prefix)) != 0)) { + 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 0000000..266ce16 --- /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 0000000..0efd8e5 --- /dev/null +++ b/src/slirp/udp.c @@ -0,0 +1,675 @@ +/* + * 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) { + memset(&((struct ipovly *)ip)->ih_mbuf, 0, sizeof(struct mbuf_ptr)); + ((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 *); + memset(&ui->ui_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr)); + 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 0000000..58ca011 --- /dev/null +++ b/src/slirp/udp.h @@ -0,0 +1,113 @@ +/* + * 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_mbuf ui_i.ih_mbuf.m.mptr +#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 index a092bc2..f038613 100644 --- a/src/sound.c +++ b/src/sound.c @@ -4,6 +4,7 @@ #include "device.h" #include "cdrom-ioctl.h" +#include "cdrom-image.h" #include "ide.h" #include "filters.h" @@ -13,6 +14,8 @@ #include "sound.h" #include "sound_adlib.h" #include "sound_adlibgold.h" +#include "sound_audiopci.h" +#include "sound_azt2316a.h" #include "sound_pas16.h" #include "sound_sb.h" #include "sound_sb_dsp.h" @@ -33,21 +36,25 @@ typedef struct static SOUND_CARD sound_cards[] = { - {"None", "none", NULL}, - {"Adlib", "adlib", &adlib_device}, - {"Adlib", "adlib_mca", &adlib_mca_device}, - {"Sound Blaster 1.0", "sb", &sb_1_device}, - {"Sound Blaster 1.5", "sb1.5", &sb_15_device}, - {"Sound Blaster MCV", "sbmcv", &sb_mcv_device}, - {"Sound Blaster 2.0", "sb2.0", &sb_2_device}, - {"Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device}, - {"Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device}, - {"Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device}, - {"Sound Blaster 16", "sb16", &sb_16_device}, - {"Sound Blaster AWE32", "sbawe32", &sb_awe32_device}, - {"Adlib Gold", "adlibgold", &adgold_device}, - {"Windows Sound System", "wss", &wss_device}, - {"Pro Audio Spectrum 16", "pas16", &pas16_device}, + {"None", "none", NULL}, + {"Adlib", "adlib", &adlib_device}, + {"Adlib", "adlib_mca", &adlib_mca_device}, + {"Sound Blaster 1.0", "sb", &sb_1_device}, + {"Sound Blaster 1.5", "sb1.5", &sb_15_device}, + {"Sound Blaster MCV", "sbmcv", &sb_mcv_device}, + {"Sound Blaster 2.0", "sb2.0", &sb_2_device}, + {"Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device}, + {"Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device}, + {"Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device}, + {"Sound Blaster 16", "sb16", &sb_16_device}, + {"Sound Blaster AWE32", "sbawe32", &sb_awe32_device}, + {"Adlib Gold", "adlibgold", &adgold_device}, + {"Windows Sound System", "wss", &wss_device}, + {"Aztech Sound Galaxy Pro 16 AB (Washington)", "azt2316a", &azt2316a_device}, + {"Aztech Sound Galaxy Nova 16 Extra (Clinton)", "azt1605", &azt1605_device}, + {"Pro Audio Spectrum 16", "pas16", &pas16_device}, + {"Ensoniq AudioPCI (ES1371)", "es1371", &es1371_device}, + {"Sound Blaster PCI 128", "sbpci128", &es1371_device}, {"", "", NULL} }; @@ -110,7 +117,8 @@ static struct static int sound_handlers_num; -static int sound_poll_time = 0, sound_poll_latch; +static pc_timer_t sound_poll_timer; +static uint64_t sound_poll_latch; int sound_pos_global = 0; int soundon = 1; @@ -119,7 +127,19 @@ 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; -static int cd_buf_update = CD_BUFLEN / SOUNDBUFLEN; + +int sound_buf_len = 48000 / 10; +int sound_gain = 0; + +void sound_update_buf_length() +{ + int new_buf_len = (48000 / (1000 / sound_buf_len)) / 4; + + if (new_buf_len > MAXSOUNDBUFLEN) + new_buf_len = MAXSOUNDBUFLEN; + + SOUNDBUFLEN = new_buf_len; +} void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) { @@ -134,7 +154,10 @@ static void sound_cd_thread(void *param) int c; thread_wait_event(sound_cd_event, -1); + thread_reset_event(sound_cd_event); + memset(cd_buffer, 0, CD_BUFLEN*2 * 2); ioctl_audio_callback(cd_buffer, CD_BUFLEN*2); + image_audio_callback(cd_buffer, CD_BUFLEN*2); if (soundon) { int32_t atapi_vol_l = atapi_get_cd_volume(0); @@ -191,7 +214,7 @@ void sound_init() initalmain(0,NULL); inital(); - outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); + outbuffer = malloc(MAXSOUNDBUFLEN * 2 * sizeof(int32_t)); sound_cd_event = thread_create_event(); sound_cd_thread_h = thread_create(sound_cd_thread, NULL); @@ -204,9 +227,17 @@ void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), vo sound_handlers_num++; } +static int cd_pos = 0; void sound_poll(void *priv) { - sound_poll_time += sound_poll_latch; + timer_advance_u64(&sound_poll_timer, sound_poll_latch); + + cd_pos++; + if (cd_pos == (CD_BUFLEN * 48000) / CD_FREQ) + { + cd_pos = 0; + thread_set_event(sound_cd_event); + } sound_pos_global++; if (sound_pos_global == SOUNDBUFLEN) @@ -235,28 +266,23 @@ void sound_poll(void *priv) if (soundon) givealbuffer(outbuffer); - cd_buf_update--; - if (!cd_buf_update) - { - cd_buf_update = (48000 / SOUNDBUFLEN) / (CD_FREQ / CD_BUFLEN); - thread_set_event(sound_cd_event); - } - sound_pos_global = 0; + sound_update_buf_length(); } } void sound_speed_changed() { - sound_poll_latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); + sound_poll_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); } void sound_reset() { - timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); + timer_add(&sound_poll_timer, sound_poll, NULL, 1); sound_handlers_num = 0; sound_set_cd_volume(65535, 65535); ioctl_audio_stop(); + image_audio_stop(); } diff --git a/src/sound.h b/src/sound.h index f5c59a3..d97406f 100644 --- a/src/sound.h +++ b/src/sound.h @@ -27,3 +27,11 @@ void inital(); void givealbuffer(int32_t *buf); void givealbuffer_cd(int16_t *buf); + +extern int sound_buf_len; +void sound_update_buf_length(); + +extern int sound_gain; + +extern int SOUNDBUFLEN; +#define MAXSOUNDBUFLEN (48000 / 10) diff --git a/src/sound_ad1848.c b/src/sound_ad1848.c index 1e9f99a..91bdcf9 100644 --- a/src/sound_ad1848.c +++ b/src/sound_ad1848.c @@ -4,8 +4,10 @@ #include "pic.h" #include "sound.h" #include "sound_ad1848.h" +#include "x86.h" -static int ad1848_vols[64]; +static int ad1848_vols_6bits[64]; +static uint32_t ad1848_vols_5bits_aux_gain[32]; void ad1848_setirq(ad1848_t *ad1848, int irq) { @@ -21,7 +23,7 @@ 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*/ @@ -34,7 +36,10 @@ uint8_t ad1848_read(uint16_t addr, void *p) temp = ad1848->status; break; } -// pclog("return %02X\n", temp); +// if ((addr & 3) == 1 && (ad1848->index & 0x1f) > 0x0f) +// pclog("ad1848_read_EXTENDED - addr %04X %04X(%08X):%08X return %02X\n", addr, CS, cs, cpu_state.pc, temp); +// else +// pclog("ad1848_read - addr %04X %04X(%08X):%08X return %02X\n", addr, CS, cs, cpu_state.pc, temp); return temp; } @@ -42,11 +47,18 @@ 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); + uint32_t new_cd_vol_l, new_cd_vol_r; +// if ((addr & 3) == 0 && (val & 0x1f) > 0x0f) +// pclog("ad1848_write_EXTENDED - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); +// else +// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); switch (addr & 3) { case 0: /*Index*/ - ad1848->index = val & 0xf; + if (ad1848->regs[12] & 0x40 && ad1848->type == AD1848_TYPE_CS4231) + ad1848->index = val & 0x1f; // cs4231a extended mode enabled + else + ad1848->index = val & 0x0f; // ad1848/cs4248 mode TODO: some variants/clones DO NOT mirror, just ignore the writes? ad1848->trd = val & 0x20; ad1848->mce = val & 0x40; break; @@ -67,23 +79,53 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) case 7: freq /= 2560; break; } ad1848->freq = freq; - ad1848->timer_latch = (int)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); break; case 9: + if (!ad1848->enable && (val & 0x41) == 0x01) + { + if (ad1848->timer_latch) + timer_set_delay_u64(&ad1848->timer, ad1848->timer_latch); + else + timer_set_delay_u64(&ad1848->timer, TIMER_USEC); + } ad1848->enable = ((val & 0x41) == 0x01); if (!ad1848->enable) + { + timer_disable(&ad1848->timer); ad1848->out_l = ad1848->out_r = 0; + } break; case 12: + ad1848->regs[12] = ((ad1848->regs[12] & 0x0f) + (val & 0xf0)) | 0x80; return; case 14: ad1848->count = ad1848->regs[15] | (val << 8); break; + // TODO: see which of the extended registers should be read only } ad1848->regs[ad1848->index] = val; + + if (ad1848->type == AD1848_TYPE_CS4231) // TODO: configure CD volume for CS4248/AD1848 too + { + if (ad1848->regs[0x12] & 0x80) + new_cd_vol_l = 0; + else + new_cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[0x12] & 0x1f]; + if (ad1848->regs[0x13] & 0x80) + new_cd_vol_r = 0; + else + new_cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[0x13] & 0x1f]; + + // Apparently there is no master volume to modulate here + // (The windows mixer just adjusts all registers at the same + // time when the master slider is adjusted) + sound_set_cd_volume(new_cd_vol_l, new_cd_vol_r); + } + break; case 2: ad1848->status &= 0xfe; @@ -93,7 +135,7 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p) void ad1848_speed_changed(ad1848_t *ad1848) { - ad1848->timer_latch = (int)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + ad1848->timer_latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); } void ad1848_update(ad1848_t *ad1848) @@ -110,12 +152,12 @@ static void ad1848_poll(void *p) ad1848_t *ad1848 = (ad1848_t *)p; if (ad1848->timer_latch) - ad1848->timer_count += ad1848->timer_latch; + timer_advance_u64(&ad1848->timer, ad1848->timer_latch); else - ad1848->timer_count = TIMER_USEC; + timer_advance_u64(&ad1848->timer, TIMER_USEC*1000); ad1848_update(ad1848); - + // TODO: line in, mic, etc... if (ad1848->enable) { int32_t temp; @@ -145,12 +187,12 @@ static void ad1848_poll(void *p) if (ad1848->regs[6] & 0x80) ad1848->out_l = 0; else - ad1848->out_l = (ad1848->out_l * ad1848_vols[ad1848->regs[6] & 0x3f]) >> 16; + ad1848->out_l = (ad1848->out_l * ad1848_vols_6bits[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; + ad1848->out_r = (ad1848->out_r * ad1848_vols_6bits[ad1848->regs[7] & 0x3f]) >> 16; if (ad1848->count < 0) { @@ -169,15 +211,17 @@ static void ad1848_poll(void *p) else { ad1848->out_l = ad1848->out_r = 0; + sound_set_cd_volume(0, 0); // pclog("ad1848_poll : not enable\n"); } } -void ad1848_init(ad1848_t *ad1848) +void ad1848_init(ad1848_t *ad1848, int type) { int c; double attenuation; + ad1848->type = type; ad1848->enable = 0; ad1848->status = 0xcc; @@ -185,15 +229,24 @@ void ad1848_init(ad1848_t *ad1848) ad1848->mce = 0x40; ad1848->regs[0] = ad1848->regs[1] = 0; - ad1848->regs[2] = ad1848->regs[3] = 0x80; + ad1848->regs[2] = ad1848->regs[3] = 0x80; // AZT2316A Line-in ad1848->regs[4] = ad1848->regs[5] = 0x80; - ad1848->regs[6] = ad1848->regs[7] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; // AZT2316A Master? ad1848->regs[8] = 0; ad1848->regs[9] = 0x08; ad1848->regs[10] = ad1848->regs[11] = 0; - ad1848->regs[12] = 0xa; + if (ad1848->type == AD1848_TYPE_CS4248 || ad1848->type == AD1848_TYPE_CS4231) + ad1848->regs[12] = 0x8a; + else + ad1848->regs[12] = 0xa; ad1848->regs[13] = 0; ad1848->regs[14] = ad1848->regs[15] = 0; + + if (ad1848->type == AD1848_TYPE_CS4231) + { + ad1848->regs[0x12] = ad1848->regs[0x13] = 0x80; // AZT2316A CD + ad1848->regs[0x1A] = 0x80; // AZT2316A Mic + } ad1848->out_l = 0; ad1848->out_r = 0; @@ -210,9 +263,23 @@ void ad1848_init(ad1848_t *ad1848) attenuation = pow(10, attenuation / 10); - ad1848_vols[c] = (int)(attenuation * 65536); -// pclog("ad1848_vols %i = %f %i\n", c, attenuation, ad1848_vols[c]); + ad1848_vols_6bits[c] = (int)(attenuation * 65536); +// pclog("ad1848_vols_6bits %i = %f %i\n", c, attenuation, ad1848_vols_6bits[c]); } - - timer_add(ad1848_poll, &ad1848->timer_count, &ad1848->enable, ad1848); + for (c = 0; c < 32; c++) + { + attenuation = 12.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; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols_5bits_aux_gain[c] = (int)(attenuation * 65536); +// pclog("ad1848_vols_5bits_aux_gain %i = %f %i\n", c, attenuation, ad1848_vols_5bits_aux_gain[c]); + } + + timer_add(&ad1848->timer, ad1848_poll, ad1848, 0); } diff --git a/src/sound_ad1848.h b/src/sound_ad1848.h index 5cba0f1..de951d9 100644 --- a/src/sound_ad1848.h +++ b/src/sound_ad1848.h @@ -1,9 +1,13 @@ #include "timer.h" +#define AD1848_TYPE_DEFAULT 0 +#define AD1848_TYPE_CS4248 1 +#define AD1848_TYPE_CS4231 2 + typedef struct ad1848_t { int index; - uint8_t regs[16]; + uint8_t regs[32]; // 16 original + 16 CS4231A extensions uint8_t status; int trd; @@ -19,10 +23,13 @@ typedef struct ad1848_t int freq; - int timer_count, timer_latch; + pc_timer_t timer; + uint64_t timer_latch; - int16_t buffer[SOUNDBUFLEN * 2]; + int16_t buffer[MAXSOUNDBUFLEN * 2]; int pos; + + int type; } ad1848_t; void ad1848_setirq(ad1848_t *ad1848, int irq); @@ -34,4 +41,4 @@ void ad1848_write(uint16_t addr, uint8_t val, void *p); void ad1848_update(ad1848_t *ad1848); void ad1848_speed_changed(ad1848_t *ad1848); -void ad1848_init(ad1848_t *ad1848); +void ad1848_init(ad1848_t *ad1848, int type); diff --git a/src/sound_adlib.c b/src/sound_adlib.c index 0be5259..da3de33 100644 --- a/src/sound_adlib.c +++ b/src/sound_adlib.c @@ -76,7 +76,7 @@ void *adlib_mca_init() adlib_t *adlib = adlib_init(); io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); - mca_add(adlib_mca_read, adlib_mca_write, adlib); + mca_add(adlib_mca_read, adlib_mca_write, NULL, adlib); adlib->pos_regs[0] = 0xd7; adlib->pos_regs[1] = 0x70; diff --git a/src/sound_adlibgold.c b/src/sound_adlibgold.c index 063d261..a8ce40b 100644 --- a/src/sound_adlibgold.c +++ b/src/sound_adlibgold.c @@ -11,6 +11,7 @@ #include "pit.h" #include "sound.h" #include "timer.h" +#include "nvr.h" #include "filters.h" @@ -35,7 +36,7 @@ typedef struct adgold_t int16_t adgold_mma_out[2]; int adgold_mma_intpos[2]; - int adgold_mma_timer_count; + pc_timer_t adgold_mma_timer; struct { @@ -55,8 +56,8 @@ typedef struct adgold_t int vol_l, vol_r; int treble, bass; - int16_t opl_buffer[SOUNDBUFLEN * 2]; - int16_t mma_buffer[2][SOUNDBUFLEN]; + int16_t opl_buffer[MAXSOUNDBUFLEN * 2]; + int16_t mma_buffer[2][MAXSOUNDBUFLEN]; int pos; @@ -585,9 +586,10 @@ 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); + timer_advance_u64(&adgold->adgold_mma_timer, (uint64_t)((double)TIMER_USEC * 1.88964)); +// 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--; @@ -648,7 +650,7 @@ void adgold_timer_poll(void *p) adgold_mma_poll(adgold, 1); } } - } +// } } static void adgold_get_buffer(int32_t *buffer, int len, void *p) @@ -768,12 +770,14 @@ void *adgold_init() FILE *f; int c; double out; + int opl_emu; adgold_t *adgold = malloc(sizeof(adgold_t)); memset(adgold, 0, sizeof(adgold_t)); adgold->surround_enabled = device_get_config_int("surround"); + opl_emu = device_get_config_int("opl_emu"); - opl3_init(&adgold->opl); + opl3_init(&adgold->opl, opl_emu); if (adgold->surround_enabled) ym7128_init(&adgold->ym7128); @@ -786,7 +790,7 @@ void *adgold_init() for (; c >= 0; c--) attenuation[c] = 0; - f = romfopen("nvr/adgold.bin", "rb"); + f = nvrfopen("adgold.bin", "rb"); if (f) { fread(adgold->adgold_eeprom, 0x18, 1, f); @@ -814,7 +818,7 @@ void *adgold_init() /*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); + timer_add(&adgold->adgold_mma_timer, adgold_timer_poll, adgold, 1); sound_add_handler(adgold_get_buffer, adgold); @@ -826,7 +830,7 @@ void adgold_close(void *p) FILE *f; adgold_t *adgold = (adgold_t *)p; - f = romfopen("nvr/adgold.bin", "wb"); + f = nvrfopen("adgold.bin", "wb"); if (f) { fwrite(adgold->adgold_eeprom, 0x18, 1, f); @@ -844,6 +848,23 @@ static device_config_t adgold_config[] = .type = CONFIG_BINARY, .default_int = 1 }, + { + .name = "opl_emu", + .description = "OPL emulator", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DBOPL", + .value = OPL_DBOPL + }, + { + .description = "NukedOPL", + .value = OPL_NUKED + }, + }, + .default_int = OPL_DBOPL + }, { .type = -1 } diff --git a/src/sound_audiopci.c b/src/sound_audiopci.c new file mode 100644 index 0000000..21df235 --- /dev/null +++ b/src/sound_audiopci.c @@ -0,0 +1,1304 @@ +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "sound.h" + +#define N 16 + +#define ES1371_NCoef 91 + +static float low_fir_es1371_coef[ES1371_NCoef]; + +typedef struct es1371_t +{ + uint8_t pci_command, pci_serr; + + uint32_t base_addr; + + uint8_t int_line; + + uint16_t pmcsr; + + uint32_t int_ctrl; + uint32_t int_status; + + uint32_t legacy_ctrl; + + int mem_page; + + uint32_t si_cr; + + uint32_t sr_cir; + uint16_t sr_ram[128]; + + uint8_t uart_ctrl; + uint8_t uart_status; + + uint16_t codec_regs[64]; + uint32_t codec_ctrl; + + struct + { + uint32_t addr, addr_latch; + uint16_t count, size; + + uint16_t samp_ct; + int curr_samp_ct; + + pc_timer_t timer; + uint64_t latch; + + uint32_t vf, ac; + + int16_t buffer_l[64], buffer_r[64]; + int buffer_pos, buffer_pos_end; + + int filtered_l[32], filtered_r[32]; + int f_pos; + + int16_t out_l, out_r; + + int32_t vol_l, vol_r; + } dac[2], adc; + + int dac_latch, dac_time; + + int master_vol_l, master_vol_r; + + int card; + + int pos; + int16_t buffer[MAXSOUNDBUFLEN * 2]; +} es1371_t; + +#define LEGACY_SB_ADDR (1 << 29) +#define LEGACY_SSCAPE_ADDR_SHIFT 27 +#define LEGACY_CODEC_ADDR_SHIFT 25 +#define LEGACY_FORCE_IRQ (1 << 24) +#define LEGACY_CAPTURE_SLAVE_DMA (1 << 23) +#define LEGACY_CAPTURE_SLAVE_PIC (1 << 22) +#define LEGACY_CAPTURE_MASTER_DMA (1 << 21) +#define LEGACY_CAPTURE_MASTER_PIC (1 << 20) +#define LEGACY_CAPTURE_ADLIB (1 << 19) +#define LEGACY_CAPTURE_SB (1 << 18) +#define LEGACY_CAPTURE_CODEC (1 << 17) +#define LEGACY_CAPTURE_SSCAPE (1 << 16) +#define LEGACY_EVENT_SSCAPE (0 << 8) +#define LEGACY_EVENT_CODEC (1 << 8) +#define LEGACY_EVENT_SB (2 << 8) +#define LEGACY_EVENT_ADLIB (3 << 8) +#define LEGACY_EVENT_MASTER_PIC (4 << 8) +#define LEGACY_EVENT_MASTER_DMA (5 << 8) +#define LEGACY_EVENT_SLAVE_PIC (6 << 8) +#define LEGACY_EVENT_SLAVE_DMA (7 << 8) +#define LEGACY_EVENT_MASK (7 << 8) +#define LEGACY_EVENT_ADDR_SHIFT 3 +#define LEGACY_EVENT_ADDR_MASK (0x1f << 3) +#define LEGACY_EVENT_TYPE_RW (1 << 2) +#define LEGACY_INT (1 << 0) + +#define SRC_RAM_WE (1 << 24) + +#define CODEC_READ (1 << 23) +#define CODEC_READY (1 << 31) + +#define INT_DAC1_EN (1 << 6) +#define INT_DAC2_EN (1 << 5) + +#define SI_P2_INTR_EN (1 << 9) +#define SI_P1_INTR_EN (1 << 8) + +#define INT_STATUS_INTR (1 << 31) +#define INT_STATUS_DAC1 (1 << 2) +#define INT_STATUS_DAC2 (1 << 1) + +#define FORMAT_MONO_8 0 +#define FORMAT_STEREO_8 1 +#define FORMAT_MONO_16 2 +#define FORMAT_STEREO_16 3 + +const int32_t codec_attn[]= +{ + 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, + 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, + 16422,20674,26027,32767 +}; + +static void es1371_fetch(es1371_t *es1371, int dac_nr); +static void update_legacy(es1371_t *es1371, uint32_t old_legacy_ctrl); + +static void es1371_update_irqs(es1371_t *es1371) +{ + int irq = 0; + + if ((es1371->int_status & INT_STATUS_DAC1) && (es1371->si_cr & SI_P1_INTR_EN)) + irq = 1; + if ((es1371->int_status & INT_STATUS_DAC2) && (es1371->si_cr & SI_P2_INTR_EN)) + irq = 1; + + if (irq) + es1371->int_status |= INT_STATUS_INTR; + else + es1371->int_status &= ~INT_STATUS_INTR; + + if (es1371->legacy_ctrl & LEGACY_FORCE_IRQ) + irq = 1; + + if (irq) + { + pci_set_irq(es1371->card, PCI_INTA); +// pclog("Raise IRQ\n"); + } + else + { + pci_clear_irq(es1371->card, PCI_INTA); +// pclog("Drop IRQ\n"); + } +} + +static uint8_t es1371_inb(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint8_t ret = 0; + + switch (port & 0x3f) + { + case 0x00: + ret = es1371->int_ctrl & 0xff; + break; + case 0x01: + ret = (es1371->int_ctrl >> 8) & 0xff; + break; + case 0x02: + ret = (es1371->int_ctrl >> 16) & 0xff; + break; + case 0x03: + ret = (es1371->int_ctrl >> 24) & 0xff; + break; + + case 0x04: + ret = es1371->int_status & 0xff; + break; + case 0x05: + ret = (es1371->int_status >> 8) & 0xff; + break; + case 0x06: + ret = (es1371->int_status >> 16) & 0xff; + break; + case 0x07: + ret = (es1371->int_status >> 24) & 0xff; + break; + + + case 0x09: + ret = es1371->uart_status; + break; + + case 0x0c: + ret = es1371->mem_page; + break; + + case 0x1a: + ret = es1371->legacy_ctrl >> 16; + break; + case 0x1b: + ret = es1371->legacy_ctrl >> 24; + break; + + case 0x20: + ret = es1371->si_cr & 0xff; + break; + case 0x21: + ret = es1371->si_cr >> 8; + break; + case 0x22: + ret = (es1371->si_cr >> 16) | 0x80; + break; + case 0x23: + ret = 0xff; + break; + + default: + pclog("Bad es1371_inb: port=%04x\n", port); + } + +// pclog("es1371_inb: port=%04x ret=%02x\n", port, ret); +// output = 3; + return ret; +} +static uint16_t es1371_inw(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint16_t ret = 0; + + switch (port & 0x3e) + { + case 0x00: + ret = es1371->int_ctrl & 0xffff; + break; + case 0x02: + ret = (es1371->int_ctrl >> 16) & 0xffff; + break; + + case 0x18: + ret = es1371->legacy_ctrl & 0xffff; +// pclog("Read legacy ctrl %04x\n", ret); + break; + + case 0x26: + ret = es1371->dac[0].curr_samp_ct; + break; + + case 0x2a: + ret = es1371->dac[1].curr_samp_ct; + break; + + case 0x36: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[0].count; + break; + + default: + pclog("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + case 0x3e: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[1].count; + break; + + default: + pclog("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + default: + pclog("Bad es1371_inw: port=%04x\n", port); + } + +// pclog("es1371_inw: port=%04x ret=%04x %04x:%08x\n", port, ret, CS,cpu_state.pc); + return ret; +} +static uint32_t es1371_inl(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint32_t ret = 0; + + switch (port & 0x3c) + { + case 0x00: + ret = es1371->int_ctrl; + break; + case 0x04: + ret = es1371->int_status; + break; + + case 0x10: + ret = es1371->sr_cir & ~0xffff; + ret |= es1371->sr_ram[es1371->sr_cir >> 25]; + break; + + case 0x14: + ret = es1371->codec_ctrl & 0x00ff0000; + ret |= es1371->codec_regs[(es1371->codec_ctrl >> 16) & 0x3f]; + ret |= CODEC_READY; + break; + + case 0x34: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[0].size | (es1371->dac[0].count << 16); + break; + + case 0xd: + ret = es1371->adc.size | (es1371->adc.count << 16); + break; + + default: + pclog("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + case 0x3c: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[1].size | (es1371->dac[1].count << 16); + break; + + default: + pclog("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + default: + pclog("Bad es1371_inl: port=%04x\n", port); + } + +// pclog("es1371_inl: port=%04x ret=%08x %08x\n", port, ret, cpu_state.pc); + return ret; +} + +static void es1371_outb(uint16_t port, uint8_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint32_t old_legacy_ctrl; + +// pclog("es1371_outb: port=%04x val=%02x %04x:%08x\n", port, val, cs, cpu_state.pc); + switch (port & 0x3f) + { + case 0x00: + if (!(es1371->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) + { + es1371->dac[0].addr = es1371->dac[0].addr_latch; + es1371->dac[0].buffer_pos = 0; + es1371->dac[0].buffer_pos_end = 0; + es1371_fetch(es1371, 0); + } + if (!(es1371->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) + { + es1371->dac[1].addr = es1371->dac[1].addr_latch; + es1371->dac[1].buffer_pos = 0; + es1371->dac[1].buffer_pos_end = 0; + es1371_fetch(es1371, 1); + } + es1371->int_ctrl = (es1371->int_ctrl & 0xffffff00) | val; + break; + case 0x01: + es1371->int_ctrl = (es1371->int_ctrl & 0xffff00ff) | (val << 8); + break; + case 0x02: + es1371->int_ctrl = (es1371->int_ctrl & 0xff00ffff) | (val << 16); + break; + case 0x03: + es1371->int_ctrl = (es1371->int_ctrl & 0x00ffffff) | (val << 24); + break; + + case 0x09: + es1371->uart_ctrl = val; + break; + + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x18: + es1371->legacy_ctrl |= LEGACY_INT; + nmi = 0; + break; + case 0x1a: + old_legacy_ctrl = es1371->legacy_ctrl; + es1371->legacy_ctrl = (es1371->legacy_ctrl & 0xff00ffff) | (val << 16); + update_legacy(es1371, old_legacy_ctrl); + break; + case 0x1b: + old_legacy_ctrl = es1371->legacy_ctrl; + es1371->legacy_ctrl = (es1371->legacy_ctrl & 0x00ffffff) | (val << 24); + es1371_update_irqs(es1371); +// output = 3; + update_legacy(es1371, old_legacy_ctrl); + break; + + case 0x20: + es1371->si_cr = (es1371->si_cr & 0xffff00) | val; + break; + case 0x21: + es1371->si_cr = (es1371->si_cr & 0xff00ff) | (val << 8); + if (!(es1371->si_cr & SI_P1_INTR_EN)) + es1371->int_status &= ~INT_STATUS_DAC1; + if (!(es1371->si_cr & SI_P2_INTR_EN)) + es1371->int_status &= ~INT_STATUS_DAC2; + es1371_update_irqs(es1371); + break; + case 0x22: + es1371->si_cr = (es1371->si_cr & 0x00ffff) | (val << 16); + break; + + default: + pclog("Bad es1371_outb: port=%04x val=%02x\n", port, val); + } +} +static void es1371_outw(uint16_t port, uint16_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + +// pclog("es1371_outw: port=%04x val=%04x\n", port, val); + switch (port & 0x3f) + { + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x24: + es1371->dac[0].samp_ct = val; + break; + + case 0x28: + es1371->dac[1].samp_ct = val; + break; + + default: + pclog("Bad es1371_outw: port=%04x val=%04x\n", port, val); + } +} +static void es1371_outl(uint16_t port, uint32_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + +// pclog("es1371_outl: port=%04x val=%08x %04x:%08x\n", port, val, CS, cpu_state.pc); + switch (port & 0x3f) + { + case 0x04: + break; + + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x10: + es1371->sr_cir = val; + if (es1371->sr_cir & SRC_RAM_WE) + { +// pclog("Write SR RAM %02x %04x\n", es1371->sr_cir >> 25, val & 0xffff); + es1371->sr_ram[es1371->sr_cir >> 25] = val & 0xffff; + switch (es1371->sr_cir >> 25) + { + case 0x71: + es1371->dac[0].vf = (es1371->dac[0].vf & ~0x1f8000) | ((val & 0xfc00) << 5); + es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + es1371->dac[0].f_pos = 0; + break; + case 0x72: + es1371->dac[0].ac = (es1371->dac[0].ac & ~0x7fff) | (val & 0x7fff); + break; + case 0x73: + es1371->dac[0].vf = (es1371->dac[0].vf & ~0x7fff) | (val & 0x7fff); + break; + + case 0x75: + es1371->dac[1].vf = (es1371->dac[1].vf & ~0x1f8000) | ((val & 0xfc00) << 5); + es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7f8000) | ((val & 0x00ff) << 15); + es1371->dac[1].f_pos = 0; + break; + case 0x76: + es1371->dac[1].ac = (es1371->dac[1].ac & ~0x7fff) | (val & 0x7fff); + break; + case 0x77: + es1371->dac[1].vf = (es1371->dac[1].vf & ~0x7fff) | (val & 0x7fff); + break; + + case 0x7c: + es1371->dac[0].vol_l = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7d: + es1371->dac[0].vol_r = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7e: + es1371->dac[1].vol_l = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7f: + es1371->dac[1].vol_r = (int32_t)(int16_t)(val & 0xffff); + break; + } + } + break; + + case 0x14: + es1371->codec_ctrl = val; + if (!(val & CODEC_READ)) + { +// pclog("Write codec %02x %04x\n", (val >> 16) & 0x3f, val & 0xffff); + es1371->codec_regs[(val >> 16) & 0x3f] = val & 0xffff; + switch ((val >> 16) & 0x3f) + { + case 0x02: /*Master volume*/ + if (val & 0x8000) + es1371->master_vol_l = es1371->master_vol_r = 0; + else + { + if (val & 0x2000) + es1371->master_vol_l = codec_attn[0]; + else + es1371->master_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)]; + if (val & 0x20) + es1371->master_vol_r = codec_attn[0]; + else + es1371->master_vol_r = codec_attn[0x1f - (val & 0x1f)]; + } + break; + case 0x12: /*CD volume*/ + if (val & 0x8000) + sound_set_cd_volume(0, 0); + else + sound_set_cd_volume(codec_attn[0x1f - ((val >> 8) & 0x1f)] * 2, codec_attn[0x1f - (val & 0x1f)] * 2); + break; + } + } + break; + + case 0x24: + es1371->dac[0].samp_ct = val & 0xffff; + break; + + case 0x28: + es1371->dac[1].samp_ct = val & 0xffff; + break; + + case 0x30: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[0].addr_latch = val; +// pclog("DAC1 addr %08x\n", val); + break; + + default: + pclog("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x34: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[0].size = val & 0xffff; + es1371->dac[0].count = val >> 16; + break; + + case 0xd: + es1371->adc.size = val & 0xffff; + es1371->adc.count = val >> 16; + break; + + default: + pclog("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x38: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[1].addr_latch = val; + break; + + case 0xd: + break; + + default: + pclog("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x3c: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[1].size = val & 0xffff; + es1371->dac[1].count = val >> 16; + break; + + default: + pclog("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + + default: + pclog("Bad es1371_outl: port=%04x val=%08x\n", port, val); + } +} + +static void capture_event(es1371_t *es1371, int type, int rw, uint16_t port) +{ + es1371->legacy_ctrl &= ~(LEGACY_EVENT_MASK | LEGACY_EVENT_ADDR_MASK); + es1371->legacy_ctrl |= type; + if (rw) + es1371->legacy_ctrl |= LEGACY_EVENT_TYPE_RW; + else + es1371->legacy_ctrl &= ~LEGACY_EVENT_TYPE_RW; + es1371->legacy_ctrl |= ((port << LEGACY_EVENT_ADDR_SHIFT) & LEGACY_EVENT_ADDR_MASK); + es1371->legacy_ctrl &= ~LEGACY_INT; + nmi = 1; +// pclog("Event! %s %04x\n", rw ? "write" : "read", port); +} + +static void capture_write_sscape(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SSCAPE, 1, port); +} +static void capture_write_codec(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_CODEC, 1, port); +} +static void capture_write_sb(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SB, 1, port); +} +static void capture_write_adlib(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_ADLIB, 1, port); +} +static void capture_write_master_pic(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_PIC, 1, port); +} +static void capture_write_master_dma(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_DMA, 1, port); +} +static void capture_write_slave_pic(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_PIC, 1, port); +} +static void capture_write_slave_dma(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_DMA, 1, port); +} + +static uint8_t capture_read_sscape(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SSCAPE, 0, port); + return 0xff; +} +static uint8_t capture_read_codec(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_CODEC, 0, port); + return 0xff; +} +static uint8_t capture_read_sb(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SB, 0, port); + return 0xff; +} +static uint8_t capture_read_adlib(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_ADLIB, 0, port); + return 0xff; +} +static uint8_t capture_read_master_pic(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_PIC, 0, port); + return 0xff; +} +static uint8_t capture_read_master_dma(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_DMA, 0, port); + return 0xff; +} +static uint8_t capture_read_slave_pic(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_PIC, 0, port); + return 0xff; +} +static uint8_t capture_read_slave_dma(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_DMA, 0, port); + return 0xff; +} + +static void update_legacy(es1371_t *es1371, uint32_t old_legacy_ctrl) +{ + if (old_legacy_ctrl & LEGACY_CAPTURE_SSCAPE) + { + switch ((old_legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) + { + case 0: io_removehandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 1: io_removehandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 2: io_removehandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 3: io_removehandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + } + } + if (old_legacy_ctrl & LEGACY_CAPTURE_CODEC) + { + switch ((old_legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) + { + case 0: io_removehandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + case 2: io_removehandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + case 3: io_removehandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + } + } + if (old_legacy_ctrl & LEGACY_CAPTURE_SB) + { + if (!(old_legacy_ctrl & LEGACY_SB_ADDR)) + io_removehandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + else + io_removehandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + } + if (old_legacy_ctrl & LEGACY_CAPTURE_ADLIB) + io_removehandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371); + if (old_legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) + io_removehandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371); + if (old_legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) + io_removehandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371); + if (old_legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) + io_removehandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371); + if (old_legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) + io_removehandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371); + + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SSCAPE) + { + switch ((es1371->legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) + { + case 0: io_sethandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 1: io_sethandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 2: io_sethandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 3: io_sethandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + } + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_CODEC) + { + switch ((es1371->legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) + { + case 0: io_sethandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + case 2: io_sethandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + case 3: io_sethandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + } + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SB) + { + if (!(es1371->legacy_ctrl & LEGACY_SB_ADDR)) + io_sethandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + else + io_sethandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_ADLIB) + io_sethandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) + io_sethandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) + io_sethandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) + io_sethandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) + io_sethandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371); +} + + +static uint8_t es1371_pci_read(int func, int addr, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + if (func) + return 0; + + //pclog("ES1371 PCI read %08X PC=%08x\n", addr, cpu_state.pc); + + switch (addr) + { + case 0x00: return 0x74; /*Ensoniq*/ + case 0x01: return 0x12; + + case 0x02: return 0x71; /*ES1371*/ + case 0x03: return 0x13; + + case 0x04: return es1371->pci_command; + case 0x05: return es1371->pci_serr; + + case 0x06: return 0x10; /*Supports ACPI*/ + case 0x07: return 0; + + case 0x08: return 2; /*Revision ID*/ + case 0x09: return 0x00; /*Multimedia audio device*/ + case 0x0a: return 0x01; + case 0x0b: return 0x04; + + case 0x10: return 0x01 | (es1371->base_addr & 0xc0); /*memBaseAddr*/ + case 0x11: return es1371->base_addr >> 8; + case 0x12: return es1371->base_addr >> 16; + case 0x13: return es1371->base_addr >> 24; + + case 0x2c: return 0x74; /*Subsystem vendor ID*/ + case 0x2d: return 0x12; + case 0x2e: return 0x71; + case 0x2f: return 0x13; + + case 0x34: return 0xdc; /*Capabilites pointer*/ + + case 0x3c: return es1371->int_line; + case 0x3d: return 0x01; /*INTA*/ + + case 0x3e: return 0xc; /*Minimum grant*/ + case 0x3f: return 0x80; /*Maximum latency*/ + + case 0xdc: return 0x01; /*Capabilities identifier*/ + case 0xdd: return 0x00; /*Next item pointer*/ + case 0xde: return 0x31; /*Power management capabilities*/ + case 0xdf: return 0x6c; + + case 0xe0: return es1371->pmcsr & 0xff; + case 0xe1: return es1371->pmcsr >> 8; + } + return 0; +} + +static void es1371_pci_write(int func, int addr, uint8_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + if (func) + return; + +// pclog("ES1371 PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc); + + switch (addr) + { + case 0x04: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->pci_command = val & 0x05; + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x05: + es1371->pci_serr = val & 1; + break; + + case 0x10: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->base_addr = (es1371->base_addr & 0xffffff00) | (val & 0xc0); + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x11: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->base_addr = (es1371->base_addr & 0xffff00c0) | (val << 8); + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x12: + es1371->base_addr = (es1371->base_addr & 0xff00ffc0) | (val << 16); + break; + case 0x13: + es1371->base_addr = (es1371->base_addr & 0x00ffffc0) | (val << 24); + break; + + case 0x3c: + es1371->int_line = val; + break; + + case 0xe0: + es1371->pmcsr = (es1371->pmcsr & 0xff00) | (val & 0x03); + break; + case 0xe1: + es1371->pmcsr = (es1371->pmcsr & 0x00ff) | ((val & 0x01) << 8); + break; + } +// pclog("es1371->base_addr %08x\n", es1371->base_addr); +} + +static void es1371_fetch(es1371_t *es1371, int dac_nr) +{ + int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3); + int pos = es1371->dac[dac_nr].buffer_pos & 63; + int c; + +//pclog("Fetch format=%i %08x %08x %08x %08x %08x\n", format, es1371->dac[dac_nr].count, es1371->dac[dac_nr].size, es1371->dac[dac_nr].curr_samp_ct,es1371->dac[dac_nr].samp_ct, es1371->dac[dac_nr].addr); + switch (format) + { + case FORMAT_MONO_8: + for (c = 0; c < 32; c += 4) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+1) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+2) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+2) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+2) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+3) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+3) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+3) ^ 0x80) << 8; + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 4; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_STEREO_8: + for (c = 0; c < 16; c += 2) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 1) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 2) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 3) ^ 0x80) << 8; + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 2; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_MONO_16: + for (c = 0; c < 16; c += 2) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr); + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2); + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 2; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_STEREO_16: + for (c = 0; c < 4; c++) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr); + es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2); +// pclog("Fetch %02x %08x %04x %04x\n", (pos+c) & 63, es1371->dac[dac_nr].addr, es1371->dac[dac_nr].buffer_l[(pos+c) & 63], es1371->dac[dac_nr].buffer_r[(pos+c) & 63]); + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end++; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + } +} + +static inline float low_fir_es1371(int dac_nr, int i, float NewSample) +{ + static float x[2][2][128]; //input samples + static int x_pos[2] = {0, 0}; + float out = 0.0; + int read_pos; + int n_coef; + int pos = x_pos[dac_nr]; + + x[dac_nr][i][pos] = NewSample; + + /*Since only 1/16th of input samples are non-zero, only filter those that + are valid.*/ + read_pos = (pos + 15) & (127 & ~15); + n_coef = (16 - pos) & 15; + + while (n_coef < ES1371_NCoef) + { + out += low_fir_es1371_coef[n_coef] * x[dac_nr][i][read_pos]; + read_pos = (read_pos + 16) & (127 & ~15); + n_coef += 16; + } + + if (i == 1) + { + x_pos[dac_nr] = (x_pos[dac_nr] + 1) & 127; + if (x_pos[dac_nr] > 127) + x_pos[dac_nr] = 0; + } + + return out; +} + +static void es1371_next_sample_filtered(es1371_t *es1371, int dac_nr, int out_idx) +{ + int out_l, out_r; + int c; + + if ((es1371->dac[dac_nr].buffer_pos - es1371->dac[dac_nr].buffer_pos_end) >= 0) + { + es1371_fetch(es1371, dac_nr); + } + + out_l = es1371->dac[dac_nr].buffer_l[es1371->dac[dac_nr].buffer_pos & 63]; + out_r = es1371->dac[dac_nr].buffer_r[es1371->dac[dac_nr].buffer_pos & 63]; + + es1371->dac[dac_nr].filtered_l[out_idx] = (int)low_fir_es1371(dac_nr, 0, (float)out_l); + es1371->dac[dac_nr].filtered_r[out_idx] = (int)low_fir_es1371(dac_nr, 1, (float)out_r); + for (c = 1; c < 16; c++) + { + es1371->dac[dac_nr].filtered_l[out_idx+c] = (int)low_fir_es1371(dac_nr, 0, 0); + es1371->dac[dac_nr].filtered_r[out_idx+c] = (int)low_fir_es1371(dac_nr, 1, 0); + } + +// pclog("Use %02x %04x %04x\n", es1371->dac[dac_nr].buffer_pos & 63, es1371->dac[dac_nr].out_l, es1371->dac[dac_nr].out_r); + + es1371->dac[dac_nr].buffer_pos++; +// pclog("Next sample %08x %08x %08x\n", es1371->dac[dac_nr].buffer_pos, es1371->dac[dac_nr].buffer_pos_end, es1371->dac[dac_nr].curr_samp_ct); +} + +//static FILE *es1371_f;//,*es1371_f2; + +static void es1371_update(es1371_t *es1371) +{ + int32_t l, r; + + l = (es1371->dac[0].out_l * es1371->dac[0].vol_l) >> 12; + l += ((es1371->dac[1].out_l * es1371->dac[1].vol_l) >> 12); + r = (es1371->dac[0].out_r * es1371->dac[0].vol_r) >> 12; + r += ((es1371->dac[1].out_r * es1371->dac[1].vol_r) >> 12); + + l >>= 1; + r >>= 1; + + l = (l * es1371->master_vol_l) >> 15; + r = (r * es1371->master_vol_r) >> 15; + + if (l < -32768) + l = -32768; + else if (l > 32767) + l = 32767; + if (r < -32768) + r = -32768; + else if (r > 32767) + r = 32767; + + for (; es1371->pos < sound_pos_global; es1371->pos++) + { + es1371->buffer[es1371->pos*2] = l; + es1371->buffer[es1371->pos*2 + 1] = r; + } +} + +static void es1371_poll(void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + timer_advance_u64(&es1371->dac[1].timer, es1371->dac[1].latch); + + es1371_update(es1371); + + if (es1371->int_ctrl & INT_DAC1_EN) + { + int frac = es1371->dac[0].ac & 0x7fff; + int idx = es1371->dac[0].ac >> 15; + int samp1_l = es1371->dac[0].filtered_l[idx]; + int samp1_r = es1371->dac[0].filtered_r[idx]; + int samp2_l = es1371->dac[0].filtered_l[(idx + 1) & 31]; + int samp2_r = es1371->dac[0].filtered_r[(idx + 1) & 31]; + + es1371->dac[0].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; + es1371->dac[0].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; +// pclog("1Samp %i %i %08x\n", es1371->dac[0].curr_samp_ct, es1371->dac[0].samp_ct, es1371->dac[0].ac); + es1371->dac[0].ac += es1371->dac[0].vf; + es1371->dac[0].ac &= ((32 << 15) - 1); + if ((es1371->dac[0].ac >> (15+4)) != es1371->dac[0].f_pos) + { + es1371_next_sample_filtered(es1371, 0, es1371->dac[0].f_pos ? 16 : 0); + es1371->dac[0].f_pos = (es1371->dac[0].f_pos + 1) & 1; + + es1371->dac[0].curr_samp_ct--; + if (es1371->dac[0].curr_samp_ct < 0) + { +// pclog("DAC1 IRQ\n"); + es1371->int_status |= INT_STATUS_DAC1; + es1371_update_irqs(es1371); + es1371->dac[0].curr_samp_ct = es1371->dac[0].samp_ct; + } + } + } + + if (es1371->int_ctrl & INT_DAC2_EN) + { + int frac = es1371->dac[1].ac & 0x7fff; + int idx = es1371->dac[1].ac >> 15; + int samp1_l = es1371->dac[1].filtered_l[idx]; + int samp1_r = es1371->dac[1].filtered_r[idx]; + int samp2_l = es1371->dac[1].filtered_l[(idx + 1) & 31]; + int samp2_r = es1371->dac[1].filtered_r[(idx + 1) & 31]; + + es1371->dac[1].out_l = ((samp1_l * (0x8000 - frac)) + (samp2_l * frac)) >> 15; + es1371->dac[1].out_r = ((samp1_r * (0x8000 - frac)) + (samp2_r * frac)) >> 15; +// pclog("2Samp %i %i %08x\n", es1371->dac[1].curr_samp_ct, es1371->dac[1].samp_ct, es1371->dac[1].ac); + es1371->dac[1].ac += es1371->dac[1].vf; + es1371->dac[1].ac &= ((32 << 15) - 1); + if ((es1371->dac[1].ac >> (15+4)) != es1371->dac[1].f_pos) + { + es1371_next_sample_filtered(es1371, 1, es1371->dac[1].f_pos ? 16 : 0); + es1371->dac[1].f_pos = (es1371->dac[1].f_pos + 1) & 1; + + es1371->dac[1].curr_samp_ct--; + if (es1371->dac[1].curr_samp_ct < 0) + { +// pclog("DAC2 IRQ\n"); + es1371->int_status |= INT_STATUS_DAC2; + es1371_update_irqs(es1371); + es1371->dac[1].curr_samp_ct = es1371->dac[1].samp_ct; + } + } + } +} + +static void es1371_get_buffer(int32_t *buffer, int len, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + int c; + + es1371_update(es1371); + + for (c = 0; c < len * 2; c++) + buffer[c] += (es1371->buffer[c] / 2); + + es1371->pos = 0; +} + +static inline double sinc(double x) +{ + return sin(M_PI * x) / (M_PI * x); +} + +static void generate_es1371_filter() +{ + /*Cutoff frequency = 1 / 32*/ + float fC = 1.0 / 32.0; + float gain; + int n; + + for (n = 0; n < ES1371_NCoef; n++) + { + /*Blackman window*/ + double w = 0.42 - (0.5 * cos((2.0*n*M_PI)/(double)(ES1371_NCoef-1))) + (0.08 * cos((4.0*n*M_PI)/(double)(ES1371_NCoef-1))); + /*Sinc filter*/ + double h = sinc(2.0 * fC * ((double)n - ((double)(ES1371_NCoef-1) / 2.0))); + + /*Create windowed-sinc filter*/ + low_fir_es1371_coef[n] = w * h; + } + + low_fir_es1371_coef[(ES1371_NCoef - 1) / 2] = 1.0; + + gain = 0.0; + for (n = 0; n < ES1371_NCoef; n++) + gain += low_fir_es1371_coef[n] / (float)N; + + gain /= 0.95; + + /*Normalise filter, to produce unity gain*/ + for (n = 0; n < ES1371_NCoef; n++) + low_fir_es1371_coef[n] /= gain; +} + +static void *es1371_init() +{ + es1371_t *es1371 = malloc(sizeof(es1371_t)); + memset(es1371, 0, sizeof(es1371_t)); + + sound_add_handler(es1371_get_buffer, es1371); + + es1371->card = pci_add(es1371_pci_read, es1371_pci_write, es1371); + + timer_add(&es1371->dac[1].timer, es1371_poll, es1371, 1); + + generate_es1371_filter(); + + return es1371; +} + +static void es1371_close(void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + free(es1371); +} + +static void es1371_speed_changed(void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + es1371->dac[1].latch = (uint64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); +} + +void es1371_add_status_info_dac(es1371_t *es1371, char *s, int max_len, int dac_nr) +{ + int ena = dac_nr ? INT_DAC2_EN : INT_DAC1_EN; + char *dac_name = dac_nr ? "DAC2 (Wave)" : "DAC1 (MIDI)"; + char temps[128]; + + if (es1371->int_ctrl & ena) + { + int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3); + double freq = 48000.0 * ((double)es1371->dac[dac_nr].vf / (32768.0 * 16.0)); + + switch (format) + { + case FORMAT_MONO_8: + snprintf(temps, 128, "%s format : 8-bit mono\n", dac_name); + break; + case FORMAT_STEREO_8: + snprintf(temps, 128, "%s format : 8-bit stereo\n", dac_name); + break; + case FORMAT_MONO_16: + snprintf(temps, 128, "%s format : 16-bit mono\n", dac_name); + break; + case FORMAT_STEREO_16: + snprintf(temps, 128, "%s format : 16-bit stereo\n", dac_name); + break; + } + + strncat(s, temps, max_len); + max_len -= strlen(temps); + + snprintf(temps, 128, "Playback frequency : %i Hz\n", (int)freq); + strncat(s, temps, max_len); + } + else + { + snprintf(temps, max_len, "%s stopped\n", dac_name); + strncat(s, temps, max_len); + } +} + +void es1371_add_status_info(char *s, int max_len, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + es1371_add_status_info_dac(es1371, s, max_len, 0); + es1371_add_status_info_dac(es1371, s, max_len, 1); +} + +device_t es1371_device = +{ + "Ensoniq AudioPCI (ES1371)", + 0, + es1371_init, + es1371_close, + NULL, + es1371_speed_changed, + NULL, + es1371_add_status_info, + NULL +}; diff --git a/src/sound_audiopci.h b/src/sound_audiopci.h new file mode 100644 index 0000000..726b1d0 --- /dev/null +++ b/src/sound_audiopci.h @@ -0,0 +1 @@ +extern device_t es1371_device; diff --git a/src/sound_azt2316a.c b/src/sound_azt2316a.c new file mode 100644 index 0000000..da41bce --- /dev/null +++ b/src/sound_azt2316a.c @@ -0,0 +1,1620 @@ +/* + * TYPE 0x11: (Washington) + * Aztech MMPRO16AB, + * Aztech Sound Galaxy Pro 16 AB + * Aztech Sound Galaxy Washington 16 + * Packard Bell Sound 16A + * ...and other OEM names + * FCC ID I38-MMSN824 and others + * + * TYPE 0x0C: (Clinton) + * Aztech Sound Galaxy Nova 16 Extra + * Aztech Sound Galaxy Clinton 16 + * Packard Bell Forte 16 + * ...and other OEM names + * + * Also works more or less for drivers of other models with the same chipsets. + * + * Copyright (c) 2020 Eluan Costa Miranda All rights reserved. + * + * 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 3 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, see . + * + * ============================================================================= + * + * The CS4248 DSP used is pin and software compatible with the AD1848. + * I also have one of these cards with a CS4231. The driver talks to the + * emulated card as if it was a CS4231 and I still don't know how to tell the + * drivers to see the CS4248. The CS4231 more advanced features are NOT used, + * just the new input/output channels. Apparently some drivers are hardcoded + * for one or the other, so there is an option for this. + * + * There is lots more to be learned form the Win95 drivers. The Linux driver is + * very straightforward and doesn't do much. + * + * Recording and voice modes in the windows mixer still do nothing in PCem, so + * this is missing. + * + * There is a jumper to load the startup configuration from an EEPROM. This is + * implemented, so any software-configured parameters will be saved. + * + * The CD-ROM interface commands are just ignored, along with gameport. + * The MPU401 is always enabled. + * The OPL3 is always active in some (all?) drivers/cards, so there is no + * configuration for this. + * + * Tested with DOS (driver installation, tools, diagnostics), Win3.1 (driver + * installation, tools), Win95 (driver auto-detection), Win NT 3.1 (driver + * installation), lots of games. + * + * I consider type 0x11 (Washington) to be very well tested. Type 0x0C (Clinton) + * wasn't fully tested, but works well for WSS/Windows. BEWARE that there are + * *too many* driver types and OEM versions for each card. Maybe yours isn't + * emulated or you have the wrong driver. Some features of each card may work + * when using wrong drivers. CODEC selection is also important. + * + * Any updates to the WSS and SBPROV2 sound cards should be synced here when + * appropriate. The WSS was completely cloned here, while the SBPROV2 tends + * to call the original functions, except for initialization. + * + * TODO/Notes: + * -Some stuff still not understood on I/O addresses 0x624 and 0x530-0x533. + * -Is the CS42xx dither mode used anywhere? Implement. + * -What are the voice commands mode in Win95 mixer again? + * -Configuration options not present on Aztech's CONFIG.EXE have been commented + * out or deleted. Other types of cards with this chipset may need them. + * -Sfademo on the Descent CD fails under Win95, works under DOS, see if it + * happens on real hardware (and OPL3 stops working after the failure) + * -There appears to be some differences in sound volumes bertween MIDI, + * SBPROV2, WSS and OPL3? Also check relationship between the SBPROV2 mixer and + * the WSS mixer! Are they independent? Current mode selects which mixer? Are + * they entangled? + * -Check real hardware to see if advanced, mic boost, etc appear in the mixer? + * -CD-ROM driver shipped with the card (SGIDECD.SYS) checks for model strings. + * I have implemented mine (AZtech CDA 468-02I 4x) in PCem. + * -Descent 2 W95 version can't start cd music. Happens on real hardware. + * Explanation further below. + * -DOSQuake and Descent 2 DOS cd music do not work under Win95. The mode + * selects get truncated and send all zeros for output channel selection and + * volume, Descent 2 also has excess zeros! This is a PCem bug, happens on all + * sound cards. CD audio works in Winquake and Descent 2 DOS setup program. + * -DOSQuake CD audio works under DOS with VIDE-CDD.SYS and SGIDECD.SYS. + * Descent 2 DOS is still mute but volume selection appears to be working. + * Descent 2 fails to launch with SGIDECD.SYS with "Device failed to request + * command". SGIDECD.SYS is the CD-ROM driver included with the sound card + * drivers. My real CD-ROM drive can't read anything so I can't check the + * real behavior of this driver. + * -Some cards just have regular IDE ports while other have proprietary ports. + * The regular IDE ports just have a option to enable an almost-generic CD-ROM + * driver in CONFIG.SYS/AUTOEXEC.BAT (like SGIDECD.SYS) and the onboard port + * is enabled/disabled by jumpers. The proprietary ones also have + * address/dma/irq settings. Since the configuration options are ignored here, + * this behaves like a card with a regular interface disabled by jumper and + * the configuration just adds/removes the drivers (which will see other IDE + * interfaces present) from the boot process. + * -Continue reverse engineering to see if the AZT1605 shares the SB DMA with + * WSS or if it is set separately by the TSR loaded on boot. Currently it is + * only set by PCem config and then saved to EEPROM (which would make it fixed + * if loading from EEPROM too). + * -Related to the previous note, part of the SBPROV2 emulation on the CLINTON + * family appears to be implemented with a TSR. It's better to remove the TSR + * for now. I need to investigate this. Mixer is also weird under DOS (and + * wants to save to EEPROM? I don't think the WASHINGTON does this). + * -VOLSET.EXE /S:S is supposed to be a no-op on the MMP16AB? + * -Search for TODO in this file. :-) + * + * Misc things I use to test for regressions: Windows sounds, Descent under + * dos/windows, Descent 2 dos/windows (+ cd music option), Descent 2 W95 + cd + * music, Age of Empires (CD + Midi), cd-audio under Windows + volume, + * cd-audio under dos + volume, Aztech diagnose.exe, Aztech volset /M:3 then + * volset /D, Aztech setmode, mixer (volume + balance) under dos and windows, + * DOSQuake under dos and windows (+ cd music and volumes, + Winquake). + * + * Reason for Descent 2 Win95 CD-Audio not working: + * The game calls auxGetNumDevs() to check if any of the AUX devices has + * caps.wTechnology == AUXCAPS_CDAUDIO, but this fails because the Aztech + * Win95 driver only returns a "Line-In" device. I'm not aware of any other + * game that does this and this is completely unnecessary. Other games that + * play cd audio correctly have the exact *same* initialization code, minus + * this check that only Descent 2 Win95 does. It would work if it just skipped + * this check and progressed with calling mciSendCommand() with + * mciOpenParms.lpstrDeviceType = "cdaudio", like other games do. There are + * some sound cards listed as incompatible in the game's README.TXT file that + * are probably due to this. + */ + +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "nvr.h" +#include "pic.h" +#include "sound.h" +#include "sound_ad1848.h" +#include "sound_azt2316a.h" +#include "sound_opl.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" + +/*530, 11, 3 - 530=23*/ +/*530, 11, 1 - 530=22*/ +/*530, 11, 0 - 530=21*/ +/*530, 10, 1 - 530=1a*/ +/*530, 10, 0 - 530=19*/ +/*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 azt2316a_wss_dma[4] = {0, 0, 1, 3}; +static int azt2316a_wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /* W95 only uses 7-10, others may be wrong */ +//static uint16_t azt2316a_wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; + +typedef struct azt2316a_t +{ + int type; + int wss_interrupt_after_config; + + uint8_t wss_config; + + uint16_t cur_addr, cur_wss_addr, cur_mpu401_addr; + + uint8_t cur_irq, cur_dma, opl_emu; // sb + uint8_t cur_wss_enabled, cur_wss_irq, cur_wss_dma; + uint8_t cur_mpu401_irq; + + uint32_t config_word; + uint32_t config_word_unlocked; + + uint8_t cur_mode; + + ad1848_t ad1848; + + sb_t *sb; +} azt2316a_t; + +uint8_t azt2316a_wss_read(uint16_t addr, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; +// pclog("azt2316a_read - addr %04X\n", addr); + // TODO: when windows is initializing, writing 0x48, 0x58 and 0x60 to + // 0x530 makes reading from 0x533 return 0x44, but writing 0x50 + // makes this return 0x04. Why? + if (addr & 1) + temp = 4 | (azt2316a->wss_config & 0x40); + else + temp = 4 | (azt2316a->wss_config & 0xC0); +// pclog("return %02X\n", temp); + return temp; +} + +void azt2316a_wss_write(uint16_t addr, uint8_t val, void *p) +{ + int interrupt = 0; + azt2316a_t *azt2316a = (azt2316a_t *)p; +// pclog("azt2316a_write - addr %04X val %02X\n", addr, val); + + if (azt2316a->wss_interrupt_after_config) + if ((azt2316a->wss_config & 0x40) && !(val & 0x40)) // TODO: is this the right edge? + interrupt = 1; + + azt2316a->wss_config = val; + azt2316a->cur_wss_dma = azt2316a_wss_dma[val & 3]; + azt2316a->cur_wss_irq = azt2316a_wss_irq[(val >> 3) & 7]; + ad1848_setdma(&azt2316a->ad1848, azt2316a_wss_dma[val & 3]); + ad1848_setirq(&azt2316a->ad1848, azt2316a_wss_irq[(val >> 3) & 7]); + + if (interrupt) + picint(1 << azt2316a->cur_wss_irq); +} + +// generate a config word based on current settings +void azt1605_create_config_word(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint32_t temp = 0; + + // not implemented / hardcoded + uint8_t game_enable = 1; + uint8_t mpu401_enable = 1; + uint8_t cd_type = 0; // TODO: see if the cd-rom was originally connected there on the real machines emulated by PCem (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) + uint8_t cd_dma8 = -1; + uint8_t cd_irq = 0; + + switch (azt2316a->cur_addr) + { + case 0x220: + // do nothing + //temp += 0 << 0; + break; + case 0x240: + temp += 1 << 0; + break; +/* + case 0x260: // TODO: INVALID? + temp += 2 << 0; + break; + case 0x280: // TODO: INVALID? + temp += 3 << 0; + break; +*/ + default: + fatal("Bad AZT1605 addr %04X\n", azt2316a->cur_addr); + } + switch (azt2316a->cur_irq) + { + case 2: + temp += 1 << 8; + break; + case 3: + temp += 1 << 9; + break; + case 5: + temp += 1 << 10; + break; + case 7: + temp += 1 << 11; + break; + default: + fatal("Bad AZT1605 irq %02X\n", azt2316a->cur_irq); + } + switch (azt2316a->cur_wss_addr) + { + case 0x530: + // do nothing + //temp += 0 << 16; + break; + case 0x604: + temp += 1 << 16; + break; + case 0xE80: + temp += 2 << 16; + break; + case 0xF40: + temp += 3 << 16; + break; + default: + fatal("Bad AZT1605 WSS addr %04X\n", azt2316a->cur_wss_addr); + } + if (azt2316a->cur_wss_enabled) + temp += 1 << 18; + if (game_enable) + temp += 1 << 4; + switch (azt2316a->cur_mpu401_addr) + { + case 0x300: + // do nothing + //temp += 0 << 2; + break; + case 0x330: + temp += 1 << 2; + break; + default: + fatal("Bad AZT1605 MPU401 addr %04X\n", azt2316a->cur_mpu401_addr); + } + if (mpu401_enable) + temp += 1 << 3; + switch (cd_type) + { + case 0: // disabled + // do nothing + //temp += 0 << 5; + break; + case 1: // panasonic + temp += 1 << 5; + break; + case 2: // mitsumi/sony/aztech + temp += 2 << 5; + break; + case 3: // all enabled + temp += 3 << 5; + break; + case 4: // unused + temp += 4 << 5; + break; + case 5: // unused + temp += 5 << 5; + break; + case 6: // unused + temp += 6 << 5; + break; + case 7: // unused + temp += 7 << 5; + break; + default: + fatal("Bad AZT1605 CD type %02X\n", cd_type); + } + switch (cd_dma8) + { + case 0xFF: // -1 + // do nothing + //temp += 0 << 22; + break; + case 0: + temp += 1 << 22; + break; + case 1: + temp += 2 << 22; + break; + case 3: + temp += 3 << 22; + break; + default: + fatal("Bad AZT1605 cd dma8 %02X\n", cd_dma8); + + } + switch (azt2316a->cur_mpu401_irq) + + { + case 2: + temp += 1 << 12; + break; + case 3: + temp += 1 << 13; + break; + case 5: + temp += 1 << 14; + break; + case 7: + temp += 1 << 15; + break; + default: + fatal("Bad AZT1605 mpu401 irq %02X\n", azt2316a->cur_mpu401_irq); + } + switch (cd_irq) + { + case 0: // disabled + // do nothing + break; + case 11: + temp += 1 << 19; + break; + case 12: + temp += 1 << 20; + break; + case 15: + temp += 1 << 21; + break; + default: + fatal("Bad AZT1605 cd irq %02X\n", cd_irq); + } + + azt2316a->config_word = temp; +} +void azt2316a_create_config_word(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint32_t temp = 0; + + // not implemented / hardcoded + uint8_t game_enable = 1; + uint8_t mpu401_enable = 1; + uint16_t cd_addr = 0x310; + uint8_t cd_type = 0; // TODO: see if the cd-rom was originally connected there on the real machines emulated by PCem (Packard Bell Legend 100CD, Itautec Infoway Multimidia, etc) + uint8_t cd_dma8 = -1; + uint8_t cd_dma16 = -1; + uint8_t cd_irq = 15; + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + azt1605_create_config_word(p); + return; + } + + switch (azt2316a->cur_addr) + { + case 0x220: + // do nothing + //temp += 0 << 0; + break; + case 0x240: + temp += 1 << 0; + break; +/* + case 0x260: // TODO: INVALID? + temp += 2 << 0; + break; + case 0x280: // TODO: INVALID? + temp += 3 << 0; + break; +*/ + default: + fatal("Bad AZT2316A addr %04X\n", azt2316a->cur_addr); + } + switch (azt2316a->cur_irq) + { + case 2: + temp += 1 << 2; + break; + case 5: + temp += 1 << 3; + break; + case 7: + temp += 1 << 4; + break; + case 10: + temp += 1 << 5; + break; + default: + fatal("Bad AZT2316A irq %02X\n", azt2316a->cur_irq); + } + switch (azt2316a->cur_dma) + { +/* + // TODO: INVALID? + case 0xFF: // -1 + // do nothing + //temp += 0 << 6; + break; +*/ + case 0: + temp += 1 << 6; + break; + case 1: + temp += 2 << 6; + break; + case 3: + temp += 3 << 6; + break; + default: + fatal("Bad AZT2316A dma %02X\n", azt2316a->cur_dma); + } + switch (azt2316a->cur_wss_addr) + { + case 0x530: + // do nothing + //temp += 0 << 8; + break; + case 0x604: + temp += 1 << 8; + break; + case 0xE80: + temp += 2 << 8; + break; + case 0xF40: + temp += 3 << 8; + break; + default: + fatal("Bad AZT2316A WSS addr %04X\n", azt2316a->cur_wss_addr); + } + if (azt2316a->cur_wss_enabled) + temp += 1 << 10; + if (game_enable) + temp += 1 << 11; + switch (azt2316a->cur_mpu401_addr) + { + case 0x300: + // do nothing + //temp += 0 << 12; + break; + case 0x330: + temp += 1 << 12; + break; + default: + fatal("Bad AZT2316A MPU401 addr %04X\n", azt2316a->cur_mpu401_addr); + } + if (mpu401_enable) + temp += 1 << 13; + switch (cd_addr) + { + case 0x310: + // do nothing + //temp += 0 << 14; + break; + case 0x320: + temp += 1 << 14; + break; + case 0x340: + temp += 2 << 14; + break; + case 0x350: + temp += 3 << 14; + break; + default: + fatal("Bad AZT2316A CD addr %04X\n", cd_addr); + } + switch (cd_type) + { + case 0: // disabled + // do nothing + //temp += 0 << 16; + break; + case 1: // panasonic + temp += 1 << 16; + break; + case 2: // sony + temp += 2 << 16; + break; + case 3: // mitsumi + temp += 3 << 16; + break; + case 4: // aztech + temp += 4 << 16; + break; + case 5: // unused + temp += 5 << 16; + break; + case 6: // unused + temp += 6 << 16; + break; + case 7: // unused + temp += 7 << 16; + break; + default: + fatal("Bad AZT2316A CD type %02X\n", cd_type); + } + switch (cd_dma8) + { + case 0xFF: // -1 + // do nothing + //temp += 0 << 20; + break; + case 0: + temp += 1 << 20; + break; +/* + case 1: // TODO: INVALID? + temp += 2 << 20; + break; +*/ + case 3: + temp += 3 << 20; + break; + default: + fatal("Bad AZT2316A cd dma8 %02X\n", cd_dma8); + } + switch (cd_dma16) + { + case 0xFF: // -1 + // do nothing + //temp += 0 << 22; + break; + case 5: + temp += 1 << 22; + break; + case 6: + temp += 2 << 22; + break; + case 7: + temp += 3 << 22; + break; + default: + fatal("Bad AZT2316A cd dma16 %02X\n", cd_dma16); + } + switch (azt2316a->cur_mpu401_irq) + + { + case 2: + temp += 1 << 24; + break; + case 5: + temp += 1 << 25; + break; + case 7: + temp += 1 << 26; + break; + case 10: + temp += 1 << 27; + break; + default: + fatal("Bad AZT2316A mpu401 irq %02X\n", azt2316a->cur_mpu401_irq); + } + switch (cd_irq) + { + case 5: + temp += 1 << 28; + break; + case 11: + temp += 1 << 29; + break; + case 12: + temp += 1 << 30; + break; + case 15: + temp += 1 << 31; + break; + default: + fatal("Bad AZT2316A cd irq %02X\n", cd_irq); + } + + azt2316a->config_word = temp; +} + +uint8_t azt2316a_config_read(uint16_t addr, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; +// pclog("azt2316a_config_read - addr %04X\n", addr); + + // Some WSS config here + config change enable bit + // (setting bit 7 and writing back) + if (addr == azt2316a->cur_addr + 0x404) + { + // TODO: what is the real meaning of the read value? + // I got a mention of bit 0x10 for WSS from disassembling the source + // code of the driver, and when playing with the I/O ports on real + // hardware after doing some configuration, but didn't dig into it. + // Bit 0x08 seems to be a busy flag and generates a timeout + // (continuous re-reading when initializing windows 98) + temp = azt2316a->cur_mode ? 0x07 : 0x0F; + if (azt2316a->config_word_unlocked) + temp |= 0x80; + } + else + { + // Rest of config. These are documented in the Linux driver. + switch (addr & 0x3) + { + case 0: + temp = azt2316a->config_word & 0xFF; + break; + case 1: + temp = (azt2316a->config_word >> 8) & 0xFF; + break; + case 2: + temp = (azt2316a->config_word >> 16) & 0xFF; + break; + case 3: + temp = (azt2316a->config_word >> 24) & 0xFF; + break; + } + } + +// pclog("return %02X\n", temp); + return temp; +} + +void azt1605_config_write(uint16_t addr, uint8_t val, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; +// pclog("azt2316a_config_write - addr %04X val %02X\n", addr, val); + + if (addr == azt2316a->cur_addr + 0x404) + { + if (val & 0x80) + azt2316a->config_word_unlocked = 1; + else + azt2316a->config_word_unlocked = 0; + } + else if (azt2316a->config_word_unlocked) + { + if (val == 0xFF) // TODO: check if this still happens on eeprom.sys after having more complete emulation! + return; + switch (addr & 0x3) + { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) + val; + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; +/* + else if (temp == 2) + azt2316a->cur_addr = 0x260; // TODO: INVALID + else if (temp == 3) + azt2316a->cur_addr = 0x280; // TODO: INVALID +*/ + + if (val & 0x4) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + // mpu401_enabled is harcoded + //if (val & 0x8) + // azt2316a->cur_mpu401_enabled = 1; + //else + // azt2316a->cur_mpu401_enabled = 0; + + // game_enabled is hardcoded + //if (val & 0x10) + // azt2316a->cur_game_enabled = 1; + //else + // azt2316a->cur_game_enabled = 0; + + // cd_type is hardcoded + //azt2316a->cur_cd_type = (val >> 5) & 0x7; + break; + case 1: + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) + (val << 8); + + if (val & 0x1) + azt2316a->cur_irq = 2; + else if (val & 0x2) + azt2316a->cur_irq = 3; + else if (val & 0x4) + azt2316a->cur_irq = 5; + else if (val & 0x8) + azt2316a->cur_irq = 7; + // else undefined? + + if (val & 0x10) + azt2316a->cur_mpu401_irq = 2; + else if (val & 0x20) + azt2316a->cur_mpu401_irq = 3; + else if (val & 0x40) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x80) + azt2316a->cur_mpu401_irq = 7; + // else undefined? + break; + case 2: + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) + (val << 16); + + io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_wss_addr = 0x530; + else if (temp == 1) + azt2316a->cur_wss_addr = 0x604; + else if (temp == 2) + azt2316a->cur_wss_addr = 0xE80; + else if (temp == 3) + azt2316a->cur_wss_addr = 0xF40; + + io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + // no actual effect + if (val & 0x4) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + // cd_irq is hardcoded + //if (val & 0x8) + // azt2316a->cur_cd_irq = 11; + //else if (val & 0x10) + // azt2316a->cur_cd_irq = 12; + //else if (val & 0x20) + // azt2316a->cur_cd_irq = 15; + // else disable? + + // cd_dma8 is hardcoded + //temp = (val >> 6) & 0x3; + //if (temp == 0) + // azt2316a->cur_cd_dma8 = -1; + //else if (temp == 1) + // azt2316a->cur_cd_dma8 = 0; + //else if (temp == 3) + // azt2316a->cur_cd_dma8 = 3; + //else error + break; + case 3: + break; + } + // update sbprov2 configs + sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); + sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); + sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); + + mpu401_uart_update_addr(&azt2316a->sb->mpu, azt2316a->cur_mpu401_addr); + mpu401_uart_update_irq(&azt2316a->sb->mpu, azt2316a->cur_mpu401_irq); + } +} +void azt2316a_config_write(uint16_t addr, uint8_t val, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + uint8_t temp; +// pclog("azt2316a_config_write - addr %04X val %02X\n", addr, val); + + if (azt2316a->type == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + azt1605_config_write(addr, val, p); + return; + } + + if (addr == azt2316a->cur_addr + 0x404) + { + if (val & 0x80) + azt2316a->config_word_unlocked = 1; + else + azt2316a->config_word_unlocked = 0; + } + else if (azt2316a->config_word_unlocked) + { + if (val == 0xFF) // TODO: check if this still happens on eeprom.sys after having more complete emulation! + return; + switch (addr & 0x3) + { + case 0: + azt2316a->config_word = (azt2316a->config_word & 0xFFFFFF00) + val; + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_addr = 0x220; + else if (temp == 1) + azt2316a->cur_addr = 0x240; +/* + else if (temp == 2) + azt2316a->cur_addr = 0x260; // TODO: INVALID + else if (temp == 3) + azt2316a->cur_addr = 0x280; // TODO: INVALID +*/ + + if (val & 0x4) + azt2316a->cur_irq = 2; + else if (val & 0x8) + azt2316a->cur_irq = 5; + else if (val & 0x10) + azt2316a->cur_irq = 7; + else if (val & 0x20) + azt2316a->cur_irq = 10; + // else undefined? + + temp = (val >> 6) & 0x3; +/* + if (temp == 0) + azt2316a->cur_dma = -1; // TODO: INVALID? + else */if (temp == 1) + azt2316a->cur_dma = 0; + else if (temp == 2) + azt2316a->cur_dma = 1; + else if (temp == 3) + azt2316a->cur_dma = 3; + break; + case 1: + azt2316a->config_word = (azt2316a->config_word & 0xFFFF00FF) + (val << 8); + + io_removehandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_removehandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + temp = val & 0x3; + if (temp == 0) + azt2316a->cur_wss_addr = 0x530; + else if (temp == 1) + azt2316a->cur_wss_addr = 0x604; + else if (temp == 2) + azt2316a->cur_wss_addr = 0xE80; + else if (temp == 3) + azt2316a->cur_wss_addr = 0xF40; + + io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + // no actual effect + if (val & 0x4) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + // game_enabled is hardcoded + //if (val & 0x8) + // azt2316a->cur_game_enabled = 1; + //else + // azt2316a->cur_game_enabled = 0; + + if (val & 0x10) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + // mpu401_enabled is harcoded + //if (val & 0x20) + // azt2316a->cur_mpu401_enabled = 1; + //else + // azt2316a->cur_mpu401_enabled = 0; + + // cd_addr is hardcoded + //temp = (val >> 6) & 0x3; + //if (temp == 0) + // azt2316a->cur_cd_addr = 0x310; + //else if (temp == 1) + // azt2316a->cur_cd_addr = 0x320; + //else if (temp == 2) + // azt2316a->cur_cd_addr = 0x340; + //else if (temp == 3) + // azt2316a->cur_cd_addr = 0x350; + break; + case 2: + azt2316a->config_word = (azt2316a->config_word & 0xFF00FFFF) + (val << 16); + + // cd_type is hardcoded + //azt2316a->cur_cd_type = val & 0x7; + + // cd_dma8 is hardcoded + //temp = (val >> 4) & 0x3; + //if (temp == 0) + // azt2316a->cur_cd_dma8 = -1; + //else if (temp == 1) + // azt2316a->cur_cd_dma8 = 0; + //else if (temp == 2) + // azt2316a->cur_cd_dma8 = 1; + //else if (temp == 3) + // azt2316a->cur_cd_dma8 = 3; + + // cd_dma16 is hardcoded + //temp = (val >> 6) & 0x3; + //if (temp == 0) + // azt2316a->cur_cd_dma16 = -1; + //else if (temp == 1) + // azt2316a->cur_cd_dma16 = 5; + //else if (temp == 2) + // azt2316a->cur_cd_dma16 = 6; + //else if (temp == 3) + // azt2316a->cur_cd_dma16 = 7; + break; + case 3: + azt2316a->config_word = (azt2316a->config_word & 0x00FFFFFF) + (val << 24); + + if (val & 0x1) + azt2316a->cur_mpu401_irq = 2; + else if (val & 0x2) + azt2316a->cur_mpu401_irq = 5; + else if (val & 0x4) + azt2316a->cur_mpu401_irq = 7; + else if (val & 0x8) + azt2316a->cur_mpu401_irq = 10; + // else undefined? + + // cd_irq is hardcoded + //if (val & 0x10) + // azt2316a->cur_cd_irq = 5; + //else if (val & 0x20) + // azt2316a->cur_cd_irq = 11; + //else if (val & 0x40) + // azt2316a->cur_cd_irq = 12; + //else if (val & 0x80) + // azt2316a->cur_cd_irq = 15; + // else undefined? + break; + } + // update sbprov2 configs + sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); + sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); + sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); + + mpu401_uart_update_addr(&azt2316a->sb->mpu, azt2316a->cur_mpu401_addr); + mpu401_uart_update_irq(&azt2316a->sb->mpu, azt2316a->cur_mpu401_irq); + } +} + +// How it behaves when one or another is activated may affect games auto-detecting (and will also use more of the limited system resources!) +void azt2316a_enable_wss(uint8_t enable, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + if (enable) + { + azt2316a->cur_mode = 1; + if (!azt2316a->cur_wss_enabled) + { +// apparently it doesn't work like this! +// azt2316a->cur_wss_enabled = 1; +// azt2316a->config_word |= 1 << 10; + } + } + else + { + azt2316a->cur_mode = 0; + if (azt2316a->cur_wss_enabled) + { +// apparently it doesn't work like this! +// azt2316a->cur_wss_enabled = 0; +// azt2316a->config_word &= 0xFFFFFFFF - (1 << 10); + } + } +} + +static void azt2316a_get_buffer(int32_t *buffer, int len, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + int c; + + // wss part + ad1848_update(&azt2316a->ad1848); + for (c = 0; c < len * 2; c++) + { + buffer[c] += (azt2316a->ad1848.buffer[c] / 2); + } + + azt2316a->ad1848.pos = 0; + + // sbprov2 part + sb_get_buffer_sbpro(buffer, len, azt2316a->sb); +} + +void *azt_common_init(const int type, char *nvr_filename) +{ + int i; + int loaded_from_eeprom = 0; + uint16_t addr_setting; + uint8_t read_eeprom[AZTECH_EEPROM_SIZE]; + azt2316a_t *azt2316a = malloc(sizeof(azt2316a_t)); + memset(azt2316a, 0, sizeof(azt2316a_t)); + + // load configs from eeprom + FILE *f; + f = nvrfopen(nvr_filename, "rb"); + if (f) + { + uint8_t checksum = 0x7F; + uint8_t saved_checksum; + size_t res; // avoid warning + + res = fread(read_eeprom, AZTECH_EEPROM_SIZE, 1, f); + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + checksum += read_eeprom[i]; + + res = fread(&saved_checksum, sizeof(saved_checksum), 1, f); + (void)res; + + fclose(f); + + if (checksum == saved_checksum) + loaded_from_eeprom = 1; + } + + // no eeprom saved or invalid checksum, load defaults + if (!loaded_from_eeprom) + { + if (type == SB_SUBTYPE_CLONE_AZT2316A_0X11) + { + read_eeprom[0] = 0x00; + read_eeprom[1] = 0x00; + read_eeprom[2] = 0x00; + read_eeprom[3] = 0x00; + read_eeprom[4] = 0x00; + read_eeprom[5] = 0x00; + read_eeprom[6] = 0x00; + read_eeprom[7] = 0x00; + read_eeprom[8] = 0x00; + read_eeprom[9] = 0x00; + read_eeprom[10] = 0x00; + read_eeprom[11] = 0x88; + read_eeprom[12] = 0xbc; + read_eeprom[13] = 0x00; + read_eeprom[14] = 0x01; + read_eeprom[15] = 0x00; + } + else if (type == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + read_eeprom[0] = 0x80; + read_eeprom[1] = 0x80; + read_eeprom[2] = 0x9F; + read_eeprom[3] = 0x13; + read_eeprom[4] = 0x16; + read_eeprom[5] = 0x13; + read_eeprom[6] = 0x00; + read_eeprom[7] = 0x00; + read_eeprom[8] = 0x16; + read_eeprom[9] = 0x0B; + read_eeprom[10] = 0x06; + read_eeprom[11] = 0x01; + read_eeprom[12] = 0x1C; + read_eeprom[13] = 0x14; + read_eeprom[14] = 0x04; + read_eeprom[15] = 0x1C; + } + else + fatal("Aztech: unknown type %d\n", type); + } + + // restore settings from EEPROM bytes + if (type == SB_SUBTYPE_CLONE_AZT2316A_0X11) + { + azt2316a->config_word = read_eeprom[11] + (read_eeprom[12] << 8) + (read_eeprom[13] << 16) + (read_eeprom[14] << 24); + switch (azt2316a->config_word & (3 << 0)) + { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + default: + fatal("AZT2316A: invalid sb addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_irq = 2; + else if (azt2316a->config_word & (1 << 3)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 4)) + azt2316a->cur_irq = 7; + else if (azt2316a->config_word & (1 << 5)) + azt2316a->cur_irq = 10; + else + fatal("AZT2316A: invalid sb irq in config word %08X\n", azt2316a->config_word); + + switch (azt2316a->config_word & (3 << 6)) + { + case 1 << 6: + azt2316a->cur_dma = 0; + break; + case 2 << 6: + azt2316a->cur_dma = 1; + break; + case 3 << 6: + azt2316a->cur_dma = 3; + break; + default: + fatal("AZT2316A: invalid sb dma in config word %08X\n", azt2316a->config_word); + } + + switch (azt2316a->config_word & (3 << 8)) + { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 8: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 8: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 8: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZT2316A: invalid wss addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + // game_enabled is hardcoded + //if (azt2316a->config_word & (1 << 11)) + // azt2316a->cur_game_enabled = 1; + //else + // azt2316a->cur_game_enabled = 0; + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + // mpu401_enabled is hardcoded + //if (azt2316a->config_word & (1 << 13)) + // azt2316a->cur_mpu401_enabled = 1; + //else + // azt2316a->cur_mpu401_enabled = 0; + + // cd_addr is hardcoded + //switch (azt2316a->config_word & (3 << 14)) + //{ + // case 0: + // azt2316a->cur_cd_addr = 0x310; + // break; + // case 1 << 14: + // azt2316a->cur_cd_addr = 0x320; + // break; + // case 2 << 14: + // azt2316a->cur_cd_addr = 0x340; + // break; + // case 3 << 14: + // azt2316a->cur_cd_addr = 0x350; + // break; + // default: + // fatal("AZT2316A: invalid cd addr in config word %08X\n", azt2316a->config_word); + //} + + // cd_type is hardcoded + //azt2316a->cur_cd_type = (azt2316a->config_word >> 16) & 0x7; + + // cd_dma8 is hardcoded + //switch (azt2316a->config_word & (3 << 20)) + //{ + // case 0: + // azt2316a->cur_cd_dma8 = -1; + // break; + // case 1 << 20: + // azt2316a->cur_cd_dma8 = 0; + // break; + // case 2 << 20: + // azt2316a->cur_cd_dma8 = 1; + // break; + // case 3 << 20: + // azt2316a->cur_cd_dma8 = 3; + // break; + // default: + // fatal("AZT2316A: invalid cd dma8 in config word %08X\n", azt2316a->config_word); + //} + + // cd_dma16 is hardcoded + //switch (azt2316a->config_word & (3 << 22)) + //{ + // case 0: + // azt2316a->cur_cd_dma16 = -1; + // break; + // case 1 << 22: + // azt2316a->cur_cd_dma16 = 5; + // break; + // case 2 << 22: + // azt2316a->cur_cd_dma16 = 6; + // break; + // case 3 << 22: + // azt2316a->cur_cd_dma16 = 7; + // break; + // default: + // fatal("AZT2316A: invalid cd dma16 in config word %08X\n", azt2316a->config_word); + //} + + if (azt2316a->config_word & (1 << 24)) + azt2316a->cur_mpu401_irq = 2; + else if (azt2316a->config_word & (1 << 25)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 26)) + azt2316a->cur_mpu401_irq = 7; + else if (azt2316a->config_word & (1 << 27)) + azt2316a->cur_mpu401_irq = 10; + else + fatal("AZT2316A: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + + // cd_irq is hardcoded + //if (azt2316a->config_word & (1 << 28)) + // azt2316a->cur_cd_irq = 5; + //else if (azt2316a->config_word & (1 << 29)) + // azt2316a->cur_cd_irq = 11; + //else if (azt2316a->config_word & (1 << 30)) + // azt2316a->cur_cd_irq = 12; + //else if (azt2316a->config_word & (1 << 31)) + // azt2316a->cur_cd_irq = 15; + //else + // fatal("AZT2316A: invalid cd irq in config word %08X\n", azt2316a->config_word); + + // these are not present on the EEPROM + azt2316a->cur_wss_irq = 10; + azt2316a->cur_wss_dma = 0; + azt2316a->cur_mode = 0; + } + else if (type == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + azt2316a->config_word = read_eeprom[12] + (read_eeprom[13] << 8) + (read_eeprom[14] << 16); + switch (azt2316a->config_word & (3 << 0)) + { + case 0: + azt2316a->cur_addr = 0x220; + break; + case 1: + azt2316a->cur_addr = 0x240; + break; + default: + fatal("AZT1605: invalid sb addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 2)) + azt2316a->cur_mpu401_addr = 0x330; + else + azt2316a->cur_mpu401_addr = 0x300; + + // mpu401_enabled is hardcoded + //if (azt2316a->config_word & (1 << 3)) + // azt2316a->cur_mpu401_enabled = 1; + //else + // azt2316a->cur_mpu401_enabled = 0; + + // game_enabled is hardcoded + //if (azt2316a->config_word & (1 << 4)) + // azt2316a->cur_game_enabled = 1; + //else + // azt2316a->cur_game_enabled = 0; + + // cd_type is hardcoded + //azt2316a->cur_cd_type = (azt2316a->config_word >> 5) & 0x7; + + if (azt2316a->config_word & (1 << 8)) + azt2316a->cur_irq = 2; + else if (azt2316a->config_word & (1 << 9)) + azt2316a->cur_irq = 3; + else if (azt2316a->config_word & (1 << 10)) + azt2316a->cur_irq = 5; + else if (azt2316a->config_word & (1 << 11)) + azt2316a->cur_irq = 7; + else + fatal("AZT1605: invalid sb irq in config word %08X\n", azt2316a->config_word); + + if (azt2316a->config_word & (1 << 12)) + azt2316a->cur_mpu401_irq = 2; + else if (azt2316a->config_word & (1 << 13)) + azt2316a->cur_mpu401_irq = 3; + else if (azt2316a->config_word & (1 << 14)) + azt2316a->cur_mpu401_irq = 5; + else if (azt2316a->config_word & (1 << 15)) + azt2316a->cur_mpu401_irq = 7; + else + fatal("AZT1605: invalid mpu401 irq in config word %08X\n", azt2316a->config_word); + + switch (azt2316a->config_word & (3 << 16)) + { + case 0: + azt2316a->cur_wss_addr = 0x530; + break; + case 1 << 16: + azt2316a->cur_wss_addr = 0x604; + break; + case 2 << 16: + azt2316a->cur_wss_addr = 0xE80; + break; + case 3 << 16: + azt2316a->cur_wss_addr = 0xF40; + break; + default: + fatal("AZT1605: invalid wss addr in config word %08X\n", azt2316a->config_word); + } + + if (azt2316a->config_word & (1 << 18)) + azt2316a->cur_wss_enabled = 1; + else + azt2316a->cur_wss_enabled = 0; + + // cd_irq is hardcoded + //if (azt2316a->config_word & (1 << 19)) + // azt2316a->cur_cd_irq = 11; + //else if (azt2316a->config_word & (1 << 20)) + // azt2316a->cur_cd_irq = 12; + //else if (azt2316a->config_word & (1 << 21)) + // azt2316a->cur_cd_irq = 15; + //else + // fatal("AZT1605: invalid cd irq in config word %08X\n", azt2316a->config_word); + + // cd_dma8 is hardcoded + //switch (azt2316a->config_word & (3 << 22)) + //{ + // case 0: + // azt2316a->cur_cd_dma8 = -1; + // break; + // case 1 << 22: + // azt2316a->cur_cd_dma8 = 0; + // break; + // case 2 << 22: + // azt2316a->cur_cd_dma8 = 1; + // break; + // case 3 << 22: + // azt2316a->cur_cd_dma8 = 3; + // break; + // default: + // fatal("AZT1605: invalid cd dma8 in config word %08X\n", azt2316a->config_word); + //} + + // these are not present on the EEPROM + azt2316a->cur_dma = 1; // TODO: investigate TSR to make this work with it - there is no software configurable DMA8? + azt2316a->cur_wss_irq = 10; + azt2316a->cur_wss_dma = 0; + azt2316a->cur_mode = 0; + } + else + fatal("Aztech: unknown type %d\n", type); + + // check for sb addr override jumper + addr_setting = device_get_config_int("addr"); + if (addr_setting) + azt2316a->cur_addr = addr_setting; + + // now we can continue initializing + azt2316a->opl_emu = device_get_config_int("opl_emu"); + azt2316a->wss_interrupt_after_config = device_get_config_int("wss_interrupt_after_config"); + + azt2316a->type = type; + + // wss part + ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); + + ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq); + ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); + + io_sethandler(azt2316a->cur_addr + 0x0400, 0x0040, azt2316a_config_read, NULL, NULL, azt2316a_config_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr, 0x0004, azt2316a_wss_read, NULL, NULL, azt2316a_wss_write, NULL, NULL, azt2316a); + io_sethandler(azt2316a->cur_wss_addr + 0x0004, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &azt2316a->ad1848); + + // sbprov2 part + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + + 2x8, 2x9, 388 and 389 FM chip (9 voices).*/ + azt2316a->sb = malloc(sizeof(sb_t)); + memset(azt2316a->sb, 0, sizeof(sb_t)); + + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + azt2316a->sb->dsp.azt_eeprom[i] = read_eeprom[i]; + + azt2316a->sb->opl_emu = azt2316a->opl_emu; + opl3_init(&azt2316a->sb->opl, azt2316a->sb->opl_emu); + sb_dsp_init(&azt2316a->sb->dsp, SBPRO2, azt2316a->type, azt2316a); + sb_dsp_setaddr(&azt2316a->sb->dsp, azt2316a->cur_addr); + sb_dsp_setirq(&azt2316a->sb->dsp, azt2316a->cur_irq); + sb_dsp_setdma8(&azt2316a->sb->dsp, azt2316a->cur_dma); + sb_ct1345_mixer_reset(azt2316a->sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + io_sethandler(azt2316a->cur_addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(azt2316a->cur_addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &azt2316a->sb->opl); + io_sethandler(azt2316a->cur_addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, azt2316a->sb); + mpu401_uart_init(&azt2316a->sb->mpu, azt2316a->cur_mpu401_addr, azt2316a->cur_mpu401_irq, 1); + + azt2316a_create_config_word(azt2316a); // recreate even if we have read it from EEPROM, because we have some overrides (CD interfaces always off, etc) + sound_add_handler(azt2316a_get_buffer, azt2316a); + + return azt2316a; +} + +void *azt2316a_init() +{ + return azt_common_init(SB_SUBTYPE_CLONE_AZT2316A_0X11, "azt2316a.nvr"); +} + +void *azt1605_init() +{ + return azt_common_init(SB_SUBTYPE_CLONE_AZT1605_0X0C, "azt1605.nvr"); +} + +void azt_common_close(void *p, char *nvr_filename) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + int i; + uint8_t checksum = 0x7F; + + // always save to eeprom (recover from bad values) + FILE *f = nvrfopen(nvr_filename, "wb"); + if (f) + { + for (i = 0; i < AZTECH_EEPROM_SIZE; i++) + checksum += azt2316a->sb->dsp.azt_eeprom[i]; + fwrite(azt2316a->sb->dsp.azt_eeprom, AZTECH_EEPROM_SIZE, 1, f); + + // TODO: confirm any models saving mixer settings to EEPROM and implement reading back + // TODO: should remember to save wss duplex setting if PCem has voice recording implemented in the future? Also, default azt2316a->wss_config + // TODO: azt2316a->cur_mode is not saved to EEPROM? + fwrite(&checksum, sizeof(checksum), 1, f); + + fclose(f); + } + + sb_close(azt2316a->sb); + + free(azt2316a); +} + +void azt2316a_close(void *p) +{ + azt_common_close(p, "azt2316a.nvr"); +} + +void azt1605_close(void *p) +{ + azt_common_close(p, "azt1605.nvr"); +} + +void azt2316a_speed_changed(void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + ad1848_speed_changed(&azt2316a->ad1848); + sb_speed_changed(azt2316a->sb); +} + +void azt2316a_add_status_info(char *s, int max_len, void *p) +{ + azt2316a_t *azt2316a = (azt2316a_t *)p; + + sb_dsp_add_status_info(s, max_len, &azt2316a->sb->dsp); +} + +static device_config_t azt2316a_config[] = +{ + { + .name = "codec", + .description = "CODEC", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "CS4248", + .value = AD1848_TYPE_CS4248 + }, + { + .description = "CS4231", + .value = AD1848_TYPE_CS4231 + }, + }, + .default_int = AD1848_TYPE_CS4248 + }, + { + .name = "wss_interrupt_after_config", + .description = "Raise CODEC interrupt on CODEC setup (needed by some drivers)", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "addr", + .description = "SB Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "Use EEPROM setting", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI, + .default_int = 0 + }, + { + .name = "opl_emu", + .description = "OPL emulator", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DBOPL", + .value = OPL_DBOPL + }, + { + .description = "NukedOPL", + .value = OPL_NUKED + }, + }, + .default_int = OPL_DBOPL + }, + { + .type = -1 + } +}; + +device_t azt2316a_device = +{ + "Aztech Sound Galaxy Pro 16 AB (Washington)", + 0, + azt2316a_init, + azt2316a_close, + NULL, + azt2316a_speed_changed, + NULL, + azt2316a_add_status_info, + azt2316a_config +}; + +device_t azt1605_device = +{ + "Aztech Sound Galaxy Nova 16 Extra (Clinton)", + DEVICE_NOT_WORKING, + azt1605_init, + azt1605_close, + NULL, + azt2316a_speed_changed, + NULL, + azt2316a_add_status_info, + azt2316a_config +}; diff --git a/src/sound_azt2316a.h b/src/sound_azt2316a.h new file mode 100644 index 0000000..2b7d7fa --- /dev/null +++ b/src/sound_azt2316a.h @@ -0,0 +1,4 @@ +extern device_t azt2316a_device; +extern device_t azt1605_device; + +void azt2316a_enable_wss(uint8_t enable, void *p); diff --git a/src/sound_cms.c b/src/sound_cms.c index 7c4a33f..dd2fa27 100644 --- a/src/sound_cms.c +++ b/src/sound_cms.c @@ -22,8 +22,10 @@ typedef struct cms_t uint16_t noisefreq[2][2]; int noisecount[2][2]; int noisetype[2][2]; + + uint8_t latched_data; - int16_t buffer[SOUNDBUFLEN * 2]; + int16_t buffer[MAXSOUNDBUFLEN * 2]; int pos; } cms_t; @@ -106,12 +108,18 @@ void cms_write(uint16_t addr, uint8_t val, void *p) int voice; int chip = (addr & 2) >> 1; - pclog("cms_write : addr %04X val %02X\n", addr, val); +// pclog("cms_write : addr %04X val %02X\n", addr, val); - if (addr & 1) - cms->addrs[chip] = val & 31; - else + switch (addr & 0xf) { + case 1: + cms->addrs[0] = val & 31; + break; + case 3: + cms->addrs[1] = val & 31; + break; + + case 0: case 2: cms_update(cms); cms->regs[chip][cms->addrs[chip] & 31] = val; switch (cms->addrs[chip] & 31) @@ -140,18 +148,30 @@ void cms_write(uint16_t addr, uint8_t val, void *p) cms->noisetype[chip][1] = (val >> 4) & 3; break; } + break; + case 0x6: case 0x7: + cms->latched_data = val; + 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]; +// pclog("cms_read : addr %04X\n", addr); + switch (addr & 0xf) + { + case 0x1: + return cms->addrs[0]; + case 0x3: + return cms->addrs[1]; + case 0x4: + return 0x7f; + case 0xa: case 0xb: + return cms->latched_data; + } + return 0xff; } void *cms_init() @@ -160,7 +180,7 @@ void *cms_init() memset(cms, 0, sizeof(cms_t)); pclog("cms_init\n"); - io_sethandler(0x0220, 0x0004, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); + io_sethandler(0x0220, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); sound_add_handler(cms_get_buffer, cms); return cms; } diff --git a/src/sound_dbopl.cc b/src/sound_dbopl.cc index 7040747..7342ea4 100644 --- a/src/sound_dbopl.cc +++ b/src/sound_dbopl.cc @@ -1,15 +1,18 @@ #include "dosbox/dbopl.h" +#include "dosbox/nukedopl.h" #include "sound_dbopl.h" static struct { DBOPL::Chip chip; + struct opl3_chip opl3chip; int addr; int timer[2]; uint8_t timer_ctrl; uint8_t status_mask; uint8_t status; int is_opl3; + int opl_emu; void (*timer_callback)(void *param, int timer, int64_t period); void *timer_param; @@ -31,13 +34,25 @@ enum 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) +void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3, int opl_emu) { - 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; + if (!is_opl3 || !opl_emu) + { + 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; + opl[nr].opl_emu = opl_emu; + } + else + { + OPL3_Reset(&opl[nr].opl3chip, 48000); + opl[nr].timer_callback = timer_callback; + opl[nr].timer_param = timer_param; + opl[nr].is_opl3 = is_opl3; + opl[nr].opl_emu = opl_emu; + } } void opl_status_update(int nr) @@ -67,10 +82,18 @@ void opl_timer_over(int nr, int timer) 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); + { + if (!opl[nr].is_opl3 || !opl[nr].opl_emu) + opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & (opl[nr].is_opl3 ? 0x1ff : 0xff); + else + opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; + } else { - opl[nr].chip.WriteReg(opl[nr].addr, val); + if (!opl[nr].is_opl3 || !opl[nr].opl_emu) + opl[nr].chip.WriteReg(opl[nr].addr, val); + else + OPL3_WriteReg(&opl[nr].opl3chip, opl[nr].addr, val); switch (opl[nr].addr) { @@ -133,9 +156,16 @@ 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]; + + if (opl[nr].opl_emu) + { + OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); + } + else + { + 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 index 0890552..4aa03bf 100644 --- a/src/sound_dbopl.h +++ b/src/sound_dbopl.h @@ -1,7 +1,7 @@ #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_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3, int opl_emu); 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); diff --git a/src/sound_emu8k.c b/src/sound_emu8k.c index 49d8216..bee7e1b 100644 --- a/src/sound_emu8k.c +++ b/src/sound_emu8k.c @@ -1,8 +1,3 @@ -/*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" @@ -11,74 +6,479 @@ #include "sound.h" #include "sound_emu8k.h" #include "timer.h" +#include + +#if !defined FILTER_INITIAL && !defined FILTER_MOOG && !defined FILTER_CONSTANT +//#define FILTER_INITIAL +#define FILTER_MOOG +//#define FILTER_CONSTANT +#endif + +#if !defined RESAMPLER_LINEAR && !defined RESAMPLER_CUBIC +//#define RESAMPLER_LINEAR +#define RESAMPLER_CUBIC +#endif + +//#define EMU8K_DEBUG_REGISTERS + +char *PORT_NAMES[][8] = +{ + /* Data 0 ( 0x620/0x622) */ + { "AWE_CPF", + "AWE_PTRX", + "AWE_CVCF", + "AWE_VTFT", + "Unk-620-4", + "Unk-620-5", + "AWE_PSST", + "AWE_CSL", + }, + /* Data 1 0xA20 */ + { "AWE_CCCA", + 0, + /* + "AWE_HWCF4" + "AWE_HWCF5" + "AWE_HWCF6" + "AWE_HWCF7" + "AWE_SMALR" + "AWE_SMARR" + "AWE_SMALW" + "AWE_SMARW" + "AWE_SMLD" + "AWE_SMRD" + "AWE_WC" + "AWE_HWCF1" + "AWE_HWCF2" + "AWE_HWCF3" + */ + 0,//"AWE_INIT1", + 0,//"AWE_INIT3", + "AWE_ENVVOL", + "AWE_DCYSUSV", + "AWE_ENVVAL", + "AWE_DCYSUS", + }, + /* Data 2 0xA22 */ + { "AWE_CCCA", + 0, + 0,//"AWE_INIT2", + 0,//"AWE_INIT4", + "AWE_ATKHLDV", + "AWE_LFO1VAL", + "AWE_ATKHLD", + "AWE_LFO2VAL", + }, + /* Data 3 0xE20 */ + { "AWE_IP", + "AWE_IFATN", + "AWE_PEFE", + "AWE_FMMOD", + "AWE_TREMFRQ", + "AWE_FM2FRQ2", + 0, + 0, + }, +}; enum { ENV_STOPPED = 0, - ENV_ATTACK = 1, - ENV_DECAY = 2, - ENV_SUSTAIN = 3, - ENV_RELEASE = 4 + ENV_DELAY = 1, + ENV_ATTACK = 2, + ENV_HOLD = 3, + //ENV_DECAY = 4, + ENV_SUSTAIN = 5, + //ENV_RELEASE = 6, + ENV_RAMP_DOWN = 7, + ENV_RAMP_UP = 8 }; + +static int random_helper = 0; +int dmareadbit = 0; +int dmawritebit = 0; + + +/* cubic and linear tables resolution. Note: higher than 10 does not improve the result. */ +#define CUBIC_RESOLUTION_LOG 10 +#define CUBIC_RESOLUTION (1<> 15 to move back to +/-1 range). */ +static int32_t lfotable[65536]; +/* Table to transform the speed parameter to emu8k_mem_internal_t range. */ +static int64_t lfofreqtospeed[256]; -#define READ16(addr, var) switch ((addr) & 2) \ +/* LFO used for the chorus. a sine wave.(signed 16bits with 32768 max int. >> 15 to move back to +/-1 range). */ +static double chortable[65536]; + +static const int REV_BUFSIZE_STEP=242; + + +/* These lines come from the awe32faq, describing the NRPN control for the initial filter + * where it describes a linear increment filter instead of an octave-incremented one. + * NRPN LSB 21 (Initial Filter Cutoff) + * Range : [0, 127] + * Unit : 62Hz + * Filter cutoff from 100Hz to 8000Hz + + * This table comes from the awe32faq, describing the NRPN control for the filter Q. + * I don't know if is meant to be interpreted as the actual measured output of the + * filter or what. Especially, I don't understand the "low" and "high" ranges. + * What is otherwise documented is that the Q ranges from 0dB to 24dB and the attenuation + * is half of the Q ( i.e. for 12dB Q, attenuate the input signal with -6dB) +Coeff Low Fc(Hz)Low Q(dB)High Fc(kHz)High Q(dB)DC Attenuation(dB) +* 0 92 5 Flat Flat -0.0 +* 1 93 6 8.5 0.5 -0.5 +* 2 94 8 8.3 1 -1.2 +* 3 95 10 8.2 2 -1.8 +* 4 96 11 8.1 3 -2.5 +* 5 97 13 8.0 4 -3.3 +* 6 98 14 7.9 5 -4.1 +* 7 99 16 7.8 6 -5.5 +* 8 100 17 7.7 7 -6.0 +* 9 100 19 7.5 9 -6.6 +* 10 100 20 7.4 10 -7.2 +* 11 100 22 7.3 11 -7.9 +* 12 100 23 7.2 13 -8.5 +* 13 100 25 7.1 15 -9.3 +* 14 100 26 7.1 16 -10.1 +* 15 100 28 7.0 18 -11.0 +* +* Attenuation as above, codified in amplitude.*/ +static int32_t filter_atten[16] = +{ + 65536, 61869, 57079, 53269, 49145, 44820, 40877, 34792, 32845, 30653, 28607, + 26392, 24630, 22463, 20487, 18470 +}; + +/*Coefficients for the filters for a defined Q and cutoff.*/ +static int32_t filt_coeffs[16][256][3]; + +#define READ16_SWITCH(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) \ +#define WRITE16_SWITCH(addr, var, val) switch ((addr) & 2) \ { \ case 0: var = (var & 0xffff0000) | (val); break; \ case 2: var = (var & 0x0000ffff) | ((val) << 16); break; \ } +#ifdef EMU8K_DEBUG_REGISTERS +uint32_t dw_value = 0; +uint32_t last_read = 0; +uint32_t last_write = 0; +uint32_t rep_count_r = 0; +uint32_t rep_count_w = 0; + +# define READ16(addr, var) READ16_SWITCH(addr, var) \ + { \ + const char *name=0; \ + switch(addr&0xF02) \ + { \ + case 0x600: case 0x602: \ + name = PORT_NAMES[0][emu8k->cur_reg]; \ + break; \ + case 0xA00: \ + name = PORT_NAMES[1][emu8k->cur_reg]; \ + break; \ + case 0xA02: \ + name = PORT_NAMES[2][emu8k->cur_reg]; \ + break; \ + } \ + if (name == 0) \ + { \ + /*pclog("EMU8K READ %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_voice,ret);*/ \ + } \ + else \ + { \ + pclog("EMU8K READ %s(%d) (%d): %04X\n",name, (addr&0x2), emu8k->cur_voice, ret); \ + }\ + } +# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) \ + { \ + const char *name=0; \ + switch(addr&0xF02) \ + { \ + case 0x600: case 0x602: \ + name = PORT_NAMES[0][emu8k->cur_reg]; \ + break; \ + case 0xA00: \ + name = PORT_NAMES[1][emu8k->cur_reg]; \ + break; \ + case 0xA02: \ + name = PORT_NAMES[2][emu8k->cur_reg]; \ + break; \ + } \ + if (name == 0) \ + { \ + /*pclog("EMU8K WRITE %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_voice, val);*/ \ + } \ + else \ + { \ + pclog("EMU8K WRITE %s(%d) (%d): %04X\n",name, (addr&0x2), emu8k->cur_voice,val); \ + }\ + } + +#else +# define READ16(addr, var) READ16_SWITCH(addr, var) +# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) +#endif //EMU8K_DEBUG_REGISTERS + + 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]; + const register emu8k_mem_pointers_t addrmem = {{addr}}; + return emu8k->ram_pointers[addrmem.hb_address][addrmem.lw_address]; } -static inline int16_t EMU8K_READ_INTERP(emu8k_t *emu8k, uint32_t addr) +static inline int16_t EMU8K_READ_INTERP_LINEAR(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract) { - 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; + /* The interpolation in AWE32 used a so-called patented 3-point interpolation + * ( I guess some sort of spline having one point before and one point after). + * Also, it has the consequence that the playback is delayed by one sample. + * I simulate the "one sample later" than the address with addr+1 and addr+2 + * instead of +0 and +1 */ + int16_t dat1 = EMU8K_READ(emu8k, int_addr+1); + int32_t dat2 = EMU8K_READ(emu8k, int_addr+2); + dat1 += ((dat2-(int32_t)dat1)* fract) >> 16; + return dat1; +} + +static inline int32_t EMU8K_READ_INTERP_CUBIC(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract) +{ + /*Since there are four floats in the table for each fraction, the position is 16byte aligned. */ + fract >>= 16-CUBIC_RESOLUTION_LOG; + fract <<=2; + + /* TODO: I still have to verify how this works, but I think that + * the card could use two oscillators (usually 31 and 32) where it would + * be writing the OPL3 output, and to which, chorus and reverb could be applied to get + * those effects for OPL3 sounds.*/ +// if ((addr & EMU8K_FM_MEM_ADDRESS) == EMU8K_FM_MEM_ADDRESS) {} + + /* This is cubic interpolation. + * Not the same than 3-point interpolation, but a better approximation than linear + * interpolation. + * Also, it takes into account the "Note that the actual audio location is the point + * 1 word higher than this value due to interpolation offset". + * That's why the pointers are 0, 1, 2, 3 and not -1, 0, 1, 2 */ + int32_t dat2 = EMU8K_READ(emu8k, int_addr+1); + const float *table = &cubic_table[fract]; + const int32_t dat1 = EMU8K_READ(emu8k, int_addr); + const int32_t dat3 = EMU8K_READ(emu8k, int_addr+2); + const int32_t dat4 = EMU8K_READ(emu8k, int_addr+3); + /* Note: I've ended using float for the table values to avoid some cases of integer overflow. */ + dat2 = dat1*table[0] + dat2*table[1] + dat3*table[2] + dat4*table[3]; + return dat2; } 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; + addr &= EMU8K_MEM_ADDRESS_MASK; + if ( !emu8k->ram || addr < EMU8K_RAM_MEM_START || addr >= EMU8K_FM_MEM_ADDRESS ) + return; + + /* It looks like if an application writes to a memory part outside of the available + * amount on the card, it wraps, and opencubicplayer uses that to detect the amount + * of memory, as opposed to simply check at the address that it has just tried to write. */ + while (addr >= emu8k->ram_end_addr) + addr -= emu8k->ram_end_addr - EMU8K_RAM_MEM_START; + + emu8k->ram[addr - EMU8K_RAM_MEM_START] = val; } -static int ff = 0; -static int voice_count = 0; uint16_t emu8k_inw(uint16_t addr, void *p) { emu8k_t *emu8k = (emu8k_t *)p; uint16_t ret = 0xffff; -/* pclog("emu8k_inw %04X reg=%i voice=%i\n", addr, emu8k->cur_reg, emu8k->cur_voice);*/ - - addr -= 0x220; - switch (addr & 0xc02) + +#ifdef EMU8K_DEBUG_REGISTERS + if (addr == 0xE22) { - case 0x400: case 0x402: /*Data0*/ + pclog("EMU8K READ POINTER: %d\n", + ((0x80 | ((random_helper + 1) & 0x1F)) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice); + } + else if ((addr&0xF00) == 0x600) + { + /* These are automatically reported by READ16 */ + if (rep_count_r>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r=0; + } + last_read=0; + } + else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 0) + { + /* These are automatically reported by READ16 */ + if (rep_count_r>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r=0; + } + last_read=0; + } + else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 1) + { + uint32_t tmpz = ((addr&0xF00) << 16)|(emu8k->cur_reg<<5); + if (tmpz != last_read) + { + if (rep_count_r>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r=0; + } + last_read=tmpz; + pclog("EMU8K READ RAM I/O or configuration or clock \n"); + } + //pclog("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); + } + else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) + { + uint32_t tmpz = ((addr&0xF00) << 16); + if (tmpz != last_read) + { + if (rep_count_r>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r=0; + } + last_read=tmpz; + pclog("EMU8K READ INIT \n"); + } + //pclog("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); + } + else + { + uint32_t tmpz = (addr << 16)|(emu8k->cur_reg<<5)| emu8k->cur_voice; + if (tmpz != last_read) + { + char* name = 0; + uint16_t val = 0xBAAD; + if (addr == 0xA20) + { + name = PORT_NAMES[1][emu8k->cur_reg]; + switch (emu8k->cur_reg) + { + case 2: val = emu8k->init1[emu8k->cur_voice]; break; + case 3: val = emu8k->init3[emu8k->cur_voice]; break; + case 4: val = emu8k->voice[emu8k->cur_voice].envvol; break; + case 5: val = emu8k->voice[emu8k->cur_voice].dcysusv; break; + case 6: val = emu8k->voice[emu8k->cur_voice].envval; break; + case 7: val = emu8k->voice[emu8k->cur_voice].dcysus; break; + } + } + else if (addr == 0xA22) + { + name = PORT_NAMES[2][emu8k->cur_reg]; + switch (emu8k->cur_reg) + { + case 2: val = emu8k->init2[emu8k->cur_voice]; break; + case 3: val = emu8k->init4[emu8k->cur_voice]; break; + case 4: val = emu8k->voice[emu8k->cur_voice].atkhldv; break; + case 5: val = emu8k->voice[emu8k->cur_voice].lfo1val; break; + case 6: val = emu8k->voice[emu8k->cur_voice].atkhld; break; + case 7: val = emu8k->voice[emu8k->cur_voice].lfo2val; break; + } + } + else if (addr == 0xE20) + { + name = PORT_NAMES[3][emu8k->cur_reg]; + switch (emu8k->cur_reg) + { + case 0: val = emu8k->voice[emu8k->cur_voice].ip; break; + case 1: val = emu8k->voice[emu8k->cur_voice].ifatn; break; + case 2: val = emu8k->voice[emu8k->cur_voice].pefe; break; + case 3: val = emu8k->voice[emu8k->cur_voice].fmmod; break; + case 4: val = emu8k->voice[emu8k->cur_voice].tremfrq; break; + case 5: val = emu8k->voice[emu8k->cur_voice].fm2frq2;break; + case 6: val = 0xffff; break; + case 7: val = 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); break; + } + } + if (rep_count_r>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_r); + } + if (name == 0) + { + pclog("EMU8K READ %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice,val); + } + else + { + pclog("EMU8K READ %s (%d): %04X\n",name,emu8k->cur_voice, val); + } + + rep_count_r=0; + last_read=tmpz; + } + rep_count_r++; + } +#endif // EMU8K_DEBUG_REGISTERS + + + switch (addr & 0xF02) + { + case 0x600: case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */ switch (emu8k->cur_reg) { case 0: @@ -97,32 +497,48 @@ uint16_t emu8k_inw(uint16_t addr, void *p) READ16(addr, emu8k->voice[emu8k->cur_voice].vtft); return ret; - case 4: case 5: /*???*/ - return 0xffff; + case 4: + READ16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_4); + return ret; + + case 5: + READ16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_5); + return ret; case 6: READ16(addr, emu8k->voice[emu8k->cur_voice].psst); return ret; case 7: - READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); + READ16(addr, emu8k->voice[emu8k->cur_voice].csl); return ret; } break; - case 0x800: /*Data1*/ + case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */ 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; - } + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; case 1: switch (emu8k->cur_voice) { + case 9: + READ16(addr, emu8k->hwcf4); + return ret; + case 10: + READ16(addr, emu8k->hwcf5); + return ret; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/ + case 13: + READ16(addr, emu8k->hwcf6); + return ret; + case 14: + READ16(addr, emu8k->hwcf7); + return ret; + case 20: READ16(addr, emu8k->smalr); return ret; @@ -140,84 +556,123 @@ uint16_t emu8k_inw(uint16_t addr, void *p) { 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++; + emu8k->smalr = (emu8k->smalr+1) & EMU8K_MEM_ADDRESS_MASK; 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); + 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 2: + return emu8k->init1[emu8k->cur_voice]; + case 3: + return emu8k->init3[emu8k->cur_voice]; + + case 4: + return emu8k->voice[emu8k->cur_voice].envvol; + case 5: return emu8k->voice[emu8k->cur_voice].dcysusv; + + case 6: + return emu8k->voice[emu8k->cur_voice].envval; case 7: return emu8k->voice[emu8k->cur_voice].dcysus; } break; - case 0x802: /*Data2*/ + case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */ 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; - } + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; case 1: switch (emu8k->cur_voice) { + case 9: + READ16(addr, emu8k->hwcf4); + return ret; + case 10: + READ16(addr, emu8k->hwcf5); + return ret; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */ + case 13: + READ16(addr, emu8k->hwcf6); + return ret; + case 14: + READ16(addr, emu8k->hwcf7); + return ret; + + /* Simulating empty/full bits by unsetting it once read. */ case 20: - READ16(addr, emu8k->smalr | ff); - ff ^= 0x80000000; + READ16(addr, emu8k->smalr|dmareadbit); + /* xor with itself to set to zero faster. */ + dmareadbit^=dmareadbit; return ret; case 21: - READ16(addr, emu8k->smarr | ff); - ff ^= 0x80000000; + READ16(addr, emu8k->smarr|dmareadbit); + /* xor with itself to set to zero faster.*/ + dmareadbit^=dmareadbit; return ret; case 22: - READ16(addr, emu8k->smalw); + READ16(addr, emu8k->smalw|dmawritebit); + /*xor with itself to set to zero faster.*/ + dmawritebit^=dmawritebit; return ret; case 23: - READ16(addr, emu8k->smarw); + READ16(addr, emu8k->smarw|dmawritebit); + /*xor with itself to set to zero faster.*/ + dmawritebit^=dmawritebit; 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++; + emu8k->smarr = (emu8k->smarr+1) & EMU8K_MEM_ADDRESS_MASK; return val; } - - case 27: /*Sample Counter*/ + /*TODO: We need to improve the precision of this clock, since + it is used by programs to wait. Not critical, but should help reduce + the amount of calls and wait time */ + case 27: /*Sample Counter ( 44Khz clock) */ return emu8k->wc; } break; - case 2: /*INIT2*/ - case 3: /*INIT4*/ - return 0xffff; /*Can we read anything useful from here?*/ + case 2: + return emu8k->init2[emu8k->cur_voice]; + + case 3: + return emu8k->init4[emu8k->cur_voice]; case 4: return emu8k->voice[emu8k->cur_voice].atkhldv; + + case 5: + return emu8k->voice[emu8k->cur_voice].lfo1val; + + case 6: + return emu8k->voice[emu8k->cur_voice].atkhld; + + case 7: + return emu8k->voice[emu8k->cur_voice].lfo2val; } break; - case 0xc00: /*Data3*/ + case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */ switch (emu8k->cur_reg) { case 0: @@ -245,13 +700,17 @@ uint16_t emu8k_inw(uint16_t addr, void *p) 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); + + case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */ + /* LS five bits = channel number, next 3 bits = register number + * and MS 8 bits = VLSI test register. + * Impulse tracker tests the non variability of the LS byte that it has set, and the variability + * of the MS byte to determine that it really is an AWE32. + * cubic player has a similar code, where it waits until value & 0x1000 is nonzero, and then waits again until it changes to zero.*/ + random_helper = (random_helper + 1) & 0x1F; + return ((0x80 | random_helper) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice; } -/* fatal("Bad EMU8K inw from %08X\n", addr);*/ + pclog("EMU8K READ : Unknown register read: %04X-%02X(%d/%d) \n", addr, (emu8k->cur_reg << 5) | emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); return 0xffff; } @@ -259,16 +718,113 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) { emu8k_t *emu8k = (emu8k_t *)p; + /*TODO: I would like to not call this here, but i found it was needed or else cubic player would not finish opening (take a looot more of time than usual). + * Basically, being here means that the audio is generated in the emulation thread, instead of the audio thread.*/ 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) + +#ifdef EMU8K_DEBUG_REGISTERS + if (addr == 0xE22) { - case 0x400: case 0x402: /*Data0*/ + //pclog("EMU8K WRITE POINTER: %d\n", val); + } + else if ((addr&0xF00) == 0x600) + { + /* These are automatically reported by WRITE16 */ + if (rep_count_w>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w=0; + } + last_write=0; + } + else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 0) + { + /* These are automatically reported by WRITE16 */ + if (rep_count_w>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w=0; + } + last_write=0; + } + else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 1) + { + uint32_t tmpz = ((addr&0xF00) << 16)|(emu8k->cur_reg<<5); + if (tmpz != last_write) + { + if (rep_count_w>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w=0; + } + last_write=tmpz; + pclog("EMU8K WRITE RAM I/O or configuration \n"); + } + //pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + } + else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) + { + uint32_t tmpz = ((addr&0xF00) << 16); + if (tmpz != last_write) + { + if (rep_count_w>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w=0; + } + last_write=tmpz; + pclog("EMU8K WRITE INIT \n"); + } + //pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + } + else if (addr != 0xE22) + { + uint32_t tmpz = (addr << 16)|(emu8k->cur_reg<<5)| emu8k->cur_voice; + //if (tmpz != last_write) + if(1) + { + char* name = 0; + if (addr == 0xA20) + { + name = PORT_NAMES[1][emu8k->cur_reg]; + } + else if (addr == 0xA22) + { + name = PORT_NAMES[2][emu8k->cur_reg]; + } + else if (addr == 0xE20) + { + name = PORT_NAMES[3][emu8k->cur_reg]; + } + + if (rep_count_w>1) + { + pclog("EMU8K ...... for %d times\n", rep_count_w); + } + if (name == 0) + { + pclog("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + } + else + { + pclog("EMU8K WRITE %s (%d): %04X\n",name,emu8k->cur_voice, val); + } + + rep_count_w=0; + last_write=tmpz; + } + rep_count_w++; + } +#endif //EMU8K_DEBUG_REGISTERS + + + switch (addr & 0xF02) + { + case 0x600: case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */ switch (emu8k->cur_reg) { case 0: + /* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over ptrx */ WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); return; @@ -277,6 +833,7 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) return; case 2: + /* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over vtft */ WRITE16(addr, emu8k->voice[emu8k->cur_voice].cvcf, val); return; @@ -284,37 +841,62 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) WRITE16(addr, emu8k->voice[emu8k->cur_voice].vtft, val); return; + case 4: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_4, val); + return; + + case 5: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_5, 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); + emu8k_voice_t *emu_voice = &emu8k->voice[emu8k->cur_voice]; + WRITE16(addr, emu_voice->psst, val); + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu_voice->loop_start.int_address = emu_voice->psst & EMU8K_MEM_ADDRESS_MASK; + if (addr & 2) + { + emu_voice->vol_l = emu_voice->psst_pan; + emu_voice->vol_r = 255 - (emu_voice->psst_pan); + } } -/* 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);*/ + WRITE16(addr, emu8k->voice[emu8k->cur_voice].csl, val); + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].loop_end.int_address = emu8k->voice[emu8k->cur_voice].csl & EMU8K_MEM_ADDRESS_MASK; return; } break; - case 0x800: /*Data1*/ + case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */ 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);*/ + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].addr.int_address = emu8k->voice[emu8k->cur_voice].ccca & EMU8K_MEM_ADDRESS_MASK; return; case 1: switch (emu8k->cur_voice) { + case 9: + WRITE16(addr, emu8k->hwcf4, val); + return; + case 10: + WRITE16(addr, emu8k->hwcf5, val); + return; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */ + case 13: + WRITE16(addr, emu8k->hwcf6, val); + return; + case 14: + WRITE16(addr, emu8k->hwcf7, val); + return; + case 20: WRITE16(addr, emu8k->smalr, val); return; @@ -330,166 +912,578 @@ void emu8k_outw(uint16_t addr, uint16_t val, void *p) 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; + emu8k->smalw = (emu8k->smalw+1) & EMU8K_MEM_ADDRESS_MASK; + return; - case 29: /*Configuration Word 1*/ + case 29: emu8k->hwcf1 = val; return; - case 30: /*Configuration Word 2*/ + case 30: emu8k->hwcf2 = val; return; - case 31: /*Configuration Word 3*/ + case 31: 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*/ + case 2: + emu8k->init1[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) { - emu8k->voice[emu8k->cur_voice].env_state = ENV_RELEASE; - emu8k->voice[emu8k->cur_voice].env_release = val & 0x7f; + switch(emu8k->cur_voice) + { + case 0x3: emu8k->reverb_engine.out_mix = val&0xFF; + break; + case 0x5: + { + int c; + for (c=0;c<8;c++) + { + emu8k->reverb_engine.allpass[c].feedback=(val&0xFF)/((float)0xFF); + } + } + break; + case 0x7: emu8k->reverb_engine.link_return_type = (val==0x8474)? 1:0; + break; + case 0xF: emu8k->reverb_engine.reflections[0].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x17: emu8k->reverb_engine.reflections[1].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x1F: emu8k->reverb_engine.reflections[2].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x9: emu8k->reverb_engine.reflections[0].feedback = (val&0xF)/15.0; + break; + case 0xB: //emu8k->reverb_engine.reflections[0].feedback_r = (val&0xF)/15.0; + break; + case 0x11:emu8k->reverb_engine.reflections[1].feedback = (val&0xF)/15.0; + break; + case 0x13: //emu8k->reverb_engine.reflections[1].feedback_r = (val&0xF)/15.0; + break; + case 0x19: emu8k->reverb_engine.reflections[2].feedback = (val&0xF)/15.0; + break; + case 0x1B: //emu8k->reverb_engine.reflections[2].feedback_r = (val&0xF)/15.0; + break; + } } - 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 3: + emu8k->init3[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + switch(emu8k->cur_voice) + { + case 9: + emu8k->chorus_engine.feedback = (val&0xFF); + break; + case 12: + /* Limiting this to a sane value given our buffer. */ + emu8k->chorus_engine.delay_samples_central = (val&0x1FFF); + break; + + case 1: emu8k->reverb_engine.refl_in_amp = val&0xFF; + break; + case 3: //emu8k->reverb_engine.refl_in_amp_r = val&0xFF; + break; + } + } + return; + + case 4: + emu8k->voice[emu8k->cur_voice].envvol = val; + emu8k->voice[emu8k->cur_voice].vol_envelope.delay_samples = ENVVOL_TO_EMU_SAMPLES(val); + return; + + case 5: + { + emu8k->voice[emu8k->cur_voice].dcysusv = val; + emu8k_envelope_t * const vol_env = &emu8k->voice[emu8k->cur_voice].vol_envelope; + int old_on=emu8k->voice[emu8k->cur_voice].env_engine_on; + emu8k->voice[emu8k->cur_voice].env_engine_on = DCYSUSV_GENERATOR_ENGINE_ON(val); + + if (emu8k->voice[emu8k->cur_voice].env_engine_on && + old_on != emu8k->voice[emu8k->cur_voice].env_engine_on) + { + if (emu8k->hwcf3 != 0x04) + { + /* This is a hack for some programs like Doom or cubic player 1.7 that don't initialize + the hwcfg and init registers (doom does not init the card at all. only tests the cfg registers) */ + emu8k->hwcf3 = 0x04; + } + + //reset lfos. + emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; + emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; + // Trigger envelopes + if (ATKHLDV_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhldv)) + { + vol_env->value_amp_hz = 0; + if (vol_env->delay_samples) + { + vol_env->state = ENV_DELAY; + } + else if (vol_env->attack_amount_amp_hz == 0) + { + vol_env->state = ENV_STOPPED; + } + else + { + vol_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal mute, + * or it means skip attack, go to hold". + if (vol_env->attack_amount == 0) + { + vol_env->value = (1 << 21); + vol_env->state = ENV_HOLD; + }*/ + } + } + + if (ATKHLD_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhld)) + { + emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + mod_env->value_amp_hz = 0; + mod_env->value_db_oct = 0; + if (mod_env->delay_samples) + { + mod_env->state = ENV_DELAY; + } + else if (mod_env->attack_amount_amp_hz == 0) + { + mod_env->state = ENV_STOPPED; + } + else + { + mod_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal start, + * or it means skip attack, go to hold". + if (mod_env->attack_amount == 0) + { + mod_env->value = (1 << 21); + mod_env->state = ENV_HOLD; + }*/ + } + } + } + + + /* Converting the input in dBs to envelope value range. */ + vol_env->sustain_value_db_oct = DCYSUSV_SUS_TO_ENV_RANGE(DCYSUSV_SUSVALUE_GET(val)); + vol_env->ramp_amount_db_oct = env_decay_to_dbs_or_oct[DCYSUSV_DECAYRELEASE_GET(val)]; + if (DCYSUSV_IS_RELEASE(val)) + { + if (vol_env->state == ENV_DELAY || vol_env->state == ENV_ATTACK || vol_env->state == ENV_HOLD) + { + vol_env->value_db_oct = env_vol_amplitude_to_db[vol_env->value_amp_hz >> 5] << 5; + if (vol_env->value_db_oct > (1 << 21)) + vol_env->value_db_oct = 1 << 21; + } + + vol_env->state = (vol_env->value_db_oct >= vol_env->sustain_value_db_oct) ? ENV_RAMP_DOWN : ENV_RAMP_UP; + } + } + return; + + case 6: + emu8k->voice[emu8k->cur_voice].envval = val; + emu8k->voice[emu8k->cur_voice].mod_envelope.delay_samples = ENVVAL_TO_EMU_SAMPLES(val); 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; + //TODO: Look for a bug on delay (first trigger it works, next trigger it doesn't) + emu8k->voice[emu8k->cur_voice].dcysus = val; + emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + /* Converting the input in octaves to envelope value range. */ + mod_env->sustain_value_db_oct = DCYSUS_SUS_TO_ENV_RANGE(DCYSUS_SUSVALUE_GET(val)); + mod_env->ramp_amount_db_oct = env_decay_to_dbs_or_oct[DCYSUS_DECAYRELEASE_GET(val)]; + if (DCYSUS_IS_RELEASE(val)) + { + if (mod_env->state == ENV_DELAY || mod_env->state == ENV_ATTACK || mod_env->state == ENV_HOLD) + { + mod_env->value_db_oct = env_mod_hertz_to_octave[mod_env->value_amp_hz >> 9] << 9; + if (mod_env->value_db_oct >= (1 << 21)) + mod_env->value_db_oct = (1 << 21)-1; + } + + mod_env->state = (mod_env->value_db_oct >= mod_env->sustain_value_db_oct) ? ENV_RAMP_DOWN : ENV_RAMP_UP; + } } - 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*/ + case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */ 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);*/ + emu8k_voice_t *emu_voice = &emu8k->voice[emu8k->cur_voice]; + WRITE16(addr, emu_voice->ccca, val); + emu_voice->addr.int_address = emu_voice->ccca & EMU8K_MEM_ADDRESS_MASK; + uint32_t paramq = CCCA_FILTQ_GET(emu_voice->ccca); + emu_voice->filt_att = filter_atten[paramq]; + emu_voice->filterq_idx = paramq; } return; case 1: switch (emu8k->cur_voice) { - case 20: - WRITE16(addr, emu8k->smalr, val); + case 9: + WRITE16(addr, emu8k->hwcf4, val); + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + /*(1/256th of a 44Khz sample) */ + /* clip the value to a reasonable value given our buffer */ + int32_t tmp = emu8k->hwcf4&0x1FFFFF; + emu8k->chorus_engine.delay_offset_samples_right = ((double)tmp)/256.0; + } return; - case 21: - WRITE16(addr, emu8k->smarr, val); + case 10: + WRITE16(addr, emu8k->hwcf5, val); + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + /* The scale of this value is unknown. I've taken it as milliHz. + * Another interpretation could be periods. (and so, Hz = 1/period)*/ + double osc_speed = emu8k->hwcf5;//*1.316; +#if 1 // milliHz + /*milliHz to lfotable samples.*/ + osc_speed *= 65.536/44100.0; +#elif 0 //periods + /* 44.1Khz ticks to lfotable samples.*/ + osc_speed = 65.536/osc_speed; +#endif + /*left shift 32bits for 32.32 fixed.point*/ + osc_speed *= 65536.0*65536.0; + emu8k->chorus_engine.lfo_inc.addr = (uint64_t)osc_speed; + } return; - case 22: - WRITE16(addr, emu8k->smalw, val); + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/ + case 13: + WRITE16(addr, emu8k->hwcf6, val); return; - case 23: - WRITE16(addr, emu8k->smarw, val); + case 14: + WRITE16(addr, emu8k->hwcf7, val); + return; + + case 20: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/ + WRITE16(addr, emu8k->smalr, val&0xFF); + dmareadbit=0x8000; + return; + case 21: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/ + WRITE16(addr, emu8k->smarr, val&0xFF); + dmareadbit=0x8000; + return; + case 22: /*Top 8 bits are for full bit or non-addressable.*/ + WRITE16(addr, emu8k->smalw, val&0xFF); + return; + case 23: /*Top 8 bits are for full bit or non-addressable.*/ + WRITE16(addr, emu8k->smarw, val&0xFF); return; case 26: + dmawritebit=0x8000; EMU8K_WRITE(emu8k, emu8k->smarw, val); -/* pclog("emu8k_SMRW %04X %08X\n", val, emu8k->smarw);*/ emu8k->smarw++; - break; + return; } break; + case 2: + emu8k->init2[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + switch(emu8k->cur_voice) + { + case 0x14: + { + int multip = ((val&0xF00)>>8)+18; + emu8k->reverb_engine.reflections[5].bufsize = multip*REV_BUFSIZE_STEP; + emu8k->reverb_engine.tailL.bufsize = (multip+1)*REV_BUFSIZE_STEP; + if ( emu8k->reverb_engine.link_return_type == 0) + { + emu8k->reverb_engine.tailR.bufsize = (multip+1)*REV_BUFSIZE_STEP; + } + } + break; + case 0x16: + if ( emu8k->reverb_engine.link_return_type == 1) + { + int multip = ((val&0xF00)>>8)+18; + emu8k->reverb_engine.tailR.bufsize = (multip+1)*REV_BUFSIZE_STEP; + } + break; + case 0x7: emu8k->reverb_engine.reflections[3].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0xf: emu8k->reverb_engine.reflections[4].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x17: emu8k->reverb_engine.reflections[5].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x1d: + { + int c; + for (c=0;c<6;c++) + { + emu8k->reverb_engine.reflections[c].damp1=(val&0xFF)/255.0; + emu8k->reverb_engine.reflections[c].damp2=(0xFF-(val&0xFF))/255.0; + emu8k->reverb_engine.reflections[c].filterstore=0; + } + emu8k->reverb_engine.damper.damp1=(val&0xFF)/255.0; + emu8k->reverb_engine.damper.damp2=(0xFF-(val&0xFF))/255.0; + emu8k->reverb_engine.damper.filterstore=0; + } + break; + case 0x1f: /* filter r */ + break; + case 0x1: emu8k->reverb_engine.reflections[3].feedback = (val&0xF)/15.0; + break; + case 0x3: //emu8k->reverb_engine.reflections[3].feedback_r = (val&0xF)/15.0; + break; + case 0x9: emu8k->reverb_engine.reflections[4].feedback = (val&0xF)/15.0; + break; + case 0xb: //emu8k->reverb_engine.reflections[4].feedback_r = (val&0xF)/15.0; + break; + case 0x11: emu8k->reverb_engine.reflections[5].feedback = (val&0xF)/15.0; + break; + case 0x13: //emu8k->reverb_engine.reflections[5].feedback_r = (val&0xF)/15.0; + break; + } + } + return; + + case 3: + emu8k->init4[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + switch(emu8k->cur_voice) + { + case 0x3: + { + int32_t samples = ((val&0xFF)*emu8k->chorus_engine.delay_samples_central) >> 8; + emu8k->chorus_engine.lfodepth_multip = samples; + + } + break; + + case 0x1F: + emu8k->reverb_engine.link_return_amp = val&0xFF; + break; + } + } + return ; + 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; + { + emu8k->voice[emu8k->cur_voice].atkhldv = val; + emu8k_envelope_t* const vol_env = &emu8k->voice[emu8k->cur_voice].vol_envelope; + vol_env->attack_samples = env_attack_to_samples[ATKHLDV_ATTACK(val)]; + if (vol_env->attack_samples == 0) + { + vol_env->attack_amount_amp_hz = 0; + } + else + { + /* Linear amplitude increase each sample. */ + vol_env->attack_amount_amp_hz = (1<<21) / vol_env->attack_samples; + } + vol_env->hold_samples = ATKHLDV_HOLD_TO_EMU_SAMPLES(val); + if (ATKHLDV_TRIGGER(val) && emu8k->voice[emu8k->cur_voice].env_engine_on) + { + /*TODO: I assume that "envelope trigger" is the same as new note + * (since changing the IP can be done when modulating pitch too) */ + emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; + emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; + + vol_env->value_amp_hz = 0; + if (vol_env->delay_samples) + { + vol_env->state = ENV_DELAY; + } + else if (vol_env->attack_amount_amp_hz == 0) + { + vol_env->state = ENV_STOPPED; + } + else + { + vol_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal mute, + * or it means skip attack, go to hold". + if (vol_env->attack_amount == 0) + { + vol_env->value = (1 << 21); + vol_env->state = ENV_HOLD; + }*/ + } + } + } + return; + + case 5: + emu8k->voice[emu8k->cur_voice].lfo1val = val; + /* TODO: verify if this is set once, or set every time. */ + emu8k->voice[emu8k->cur_voice].lfo1_delay_samples = LFOxVAL_TO_EMU_SAMPLES(val); 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; + { + emu8k->voice[emu8k->cur_voice].atkhld = val; + emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + mod_env->attack_samples = env_attack_to_samples[ATKHLD_ATTACK(val)]; + if (mod_env->attack_samples == 0) + { + mod_env->attack_amount_amp_hz = 0; + } + else + { + /* Linear amplitude increase each sample. */ + mod_env->attack_amount_amp_hz = (1<<21) / mod_env->attack_samples; + } + mod_env->hold_samples = ATKHLD_HOLD_TO_EMU_SAMPLES(val); + if (ATKHLD_TRIGGER(val) && emu8k->voice[emu8k->cur_voice].env_engine_on) + { + mod_env->value_amp_hz = 0; + mod_env->value_db_oct = 0; + if (mod_env->delay_samples) + { + mod_env->state = ENV_DELAY; + } + else if (mod_env->attack_amount_amp_hz == 0) + { + mod_env->state = ENV_STOPPED; + } + else + { + mod_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal start, + * or it means skip attack, go to hold". + if (mod_env->attack_amount == 0) + { + mod_env->value = (1 << 21); + mod_env->state = ENV_HOLD; + }*/ + } + } + } + return; + + case 7: + emu8k->voice[emu8k->cur_voice].lfo2val = val; + emu8k->voice[emu8k->cur_voice].lfo2_delay_samples = LFOxVAL_TO_EMU_SAMPLES(val); + return; } break; - case 0xc00: /*Data3*/ + case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */ switch (emu8k->cur_reg) { case 0: emu8k->voice[emu8k->cur_voice].ip = val; - emu8k->voice[emu8k->cur_voice].pitch = val; + emu8k->voice[emu8k->cur_voice].ptrx_pit_target = freqtable[val] >> 18; 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);*/ + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + if ((val&0xFF) == 0 && the_voice->cvcf_curr_volume == 0 && the_voice->vtft_vol_target == 0 + && the_voice->dcysusv == 0x80 && the_voice->ip == 0) + { + // Patch to avoid some clicking noises with Impulse tracker or other software that sets + // different values to 0 to set noteoff, but here, 0 means no attenuation = full volume. + return; + } + the_voice->ifatn = val; + the_voice->initial_att = (((int32_t)the_voice->ifatn_attenuation <<21)/0xFF); + the_voice->vtft_vol_target = attentable[the_voice->ifatn_attenuation]; + + the_voice->initial_filter = (((int32_t)the_voice->ifatn_init_filter <<21)/0xFF); + if (the_voice->ifatn_init_filter==0xFF) + { + the_voice->vtft_filter_target = 0xFFFF; + } + else + { + the_voice->vtft_filter_target = the_voice->initial_filter >> 5; + } + } return; case 2: - emu8k->voice[emu8k->cur_voice].pefe = val; - emu8k->voice[emu8k->cur_voice].fe_height = (int8_t)(val & 0xff); + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->pefe = val; + + int divider = (the_voice->pefe_modenv_filter_height < 0) ? 0x80 : 0x7F; + the_voice->fixed_modenv_filter_height = ((int32_t)the_voice->pefe_modenv_filter_height)*0x4000/divider; + + divider = (the_voice->pefe_modenv_pitch_height < 0) ? 0x80 : 0x7F; + the_voice->fixed_modenv_pitch_height = ((int32_t)the_voice->pefe_modenv_pitch_height)*0x4000/divider; + } return; case 3: - emu8k->voice[emu8k->cur_voice].fmmod = val; - emu8k->voice[emu8k->cur_voice].lfo1_fmmod = (val >> 8); + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->fmmod = val; + + int divider = (the_voice->fmmod_lfo1_filt_mod < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_filt_mod = ((int32_t)the_voice->fmmod_lfo1_filt_mod)*0x4000/divider; + + divider = (the_voice->fmmod_lfo1_vibrato < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_vibrato = ((int32_t)the_voice->fmmod_lfo1_vibrato)*0x4000/divider; + } return; case 4: - emu8k->voice[emu8k->cur_voice].tremfrq = val; - emu8k->voice[emu8k->cur_voice].lfo1_trem = (val >> 8); + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->tremfrq = val; + the_voice->lfo1_speed = lfofreqtospeed[the_voice->tremfrq_lfo1_freq]; + + int divider = (the_voice->tremfrq_lfo1_tremolo < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_tremolo = ((int32_t)the_voice->tremfrq_lfo1_tremolo)*0x4000/divider; + } return; case 5: - emu8k->voice[emu8k->cur_voice].fm2frq2 = val; - emu8k->voice[emu8k->cur_voice].lfo2_fmmod = (val >> 8); + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->fm2frq2 = val; + the_voice->lfo2_speed = lfofreqtospeed[the_voice->fm2frq2_lfo2_freq]; + + int divider = (the_voice->fm2frq2_lfo2_vibrato < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo2_vibrato = ((int32_t)the_voice->fm2frq2_lfo2_vibrato)*0x4000/divider; + } return; - case 7: /*ID?*/ + case 7: /*ID? I believe that this allows applications to know if the emu is in use by another application */ emu8k->id = val; return; } break; - case 0xc02: /*Pointer*/ + case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */ emu8k->cur_voice = (val & 31); emu8k->cur_reg = ((val >> 5) & 7); return; } + pclog("EMU8K WRITE: Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg)<<5|emu8k->cur_voice, + emu8k->cur_reg,emu8k->cur_voice, val); + } uint8_t emu8k_inb(uint16_t addr, void *p) { + /* Reading a single byte is a feature that at least Impulse tracker uses, + * but only on detection code and not for odd addresses.*/ if (addr & 1) return emu8k_inw(addr & ~1, p) >> 1; return emu8k_inw(addr, p) & 0xff; @@ -497,254 +1491,863 @@ uint8_t emu8k_inb(uint16_t addr, void *p) void emu8k_outb(uint16_t addr, uint8_t val, void *p) { + /* TODO: AWE32 docs says that you cannot write in bytes, but if + * an app were to use this implementation, the content of the LS Byte would be lost.*/ if (addr & 1) emu8k_outw(addr & ~1, val << 8, p); else emu8k_outw(addr, val, p); } +/* TODO: This is not a correct emulation, just a workalike implementation. */ +void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engine, int count) +{ + int pos; + for (pos = 0; pos < count; pos++) + { + double lfo_inter1 = chortable[engine->lfo_pos.int_address]; + // double lfo_inter2 = chortable[(engine->lfo_pos.int_address+1)&0xFFFF]; + + double offset_lfo =lfo_inter1; //= lfo_inter1 + ((lfo_inter2-lfo_inter1)*engine->lfo_pos.fract_address/65536.0); + offset_lfo *= engine->lfodepth_multip; + + /* Work left */ + double readdouble = (double)engine->write - (double)engine->delay_samples_central - offset_lfo; + int read = (int32_t)floor(readdouble); + int fraction_part = (readdouble - (double)read)*65536.0; + int next_value = read + 1; + if(read < 0) + { + read += EMU8K_LFOCHORUS_SIZE; + if(next_value < 0) next_value += EMU8K_LFOCHORUS_SIZE; + } + else if(next_value >= EMU8K_LFOCHORUS_SIZE) + { + next_value -= EMU8K_LFOCHORUS_SIZE; + if(read >= EMU8K_LFOCHORUS_SIZE) read -= EMU8K_LFOCHORUS_SIZE; + } + int32_t dat1 = engine->chorus_left_buffer[read]; + int32_t dat2 = engine->chorus_left_buffer[next_value]; + dat1 += ((dat2-dat1)* fraction_part) >> 16; + + engine->chorus_left_buffer[engine->write] = *inbuf + ((dat1 * engine->feedback)>>8); + + + /* Work right */ + readdouble = (double)engine->write - (double)engine->delay_samples_central - engine->delay_offset_samples_right - offset_lfo; + read = (int32_t)floor(readdouble); + next_value = read + 1; + if(read < 0) + { + read += EMU8K_LFOCHORUS_SIZE; + if(next_value < 0) next_value += EMU8K_LFOCHORUS_SIZE; + } + else if(next_value >= EMU8K_LFOCHORUS_SIZE) + { + next_value -= EMU8K_LFOCHORUS_SIZE; + if(read >= EMU8K_LFOCHORUS_SIZE) read -= EMU8K_LFOCHORUS_SIZE; + } + int32_t dat3 = engine->chorus_right_buffer[read]; + int32_t dat4 = engine->chorus_right_buffer[next_value]; + dat3 += ((dat4-dat3)* fraction_part) >> 16; + + engine->chorus_right_buffer[engine->write] = *inbuf + ((dat3 * engine->feedback)>>8); + + ++engine->write; + engine->write %= EMU8K_LFOCHORUS_SIZE; + engine->lfo_pos.addr +=engine->lfo_inc.addr; + engine->lfo_pos.int_address &= 0xFFFF; + + (*outbuf++) += dat1; + (*outbuf++) += dat3; + inbuf++; + } + +} + +int32_t emu8k_reverb_comb_work(emu8k_reverb_combfilter_t* comb, int32_t in) +{ + + int32_t bufin; + /* get echo */ + int32_t output = comb->reflection[comb->read_pos]; + /* apply lowpass */ + comb->filterstore = (output*comb->damp2) + (comb->filterstore*comb->damp1); + /* appply feedback */ + bufin = in - (comb->filterstore*comb->feedback); + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = bufin; + + if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; + + return output*comb->output_gain; +} + +int32_t emu8k_reverb_diffuser_work(emu8k_reverb_combfilter_t* comb, int32_t in) +{ + + int32_t bufout = comb->reflection[comb->read_pos]; + /*diffuse*/ + int32_t bufin = -in + (bufout*comb->feedback); + int32_t output = bufout - (bufin*comb->feedback); + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = bufin; + + if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; + + return output; +} + +int32_t emu8k_reverb_tail_work(emu8k_reverb_combfilter_t* comb, emu8k_reverb_combfilter_t* allpasses, int32_t in) +{ + int32_t output = comb->reflection[comb->read_pos]; + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = in; + + //output = emu8k_reverb_allpass_work(&allpasses[0],output); + output = emu8k_reverb_diffuser_work(&allpasses[1],output); + output = emu8k_reverb_diffuser_work(&allpasses[2],output); + //output = emu8k_reverb_allpass_work(&allpasses[3],output); + + if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; + + return output; +} +int32_t emu8k_reverb_damper_work(emu8k_reverb_combfilter_t* comb, int32_t in) +{ + /* apply lowpass */ + comb->filterstore = (in*comb->damp2) + (comb->filterstore*comb->damp1); + return comb->filterstore; +} + +/* TODO: This is not a correct emulation, just a workalike implementation. */ +void emu8k_work_reverb(int32_t *inbuf, int32_t *outbuf, emu8k_reverb_eng_t *engine, int count) +{ + int pos; + if (engine->link_return_type) + { + for (pos = 0; pos < count; pos++) + { + int32_t dat1, dat2, in, in2; + in = emu8k_reverb_damper_work(&engine->damper, inbuf[pos]); + in2 = (in * engine->refl_in_amp) >> 8; + dat2 = emu8k_reverb_comb_work(&engine->reflections[0], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[1], in2); + dat1 = emu8k_reverb_comb_work(&engine->reflections[2], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[3], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[4], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[5], in2); + + dat1 += (emu8k_reverb_tail_work(&engine->tailL,&engine->allpass[0], in+dat1)*engine->link_return_amp) >> 8; + dat2 += (emu8k_reverb_tail_work(&engine->tailR,&engine->allpass[4], in+dat2)*engine->link_return_amp) >> 8; + + (*outbuf++) += (dat1 * engine->out_mix) >> 8; + (*outbuf++) += (dat2 * engine->out_mix) >> 8; + } + } + else + { + for (pos = 0; pos < count; pos++) + { + int32_t dat1, dat2, in, in2; + in = emu8k_reverb_damper_work(&engine->damper, inbuf[pos]); + in2 = (in * engine->refl_in_amp) >> 8; + dat1 = emu8k_reverb_comb_work(&engine->reflections[0], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[1], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[2], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[3], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[4], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[5], in2); + dat2 = dat1; + + dat1 += (emu8k_reverb_tail_work(&engine->tailL,&engine->allpass[0], in+dat1)*engine->link_return_amp) >> 8; + dat2 += (emu8k_reverb_tail_work(&engine->tailR,&engine->allpass[4], in+dat2)*engine->link_return_amp) >> 8; + + (*outbuf++) += (dat1 * engine->out_mix) >> 8; + (*outbuf++) += (dat2 * engine->out_mix) >> 8; + } + } +} +void emu8k_work_eq(int32_t *inoutbuf, int count) +{ + // TODO: Work EQ over buf +} + + +int32_t emu8k_vol_slide(emu8k_slide_t* slide, int32_t target) +{ + if (slide->last < target) + { + slide->last+=0x400; + if (slide->last > target) slide->last = target; + } + else if (slide->last > target) + { + slide->last-=0x400; + if (slide->last < target) slide->last = target; + } + return slide->last; +} + +//int32_t old_pitch[32]={0}; +//int32_t old_cut[32]={0}; +//int32_t old_vol[32]={0}; void emu8k_update(emu8k_t *emu8k) { int new_pos = (sound_pos_global * 44100) / 48000; - if (emu8k->pos < new_pos) + if (emu8k->pos >= new_pos) + return; + + int32_t *buf; + emu8k_voice_t* emu_voice; + int pos; + int c; + + /* Clean the buffers since we will accumulate into them. */ + buf = &emu8k->buffer[emu8k->pos*2]; + memset(buf, 0, 2*(new_pos-emu8k->pos)*sizeof(emu8k->buffer[0])); + memset(&emu8k->chorus_in_buffer[emu8k->pos], 0, (new_pos-emu8k->pos)*sizeof(emu8k->chorus_in_buffer[0])); + memset(&emu8k->reverb_in_buffer[emu8k->pos], 0, (new_pos-emu8k->pos)*sizeof(emu8k->reverb_in_buffer[0])); + + /* Voices section */ + for (c = 0; c < 32; c++) { - int32_t *buf; - int pos; - int c; - + emu_voice = &emu8k->voice[c]; 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++) + for (pos = emu8k->pos; pos < new_pos; pos++) { - buf = &emu8k->buffer[emu8k->pos*2]; - - for (pos = emu8k->pos; pos < new_pos; pos++) + int32_t dat; + + if (emu_voice->cvcf_curr_volume) { - 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; + /* Waveform oscillator */ + #ifdef RESAMPLER_LINEAR + dat = EMU8K_READ_INTERP_LINEAR(emu8k, emu_voice->addr.int_address, + emu_voice->addr.fract_address); - 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); + #elif defined RESAMPLER_CUBIC + dat = EMU8K_READ_INTERP_CUBIC(emu8k, emu_voice->addr.int_address, + emu_voice->addr.fract_address); + #endif - 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)) + /* Filter section */ + if (emu_voice->filterq_idx || emu_voice->cvcf_curr_filt_ctoff != 0xFFFF ) { - 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; + int cutoff = emu_voice->cvcf_curr_filt_ctoff >> 8; + const int64_t coef0 = filt_coeffs[emu_voice->filterq_idx][cutoff][0]; + const int64_t coef1 = filt_coeffs[emu_voice->filterq_idx][cutoff][1]; + const int64_t coef2 = filt_coeffs[emu_voice->filterq_idx][cutoff][2]; + /* clip at twice the range */ + #define ClipBuffer(buf) (buf < -16777216) ? -16777216 : (buf > 16777216) ? 16777216 : buf - 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; + #ifdef FILTER_INITIAL + #define NOOP(x) (void)x; + NOOP(coef1) + /* Apply expected attenuation. (FILTER_MOOG does it implicitly, but this one doesn't). + * Work in 24bits. */ + dat = (dat * emu_voice->filt_att) >> 8; - 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); + int64_t vhp = ((-emu_voice->filt_buffer[0] * coef2) >> 24) - emu_voice->filt_buffer[1] - dat; + emu_voice->filt_buffer[1] += (emu_voice->filt_buffer[0] * coef0) >> 24; + emu_voice->filt_buffer[0] += (vhp * coef0) >> 24; + dat = (int32_t)(emu_voice->filt_buffer[1] >> 8); + if (dat > 32767) { dat = 32767; } + else if (dat < -32768) { dat = -32768; } - emu8k->voice[c].lfo1_count += (emu8k->voice[c].tremfrq & 0xff); - emu8k->voice[c].lfo2_count += (emu8k->voice[c].fm2frq2 & 0xff); + #elif defined FILTER_MOOG + + /*move to 24bits*/ + dat <<= 8; + + dat -= (coef2 * emu_voice->filt_buffer[4]) >> 24; /*feedback*/ + int64_t t1 = emu_voice->filt_buffer[1]; + emu_voice->filt_buffer[1] = ((dat + emu_voice->filt_buffer[0]) * coef0 - emu_voice->filt_buffer[1] * coef1) >> 24; + emu_voice->filt_buffer[1] = ClipBuffer(emu_voice->filt_buffer[1]); + + int64_t t2 = emu_voice->filt_buffer[2]; + emu_voice->filt_buffer[2] = ((emu_voice->filt_buffer[1] + t1) * coef0 - emu_voice->filt_buffer[2] * coef1) >> 24; + emu_voice->filt_buffer[2] = ClipBuffer(emu_voice->filt_buffer[2]); + + int64_t t3 = emu_voice->filt_buffer[3]; + emu_voice->filt_buffer[3] = ((emu_voice->filt_buffer[2] + t2) * coef0 - emu_voice->filt_buffer[3] * coef1) >> 24; + emu_voice->filt_buffer[3] = ClipBuffer(emu_voice->filt_buffer[3]); + + emu_voice->filt_buffer[4] = ((emu_voice->filt_buffer[3] + t3) * coef0 - emu_voice->filt_buffer[4] * coef1) >> 24; + emu_voice->filt_buffer[4] = ClipBuffer(emu_voice->filt_buffer[4]); + + emu_voice->filt_buffer[0] = ClipBuffer(dat); + + dat = (int32_t)(emu_voice->filt_buffer[4] >> 8); + if (dat > 32767) { dat = 32767; } + else if (dat < -32768) { dat = -32768; } + + #elif defined FILTER_CONSTANT + + /* Apply expected attenuation. (FILTER_MOOG does it implicitly, but this one is constant gain). + * Also stay at 24bits.*/ + dat = (dat * emu_voice->filt_att) >> 8; + + emu_voice->filt_buffer[0] = (coef1 * emu_voice->filt_buffer[0] + + coef0 * (dat + + ((coef2 * (emu_voice->filt_buffer[0] - emu_voice->filt_buffer[1]))>>24)) + ) >> 24; + emu_voice->filt_buffer[1] = (coef1 * emu_voice->filt_buffer[1] + + coef0 * emu_voice->filt_buffer[0]) >> 24; + + emu_voice->filt_buffer[0] = ClipBuffer(emu_voice->filt_buffer[0]); + emu_voice->filt_buffer[1] = ClipBuffer(emu_voice->filt_buffer[1]); + + dat = (int32_t)(emu_voice->filt_buffer[1] >> 8); + if (dat > 32767) { dat = 32767; } + else if (dat < -32768) { dat = -32768; } + + #endif + + } + if (( emu8k->hwcf3 & 0x04) && !CCCA_DMA_ACTIVE(emu_voice->ccca)) + { + /*volume and pan*/ + dat = (dat * emu_voice->cvcf_curr_volume) >> 16; + + (*buf++) += (dat * emu_voice->vol_l) >> 8; + (*buf++) += (dat * emu_voice->vol_r) >> 8; + + /* Effects section */ + if (emu_voice->ptrx_revb_send > 0) + { + emu8k->reverb_in_buffer[pos]+=(dat*emu_voice->ptrx_revb_send) >> 8; + } + if (emu_voice->csl_chor_send > 0) + { + emu8k->chorus_in_buffer[pos]+=(dat*emu_voice->csl_chor_send) >> 8; + } + } } - } - 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; - } + if ( emu_voice->env_engine_on) + { + int32_t attenuation = emu_voice->initial_att; + int32_t filtercut = emu_voice->initial_filter; + int32_t currentpitch = emu_voice->ip; + /* run envelopes */ + emu8k_envelope_t *volenv = &emu_voice->vol_envelope; + switch (volenv->state) + { + case ENV_DELAY: + volenv->delay_samples--; + if (volenv->delay_samples <=0) + { + volenv->state=ENV_ATTACK; + volenv->delay_samples=0; + } + attenuation = 0x1FFFFF; + break; + + case ENV_ATTACK: + /* Attack amount is in linear amplitude */ + volenv->value_amp_hz += volenv->attack_amount_amp_hz; + if (volenv->value_amp_hz >= (1 << 21)) + { + volenv->value_amp_hz = 1 << 21; + volenv->value_db_oct = 0; + if (volenv->hold_samples) + { + volenv->state = ENV_HOLD; + } + else + { + /* RAMP_UP since db value is inverted and it is 0 at this point. */ + volenv->state = ENV_RAMP_UP; + } + } + attenuation += env_vol_amplitude_to_db[volenv->value_amp_hz >> 5] << 5; + break; + + case ENV_HOLD: + volenv->hold_samples--; + if (volenv->hold_samples <=0) + { + volenv->state=ENV_RAMP_UP; + } + attenuation += volenv->value_db_oct; + break; - emu8k->wc += (new_pos - emu8k->pos); + case ENV_RAMP_DOWN: + /* Decay/release amount is in fraction of dBs and is always positive */ + volenv->value_db_oct -= volenv->ramp_amount_db_oct; + if (volenv->value_db_oct <= volenv->sustain_value_db_oct) + { + volenv->value_db_oct = volenv->sustain_value_db_oct; + volenv->state = ENV_SUSTAIN; + } + attenuation += volenv->value_db_oct; + break; + + case ENV_RAMP_UP: + /* Decay/release amount is in fraction of dBs and is always positive */ + volenv->value_db_oct += volenv->ramp_amount_db_oct; + if (volenv->value_db_oct >= volenv->sustain_value_db_oct) + { + volenv->value_db_oct = volenv->sustain_value_db_oct; + volenv->state = ENV_SUSTAIN; + } + attenuation += volenv->value_db_oct; + break; + + case ENV_SUSTAIN: + attenuation += volenv->value_db_oct; + break; + + case ENV_STOPPED: + attenuation = 0x1FFFFF; + break; + } + + emu8k_envelope_t *modenv = &emu_voice->mod_envelope; + switch (modenv->state) + { + case ENV_DELAY: + modenv->delay_samples--; + if (modenv->delay_samples <=0) + { + modenv->state=ENV_ATTACK; + modenv->delay_samples=0; + } + break; + + case ENV_ATTACK: + /* Attack amount is in linear amplitude */ + modenv->value_amp_hz += modenv->attack_amount_amp_hz; + modenv->value_db_oct = env_mod_hertz_to_octave[modenv->value_amp_hz >> 5] << 5; + if (modenv->value_amp_hz >= (1 << 21)) + { + modenv->value_amp_hz = 1 << 21; + modenv->value_db_oct = 1 << 21; + if (modenv->hold_samples) + { + modenv->state = ENV_HOLD; + } + else + { + modenv->state = ENV_RAMP_DOWN; + } + } + break; + + case ENV_HOLD: + modenv->hold_samples--; + if (modenv->hold_samples <=0) + { + modenv->state=ENV_RAMP_UP; + } + break; + + case ENV_RAMP_DOWN: + /* Decay/release amount is in fraction of octave and is always positive */ + modenv->value_db_oct -= modenv->ramp_amount_db_oct; + if (modenv->value_db_oct <= modenv->sustain_value_db_oct) + { + modenv->value_db_oct = modenv->sustain_value_db_oct; + modenv->state = ENV_SUSTAIN; + } + break; + + case ENV_RAMP_UP: + /* Decay/release amount is in fraction of octave and is always positive */ + modenv->value_db_oct += modenv->ramp_amount_db_oct; + if (modenv->value_db_oct >= modenv->sustain_value_db_oct) + { + modenv->value_db_oct = modenv->sustain_value_db_oct; + modenv->state = ENV_SUSTAIN; + } + break; + } + + /* run lfos */ + if (emu_voice->lfo1_delay_samples) + { + emu_voice->lfo1_delay_samples--; + } + else + { + emu_voice->lfo1_count.addr += emu_voice->lfo1_speed; + emu_voice->lfo1_count.int_address &= 0xFFFF; + } + if (emu_voice->lfo2_delay_samples) + { + emu_voice->lfo2_delay_samples--; + } + else + { + emu_voice->lfo2_count.addr += emu_voice->lfo2_speed; + emu_voice->lfo2_count.int_address &= 0xFFFF; + } + + + if (emu_voice->fixed_modenv_pitch_height) + { + /* modenv range 1<<21, pitch height range 1<<14 desired range 0x1000 (+/-one octave) */ + currentpitch += ((modenv->value_db_oct>>9)*emu_voice->fixed_modenv_pitch_height) >> 14; + } + + if (emu_voice->fixed_lfo1_vibrato) + { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x1000 (+/-one octave) */ + int32_t lfo1_vibrato = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_vibrato) >> 17; + currentpitch += lfo1_vibrato; + } + if (emu_voice->fixed_lfo2_vibrato) + { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x1000 (+/-one octave) */ + int32_t lfo2_vibrato = (lfotable[emu_voice->lfo2_count.int_address]*emu_voice->fixed_lfo2_vibrato) >> 17; + currentpitch += lfo2_vibrato; + } + + if (emu_voice->fixed_modenv_filter_height) + { + /* modenv range 1<<21, pitch height range 1<<14 desired range 0x200000 (+/-full filter range) */ + filtercut += ((modenv->value_db_oct>>9)*emu_voice->fixed_modenv_filter_height) >> 5; + } + + if (emu_voice->fixed_lfo1_filt_mod) + { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x100000 (+/-three octaves) */ + int32_t lfo1_filtmod = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_filt_mod) >> 9; + filtercut += lfo1_filtmod; + } + + if (emu_voice->fixed_lfo1_tremolo) + { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x40000 (+/-12dBs). */ + int32_t lfo1_tremolo = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_tremolo) >> 11; + attenuation += lfo1_tremolo; + } + + if (currentpitch > 0xFFFF) currentpitch = 0xFFFF; + if (currentpitch < 0) currentpitch = 0; + if (attenuation > 0x1FFFFF) attenuation = 0x1FFFFF; + if (attenuation < 0) attenuation = 0; + if (filtercut > 0x1FFFFF) filtercut = 0x1FFFFF; + if (filtercut < 0) filtercut = 0; + + emu_voice->vtft_vol_target = env_vol_db_to_vol_target[attenuation >> 5]; + emu_voice->vtft_filter_target = filtercut >> 5; + emu_voice->ptrx_pit_target = freqtable[currentpitch]>>18; + + } +/* +I've recopilated these sentences to get an idea of how to loop + +- Set its PSST register and its CLS register to zero to cause no loops to occur. +-Setting the Loop Start Offset and the Loop End Offset to the same value, will cause the oscillator to loop the entire memory. + +-Setting the PlayPosition greater than the Loop End Offset, will cause the oscillator to play in reverse, back to the Loop End Offset. + It's pretty neat, but appears to be uncontrollable (the rate at which the samples are played in reverse). + +-Note that due to interpolator offset, the actual loop point is one greater than the start address +-Note that due to interpolator offset, the actual loop point will end at an address one greater than the loop address +-Note that the actual audio location is the point 1 word higher than this value due to interpolation offset +-In programs that use the awe, they generally set the loop address as "loopaddress -1" to compensate for the above. +(Note: I am already using address+1 in the interpolators so these things are already as they should.) +*/ + emu_voice->addr.addr += ((uint64_t)emu_voice->cpf_curr_pitch) << 18; + if (emu_voice->addr.addr >= emu_voice->loop_end.addr) + { + emu_voice->addr.int_address -= (emu_voice->loop_end.int_address - emu_voice->loop_start.int_address); + emu_voice->addr.int_address &= EMU8K_MEM_ADDRESS_MASK; + } + + /* TODO: How and when are the target and current values updated */ + emu_voice->cpf_curr_pitch = emu_voice->ptrx_pit_target; + emu_voice->cvcf_curr_volume = emu8k_vol_slide(&emu_voice->volumeslide,emu_voice->vtft_vol_target); + emu_voice->cvcf_curr_filt_ctoff = emu_voice->vtft_filter_target; + } - emu8k->pos = new_pos; + /* Update EMU voice registers. */ + emu_voice->ccca = (((uint32_t)emu_voice->ccca_qcontrol) << 24) | emu_voice->addr.int_address; + emu_voice->cpf_curr_frac_addr = emu_voice->addr.fract_address; + + //if ( emu_voice->cvcf_curr_volume != old_vol[c]) { + // pclog("EMUVOL (%d):%d\n", c, emu_voice->cvcf_curr_volume); + // old_vol[c]=emu_voice->cvcf_curr_volume; + //} + //pclog("EMUFILT :%d\n", emu_voice->cvcf_curr_filt_ctoff); } -} -void emu8k_init(emu8k_t *emu8k, int onboard_ram) + + buf = &emu8k->buffer[emu8k->pos*2]; + emu8k_work_reverb(&emu8k->reverb_in_buffer[emu8k->pos], buf, &emu8k->reverb_engine, new_pos-emu8k->pos); + emu8k_work_chorus(&emu8k->chorus_in_buffer[emu8k->pos], buf, &emu8k->chorus_engine, new_pos-emu8k->pos); + emu8k_work_eq(buf, new_pos-emu8k->pos); + + // Clip signal + for (pos = emu8k->pos; pos < new_pos; pos++) + { + 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; + } + + /* Update EMU clock. */ + emu8k->wc += (new_pos - emu8k->pos); + + emu8k->pos = new_pos; +} +/* onboard_ram in kilobytes */ +void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) { + uint32_t const BLOCK_SIZE_WORDS = 0x10000; FILE *f; int c; double out; - - f = romfopen("roms/awe32.raw", "rb"); + + f = romfopen("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); + fatal("AWE32.RAW not found\n"); + 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); + memmove(&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*/ + emu8k->empty = malloc(2*BLOCK_SIZE_WORDS); + memset(emu8k->empty, 0, 2*BLOCK_SIZE_WORDS); + + int j=0; + for (;j<0x8;j++) + { + emu8k->ram_pointers[j]=emu8k->rom+(j*BLOCK_SIZE_WORDS); + } + for (;j<0x20;j++) + { + emu8k->ram_pointers[j]=emu8k->empty; + } + + if (onboard_ram) + { + /*Clip to 28MB, since that's the max that we can address. */ + if (onboard_ram > 0x7000) onboard_ram = 0x7000; + emu8k->ram = malloc(onboard_ram * 1024); + memset(emu8k->ram, 0, onboard_ram * 1024); + const int i_end=onboard_ram>>7; + int i=0; + for(;iram_pointers[j]=emu8k->ram+(i*BLOCK_SIZE_WORDS); + } + emu8k->ram_end_addr = EMU8K_RAM_MEM_START + (onboard_ram<<9); + } + else + { + emu8k->ram = 0; + emu8k->ram_end_addr = EMU8K_RAM_MEM_START; + } + for (;j < 0x100;j++) + { + emu8k->ram_pointers[j]=emu8k->empty; + + } + + io_sethandler(emu_addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu_addr+0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu_addr+0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + + /*Create frequency table. (Convert initial pitch register value to a linear speed change) + * The input is encoded such as 0xe000 is center note (no pitch shift) + * and from then on , changing up or down 0x1000 (4096) increments/decrements an octave. + * Note that this is in reference to the 44.1Khz clock that the channels play at. + * The 65536 * 65536 is in order to left-shift the 32bit value to a 64bit value as a 32.32 fixed point. + */ for (c = 0; c < 0x10000; c++) { freqtable[c] = (uint64_t)(exp2((double)(c - 0xe000) / 4096.0) * 65536.0 * 65536.0); } + /* Shortcut: minimum pitch equals stopped. I don't really know if this is true, but it's better + * since some programs set the pitch to 0 for unused channels. */ + freqtable[0] = 0; - out = 65536.0; - + /* starting at 65535 because it is used for "volume target" register conversion. */ + out = 65535.0; for (c = 0; c < 256; c++) { - attentable[c] = (int)out; + attentable[c] = (int32_t)out; out /= sqrt(1.09018); /*0.375 dB steps*/ } + /* Shortcut: max attenuation is silent, not -96dB. */ + attentable[255]=0; - out = 65536; - - for (c = 0; c < 4096; c++) + /* Note: these two tables have "db" inverted: 0 dB is max volume, 65535 "db" (-96.32dBFS) is silence. + * Important: Using 65535 as max output value because this is intended to be used with the volume target register! */ + out = 65535.0; + for (c = 0; c < 0x10000; 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; + //double db = -(c*6.0205999/65535.0)*16.0; + //out = powf(10.f,db/20.f) * 65536.0; + env_vol_db_to_vol_target[c] = (int32_t)out; + /* calculated from the 65536th root of 65536 */ + out /= 1.00016923970; } + /* Shortcut: max attenuation is silent, not -96dB. */ + env_vol_db_to_vol_target[0x10000-1]=0; + /* One more position to accept max value being 65536. */ + env_vol_db_to_vol_target[0x10000]=0; - out = 125.0; + for (c = 1; c < 0x10000; c++) + { + out = -680.32142884264* 20.0 * log10(((double)c)/65535.0); + env_vol_amplitude_to_db[c] = (int32_t)out; + } + /*Shortcut: max attenuation is silent, not -96dB.*/ + env_vol_amplitude_to_db[0]=65535; + /* One more position to accept max value being 65536. */ + env_vol_amplitude_to_db[0x10000]=0; + + + for (c = 1; c < 0x10000; c++) + { + out = log2((((double)c)/0x10000)+1.0) *65536.0; + env_mod_hertz_to_octave[c] = (int32_t)out; + } + /*No hertz change, no octave change. */ + env_mod_hertz_to_octave[0]=0; + /* One more position to accept max value being 65536. */ + env_mod_hertz_to_octave[0x10000]=65536; + + + /* This formula comes from vince vu/judge dredd's awe32p10 and corresponds to what the freebsd/linux AWE32 driver has. */ + float millis; + for (c=0;c<128;c++) + { + if (c==0) + millis = 0; /* This means never attack. */ + else if (c < 32) + millis = 11878.0/c; + else + millis = 360*exp((c - 32) / (16.0/log(1.0/2.0))); + + env_attack_to_samples[c] = 44.1*millis; + /* This is an alternate formula with linear increments, but probably incorrect: + * millis = (256+4096*(0x7F-c)) */ + } + + /* The LFOs use a triangular waveform starting at zero and going 1/-1/1/-1. + * This table is stored in signed 16bits precision, with a period of 65536 samples */ + for (c = 0; c < 65536; c++) + { + int d = (c + 16384) & 65535; + if (d >= 32768) + lfotable[c] = 32768 + ((32768 - d)*2); + else + lfotable[c] = (d*2) - 32768; + } + /* The 65536 * 65536 is in order to left-shift the 32bit value to a 64bit value as a 32.32 fixed point. */ + out = 0.01; 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; + lfofreqtospeed[c] = (uint64_t)(out *65536.0/44100.0 * 65536.0 * 65536.0); + out += 0.042; } + for (c = 0; c < 65536; c++) + { + chortable[c] = sin(c*M_PI/32768.0); + } + + + /* Filter coefficients tables. Note: Values are multiplied by *16777216 to left shift 24 bits. (i.e. 8.24 fixed point) */ + int qidx; + for (qidx = 0; qidx < 16; qidx++) + { + out = 125.0; /* Start at 125Hz */ + for (c = 0; c < 256; c++) + { +#ifdef FILTER_INITIAL + float w0 = sin(2.0*M_PI*out / 44100.0); + /* The value 102.5f has been selected a bit randomly. Pretends to reach 0.2929 at w0 = 1.0 */ + float q = (qidx / 102.5f) * (1.0 + 1.0 / w0); + /* Limit max value. Else it would be 470. */ + if (q > 200) q=200; + filt_coeffs[qidx][c][0] = (int32_t)(w0 * 16777216.0); + filt_coeffs[qidx][c][1] = 16777216.0; + filt_coeffs[qidx][c][2] = (int32_t)((1.0f / (0.7071f + q)) * 16777216.0); +#elif defined FILTER_MOOG + float w0 = sin(2.0*M_PI*out / 44100.0); + float q_factor = 1.0f - w0; + float p = w0 + 0.8f * w0 * q_factor; + float f = p + p - 1.0f; + float resonance = (1.0-pow(2.0,-qidx*24.0/90.0))*0.8; + float q = resonance * (1.0f + 0.5f * q_factor * (w0 + 5.6f * q_factor * q_factor)); + filt_coeffs[qidx][c][0] = (int32_t)(p * 16777216.0); + filt_coeffs[qidx][c][1] = (int32_t)(f * 16777216.0); + filt_coeffs[qidx][c][2] = (int32_t)(q * 16777216.0); +#elif defined FILTER_CONSTANT + float q = (1.0-pow(2.0,-qidx*24.0/90.0))*0.8; + float coef0 = sin(2.0*M_PI*out / 44100.0); + float coef1 = 1.0 - coef0; + float coef2 = q * (1.0 + 1.0 / coef1); + filt_coeffs[qidx][c][0] = (int32_t)(coef0 * 16777216.0); + filt_coeffs[qidx][c][1] = (int32_t)(coef1 * 16777216.0); + filt_coeffs[qidx][c][2] = (int32_t)(coef2 * 16777216.0); +#endif //FILTER_TYPE + /* 42.66 divisions per octave (the doc says quarter seminotes which is 48, but then it would be almost an octave less) */ + out *= 1.016378315; + /* 42 divisions. This moves the max frequency to 8.5Khz.*/ + //out *= 1.0166404394; + /* This is a linear increment method, that corresponds to the NRPN table, but contradicts the EMU8KPRM doc: */ + //out = 100.0 + (c+1.0)*31.25; //31.25Hz steps */ + } + } + /* NOTE! read_pos and buffer content is implicitly initialized to zero by the sb_t structure memset on sb_awe32_init() */ + emu8k->reverb_engine.reflections[0].bufsize=2*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[1].bufsize=4*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[2].bufsize=8*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[3].bufsize=13*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[4].bufsize=19*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[5].bufsize=26*REV_BUFSIZE_STEP; + + /*This is a bit random.*/ + for (c=0;c<4;c++) + { + emu8k->reverb_engine.allpass[3-c].feedback=0.5; + emu8k->reverb_engine.allpass[3-c].bufsize=(4*c)*REV_BUFSIZE_STEP+55; + emu8k->reverb_engine.allpass[7-c].feedback=0.5; + emu8k->reverb_engine.allpass[7-c].bufsize=(4*c)*REV_BUFSIZE_STEP+55; + } + + + + /* Cubic Resampling ( 4point cubic spline) */ + double const resdouble = 1.0/(double)CUBIC_RESOLUTION; + for (c = 0; c < CUBIC_RESOLUTION; c++) + { + double x = (double)c * resdouble; + /* Cubic resolution is made of four table, but I've put them all in one table to optimize memory access. */ + cubic_table[c*4] = (-0.5 * x * x * x + x * x - 0.5 * x) ; + cubic_table[c*4+1] = ( 1.5 * x * x * x - 2.5 * x * x + 1.0) ; + cubic_table[c*4+2] = (-1.5 * x * x * x + 2.0 * x * x + 0.5 * x) ; + cubic_table[c*4+3] = ( 0.5 * x * x * x - 0.5 * x * x) ; + } + /* Even when the documentation says that this has to be written by applications to initialize the card, + * several applications and drivers ( aweman on windows, linux oss driver..) read it to detect an AWE card. */ emu8k->hwcf1 = 0x59; emu8k->hwcf2 = 0x20; - emu8k->hwcf3 = 0x04; + /* Initial state is muted. 0x04 is unmuted. */ + emu8k->hwcf3 = 0x00; } void emu8k_close(emu8k_t *emu8k) @@ -752,3 +2355,4 @@ void emu8k_close(emu8k_t *emu8k) free(emu8k->rom); free(emu8k->ram); } + diff --git a/src/sound_emu8k.h b/src/sound_emu8k.h index ac091de..85eeea6 100644 --- a/src/sound_emu8k.h +++ b/src/sound_emu8k.h @@ -1,90 +1,779 @@ +#ifndef SOUND_EMU8K_H +#define SOUND_EMU8K_H + +/* All these defines are in samples, not in bytes. */ +#define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF +#define EMU8K_RAM_MEM_START 0x200000 +#define EMU8K_FM_MEM_ADDRESS 0xFFFFE0 +#define EMU8K_RAM_POINTERS_MASK 0x3F +#define EMU8K_LFOCHORUS_SIZE 0x4000 +/* + * Everything in this file assumes little endian + */ +/* used for the increment of oscillator position*/ +typedef struct emu8k_mem_internal_t { + union { + uint64_t addr; + struct { + uint16_t fract_lw_address; + uint16_t fract_address; + uint32_t int_address; + }; + }; +} emu8k_mem_internal_t; + +/* used for access to ram pointers from oscillator position. */ +typedef struct emu8k_mem_pointers_t { + union { + uint32_t addr; + struct { + uint16_t lw_address; + uint8_t hb_address; + uint8_t unused_address; + }; + }; +} emu8k_mem_pointers_t; + +/* + * From the Soundfount 2.0 fileformat Spec.: + * + An envelope generates a control signal in six phases. + When key-on occurs, a delay period begins during which the envelope value is zero. + The envelope then rises in a convex curve to a value of one during the attack phase. + " Note that the attack is convex; the curve is nominally such that when applied to a + decibel or semitone parameter, the result is linear in amplitude or Hz respectively" + + When a value of one is reached, the envelope enters a hold phase during which it remains at one. + When the hold phase ends, the envelope enters a decay phase during which its value decreases linearly to a sustain level. + " For the Volume Envelope, the decay phase linearly ramps toward the sustain level, causing a constant dB change for each time unit. " + When the sustain level is reached, the envelope enters sustain phase, during which the envelope stays at the sustain level. + + Whenever a key-off occurs, the envelope immediately enters a release phase during which the value linearly ramps from the current value to zero. + " For the Volume Envelope, the release phase linearly ramps toward zero from the current level, causing a constant dB change for each time unit" + + When zero is reached, the envelope value remains at zero. + + Modulation of pitch and filter cutoff are in octaves, semitones, and cents. + These parameters can be modulated to varying degree, either positively or negatively, by the modulation envelope. + The degree of modulation is specified in cents for the full-scale attack peak. + + The volume envelope operates in dB, with the attack peak providing a full scale output, appropriately scaled by the initial volume. + The zero value, however, is actually zero gain. + The implementation in the EMU8000 provides for 96 dB of amplitude control. + When 96 dB of attenuation is reached in the final gain amplifier, an abrupt jump to zero gain + (infinite dB of attenuation) occurs. In a 16-bit system, this jump is inaudible +*/ +/* It seems that the envelopes don't really have a decay/release stage, + * but instead they have a volume ramper that can be triggered + * automatically (after hold period), or manually (by activating release) + * and the "sustain" value is the target of any of both cases. + * Some programs like cubic player and AWEAmp use this, and it was + * described in the following way in Vince Vu/Judge Dredd's awe32p10.txt: + * If the MSB (most significant bit or bit 15) of this register is set, + * the Decay/Release will begin immediately, overriding the Delay, Attack, + * and Hold. Otherwise the Decay/Release will wait until the Delay, Attack, + * and Hold are finished. If you set the MSB of this register, you can use + * it as a volume ramper, as on the GUS. The upper byte (except the MSB), + * contains the destination volume, and the lower byte contains the ramp time. + */ + +/* attack_amount is linear amplitude (added directly to value). + * ramp_amount_db is linear dB (added directly to value too, but needs conversion to get linear amplitude). + * value range is 21bits for both, linear amplitude being 1<<21 = 0dBFS and 0 = -96dBFS (which is shortcut to silence), + * and db amplutide being 0 = 0dBFS and -(1<<21) = -96dBFS (which is shortcut to silence). + * This allows to operate db values by simply adding them. + */ +typedef struct emu8k_envelope_t { + int state; + int32_t delay_samples, hold_samples, attack_samples; + int32_t value_amp_hz, value_db_oct; + int32_t sustain_value_db_oct; + int32_t attack_amount_amp_hz, ramp_amount_db_oct; +} emu8k_envelope_t; + + + +typedef struct emu8k_chorus_eng_t { + int32_t write; + int32_t feedback; + int32_t delay_samples_central; + double lfodepth_multip; + double delay_offset_samples_right; + emu8k_mem_internal_t lfo_inc; + emu8k_mem_internal_t lfo_pos; + + int32_t chorus_left_buffer[EMU8K_LFOCHORUS_SIZE]; + int32_t chorus_right_buffer[EMU8K_LFOCHORUS_SIZE]; + +} emu8k_chorus_eng_t; + +/* 32 * 242. 32 comes from the "right" room resso case.*/ +#define MAX_REFL_SIZE 7744 + + +/* Reverb parameters description, extracted from AST sources. + Mix level + Decay + Link return amp + Link type Switches between normal or panned + Room reso ( ms) L&R (Ref 6 +1) + Ref 1 x2 (11 ms)R + Ref 2 x4 (22 ms)R + Ref 3 x8 (44 ms)L + Ref 4 x13(71 ms)R + Ref 5 x19(105ms)L + Ref 6 x ( ms)R (multiplier changes with room reso) + Ref 1-6 filter L&R + Ref 1-6 amp L&R + Ref 1 feedback L&R + Ref 2 feedback L&R + Ref 3 feedback L&R + Ref 4 feedback L&R + Ref 5 feedback L&R + Ref 6 feedback L&R +*/ +typedef struct emu8k_reverb_combfilter_t { + int read_pos; + int32_t reflection[MAX_REFL_SIZE]; + float output_gain; + float feedback; + float damp1; + float damp2; + int bufsize; + int32_t filterstore; +} emu8k_reverb_combfilter_t; + +typedef struct emu8k_reverb_eng_t { + + int16_t out_mix; + int16_t link_return_amp; /* tail part output gain ? */ + int8_t link_return_type; + + uint8_t refl_in_amp; + + emu8k_reverb_combfilter_t reflections[6]; + emu8k_reverb_combfilter_t allpass[8]; + emu8k_reverb_combfilter_t tailL; + emu8k_reverb_combfilter_t tailR; + + emu8k_reverb_combfilter_t damper; +} emu8k_reverb_eng_t; + +typedef struct emu8k_slide_t { + int32_t last; +} emu8k_slide_t; + + +typedef struct emu8k_voice_t +{ + union { + uint32_t cpf; + struct { + uint16_t cpf_curr_frac_addr; /* fractional part of the playing cursor. */ + uint16_t cpf_curr_pitch; /* 0x4000 = no shift. Linear increment */ + }; + }; + union { + uint32_t ptrx; + struct { + uint8_t ptrx_pan_aux; + uint8_t ptrx_revb_send; + uint16_t ptrx_pit_target; /* target pitch to which slide at curr_pitch speed. */ + }; + }; + union { + uint32_t cvcf; + struct { + uint16_t cvcf_curr_filt_ctoff; + uint16_t cvcf_curr_volume; + }; + }; + emu8k_slide_t volumeslide; + union { + uint32_t vtft; + struct { + uint16_t vtft_filter_target; + uint16_t vtft_vol_target; /* written to by the envelope engine. */ + }; + }; + /* These registers are used at least by the Windows drivers, and seem to be resetting + * something, similarly to targets and current, but... of what? + * what is curious is that if they are already zero, they are not written to, so it really + * looks like they are information about the status of the channel. (lfo position maybe?) */ + uint32_t unknown_data0_4; + uint32_t unknown_data0_5; + union { + uint32_t psst; + struct { + uint16_t psst_lw_address; + uint8_t psst_hw_address; + uint8_t psst_pan; + }; + #define PSST_LOOP_START_MASK 0x00FFFFFF /* In samples, i.e. uint16_t array[BOARD_RAM/2]; */ + }; + union { + uint32_t csl; + struct { + uint16_t csl_lw_address; + uint8_t csl_hw_address; + uint8_t csl_chor_send; + }; + #define CSL_LOOP_END_MASK 0x00FFFFFF /* In samples, i.e. uint16_t array[BOARD_RAM/2]; */ + }; + union { + uint32_t ccca; + struct { + uint16_t ccca_lw_addr; + uint8_t ccca_hb_addr; + uint8_t ccca_qcontrol; + }; + }; + #define CCCA_FILTQ_GET(ccca) (ccca>>28) + #define CCCA_FILTQ_SET(ccca,q) ccca = (ccca&0x0FFFFFFF) | (q<<28) + /* Bit 27 should always be zero */ + #define CCCA_DMA_ACTIVE(ccca) (ccca&0x04000000) + #define CCCA_DMA_WRITE_MODE(ccca) (ccca&0x02000000) + #define CCCA_DMA_WRITE_RIGHT(ccca) (ccca&0x01000000) + + uint16_t envvol; + #define ENVVOL_NODELAY(envol) (envvol&0x8000) + /* Verified with a soundfont bank. 7FFF is the minimum delay time, and 0 is the max delay time */ + #define ENVVOL_TO_EMU_SAMPLES(envvol) (envvol&0x8000) ? 0 : ((0x8000-(envvol&0x7FFF)) <<5) + + uint16_t dcysusv; + #define DCYSUSV_IS_RELEASE(dcysusv) (dcysusv&0x8000) + #define DCYSUSV_GENERATOR_ENGINE_ON(dcysusv) !(dcysusv&0x0080) + #define DCYSUSV_SUSVALUE_GET(dcysusv) ((dcysusv>>8)&0x7F) + /* Inverting the range compared to documentation because the envelope runs from 0dBFS = 0 to -96dBFS = (1 <<21) */ + #define DCYSUSV_SUS_TO_ENV_RANGE(susvalue) (((0x7F-susvalue) << 21)/0x7F) + #define DCYSUSV_DECAYRELEASE_GET(dcysusv) (dcysusv&0x7F) + + uint16_t envval; + #define ENVVAL_NODELAY(enval) (envval&0x8000) + /* Verified with a soundfont bank. 7FFF is the minimum delay time, and 0 is the max delay time */ + #define ENVVAL_TO_EMU_SAMPLES(envval)(envval&0x8000) ? 0 : ((0x8000-(envval&0x7FFF)) <<5) + + uint16_t dcysus; + #define DCYSUS_IS_RELEASE(dcysus) (dcysus&0x8000) + #define DCYSUS_SUSVALUE_GET(dcysus) ((dcysus>>8)&0x7F) + #define DCYSUS_SUS_TO_ENV_RANGE(susvalue) ((susvalue << 21)/0x7F) + #define DCYSUS_DECAYRELEASE_GET(dcysus) (dcysus&0x7F) + + uint16_t atkhldv; + #define ATKHLDV_TRIGGER(atkhldv) !(atkhldv&0x8000) + #define ATKHLDV_HOLD(atkhldv) ((atkhldv>>8)&0x7F) + #define ATKHLDV_HOLD_TO_EMU_SAMPLES(atkhldv) (4096*(0x7F-((atkhldv>>8)&0x7F))) + #define ATKHLDV_ATTACK(atkhldv) (atkhldv&0x7F) + + uint16_t lfo1val, lfo2val; + #define LFOxVAL_NODELAY(lfoxval) (lfoxval&0x8000) + #define LFOxVAL_TO_EMU_SAMPLES(lfoxval) (lfoxval&0x8000) ? 0 : ((0x8000-(lfoxval&0x7FFF)) <<5) + + uint16_t atkhld; + #define ATKHLD_TRIGGER(atkhld) !(atkhld&0x8000) + #define ATKHLD_HOLD(atkhld) ((atkhld>>8)&0x7F) + #define ATKHLD_HOLD_TO_EMU_SAMPLES(atkhld) (4096*(0x7F-((atkhld>>8)&0x7F))) + #define ATKHLD_ATTACK(atkhld) (atkhld&0x7F) + + + uint16_t ip; + #define INTIAL_PITCH_CENTER 0xE000 + #define INTIAL_PITCH_OCTAVE 0x1000 + + union { + uint16_t ifatn; + struct{ + uint8_t ifatn_attenuation; + uint8_t ifatn_init_filter; + }; + }; + union { + uint16_t pefe; + struct { + int8_t pefe_modenv_filter_height; + int8_t pefe_modenv_pitch_height; + }; + }; + union { + uint16_t fmmod; + struct { + int8_t fmmod_lfo1_filt_mod; + int8_t fmmod_lfo1_vibrato; + }; + }; + union { + uint16_t tremfrq; + struct { + uint8_t tremfrq_lfo1_freq; + int8_t tremfrq_lfo1_tremolo; + }; + }; + union { + uint16_t fm2frq2; + struct { + uint8_t fm2frq2_lfo2_freq; + int8_t fm2frq2_lfo2_vibrato; + }; + }; + + int env_engine_on; + + emu8k_mem_internal_t addr, loop_start, loop_end; + + int32_t initial_att; + int32_t initial_filter; + + emu8k_envelope_t vol_envelope; + emu8k_envelope_t mod_envelope; + + int64_t lfo1_speed, lfo2_speed; + emu8k_mem_internal_t lfo1_count, lfo2_count; + int32_t lfo1_delay_samples, lfo2_delay_samples; + int vol_l, vol_r; + + int16_t fixed_modenv_filter_height; + int16_t fixed_modenv_pitch_height; + int16_t fixed_lfo1_filt_mod; + int16_t fixed_lfo1_vibrato; + int16_t fixed_lfo1_tremolo; + int16_t fixed_lfo2_vibrato; + + /* filter internal data. */ + int filterq_idx; + int32_t filt_att; + int64_t filt_buffer[5]; + +} emu8k_voice_t; + 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; + emu8k_voice_t voice[32]; - 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; + uint16_t hwcf1, hwcf2, hwcf3; + uint32_t hwcf4, hwcf5, hwcf6, hwcf7; - 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; + uint16_t init1[32], init2[32], init3[32], init4[32]; uint32_t smalr, smarr, smalw, smarw; uint16_t smld_buffer, smrd_buffer; uint16_t wc; - uint16_t c02_read; + uint16_t id; - uint16_t id; - - int16_t *ram, *rom; - + /* The empty block is used to act as an unallocated memory returning zero. */ + int16_t *ram, *rom, *empty; + + /* RAM pointers are a way to avoid checking ram boundaries on read */ + int16_t *ram_pointers[0x100]; uint32_t ram_end_addr; - + int cur_reg, cur_voice; - int timer_count; - int16_t out_l, out_r; + emu8k_chorus_eng_t chorus_engine; + int32_t chorus_in_buffer[MAXSOUNDBUFLEN]; + emu8k_reverb_eng_t reverb_engine; + int32_t reverb_in_buffer[MAXSOUNDBUFLEN]; + int pos; - int32_t buffer[SOUNDBUFLEN * 2]; + int32_t buffer[MAXSOUNDBUFLEN * 2]; } emu8k_t; -void emu8k_init(emu8k_t *emu8k, int onboard_ram); + + +void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram); void emu8k_close(emu8k_t *emu8k); void emu8k_update(emu8k_t *emu8k); + + + + +/* + +Section E - Introduction to the EMU8000 Chip + + The EMU8000 has its roots in E-mu's Proteus sample playback + modules and their renowned Emulator sampler. The EMU8000 has + 32 individual oscillators, each playing back at 44.1 kHz. By + incorporating sophisticated sample interpolation algorithms + and digital filtering, the EMU8000 is capable of producing + high fidelity sample playback. + + The EMU8000 has an extensive modulation capability using two + sine-wave LFOs (Low Frequency Oscillator) and two multi- + stage envelope generators. + + What exactly does modulation mean? Modulation means to + dynamically change a parameter of an audio signal, whether + it be the volume (amplitude modulation, or tremolo), pitch + (frequency modulation, or vibrato) or filter cutoff + frequency (filter modulation, or wah-wah). To modulate + something we would require a modulation source, and a + modulation destination. In the EMU8000, the modulation + sources are the LFOs and the envelope generators, and the + modulation destinations can be the pitch, the volume or the + filter cutoff frequency. + + The EMU8000's LFOs and envelope generators provide a complex + modulation environment. Each sound producing element of the + EMU8000 consists of a resonant low-pass filter, two LFOs, in + which one modulates the pitch (LFO2), and the other + modulates pitch, filter cutoff and volume (LFO1) + simultaneously. There are two envelope generators; envelope + 1 contours both pitch and filter cutoff simultaneously, and + envelope 2 contours volume. The output stage consists of an + effects engine that mixes the dry signals with the + Reverb/chorus level signals to produce the final mix. + + What are the EMU8000 sound elements? + + Each of the sound elements in an EMU8000 consists of the + following: + + Oscillator + An oscillator is the source of an audio signal. + + Low Pass Filter + The low pass filter is responsible for modifying the + timbres of an instrument. The low pass filter's filter + cutoff values can be varied from 100 Hz to 8000 Hz. By + changing the values of the filter cutoff, a myriad of + analogue sounding filter sweeps can be achieved. An + example of a GM instrument that makes use of filter sweep + is instrument number 87, Lead 7 (fifths). + + Amplifier + The amplifier determines the loudness of an audio signal. + + LFO1 + An LFO, or Low Frequency Oscillator, is normally used to + periodically modulate, that is, change a sound parameter, + whether it be volume (amplitude modulation), pitch + (frequency modulation) or filter cutoff (filter + modulation). It operates at sub-audio frequency from + 0.042 Hz to 10.71 Hz. The LFO1 in the EMU8000 modulates + the pitch, volume and filter cutoff simultaneously. + + LFO2 + The LFO2 is similar to the LFO1, except that it modulates + the pitch of the audio signal only. + + Resonance + A filter alone would be like an equalizer, making a + bright audio signal duller, but the addition of resonance + greatly increases the creative potential of a filter. + Increasing the resonance of a filter makes it emphasize + signals at the cutoff frequency, giving the audio signal + a subtle wah-wah, that is, imagine a siren sound going + from bright to dull to bright again periodically. + + LFO1 to Volume (Tremolo) + The LFO1's output is routed to the amplifier, with the + depth of oscillation determined by LFO1 to Volume. LFO1 + to Volume produces tremolo, which is a periodic + fluctuation of volume. Lets say you are listening to a + piece of music on your home stereo system. When you + rapidly increase and decrease the playback volume, you + are creating tremolo effect, and the speed in which you + increases and decreases the volume is the tremolo rate + (which corresponds to the speed at which the LFO is + oscillating). An example of a GM instrument that makes + use of LFO1 to Volume is instrument number 45, Tremolo + Strings. + + LFO1 to Filter Cutoff (Wah-Wah) + The LFO1's output is routed to the filter, with the depth + of oscillation determined by LFO1 to Filter. LFO1 to + Filter produces a periodic fluctuation in the filter + cutoff frequency, producing an effect very similar to + that of a wah-wah guitar (see resonance for a description + of wah-wah) An example of a GM instrument that makes + use of LFO1 to Filter Cutoff is instrument number 19, + Rock Organ. + + LFO1 to Pitch (Vibrato) + The LFO1's output is routed to the oscillator, with the + depth of oscillation determined by LFO1 to Pitch. LFO1 to + Pitch produces a periodic fluctuation in the pitch of the + oscillator, producing a vibrato effect. An example of a + GM instrument that makes use of LFO1 to Pitch is + instrument number 57, Trumpet. + + LFO2 to Pitch (Vibrato) + The LFO1 in the EMU8000 can simultaneously modulate + pitch, volume and filter. LFO2, on the other hand, + modulates only the pitch, with the depth of modulation + determined by LFO2 to Pitch. LFO2 to Pitch produces a + periodic fluctuation in the pitch of the oscillator, + producing a vibrato effect. When this is coupled with + LFO1 to Pitch, a complex vibrato effect can be achieved. + + Volume Envelope + The character of a musical instrument is largely + determined by its volume envelope, the way in which the + level of the sound changes with time. For example, + percussive sounds usually start suddenly and then die + away, whereas a bowed sound might take quite some time to + start and then sustain at a more or less fixed level. + + A six-stage envelope makes up the volume envelope of the + EMU8000. The six stages are delay, attack, hold, decay, + sustain and release. The stages can be described as + follows: + + Delay The time between when a key is played and when + the attack phase begins + Attack The time it takes to go from zero to the peak + (full) level. + Hold The time the envelope will stay at the peak + level before starting the decay phase. + Decay The time it takes the envelope to go from the + peak level to the sustain level. + Sustain The level at which the envelope remains as long + as a key is held down. + Release The time it takes the envelope to fall to the + zero level after the key is released. + + Using these six parameters can yield very realistic + reproduction of the volume envelope characteristics of + many musical instruments. + + Pitch and Filter Envelope + The pitch and filter envelope is similar to the volume + envelope in that it has the same envelope stages. The + difference between them is that whereas the volume + envelope contours the volume of the instrument over time, + the pitch and filter envelope contours the pitch and + filter values of the instrument over time. The pitch + envelope is particularly useful in putting the finishing + touches in simulating a natural instrument. For example, + some wind instruments tend to go slightly sharp when they + are first blown, and this characteristic can be simulated + by setting up a pitch envelope with a fairly fast attack + and decay. The filter envelope, on the other hand, is + useful in creating synthetic sci-fi sound textures. An + example of a GM instrument that makes use of the filter + envelope is instrument number 86, Pad 8 (Sweep). + + Pitch/Filter Envelope Modulation + These two parameters determine the modulation depth of + the pitch and filter envelope. In the wind instrument + example above, a small amount of pitch envelope + modulation is desirable to simulate its natural pitch + characteristics. + + This rich modulation capability of the EMU8000 is fully + exploited by the SB AWE32 MIDI drivers. The driver also + provides you with a means to change these parameters over + MIDI in real time. Refer to the section "How do I change an + instrument's sound parameter in real time" for more + information. + + + + + Room 1 - 3 + This group of reverb variation simulates the natural + ambiance of a room. Room 1 simulates a small room, Room 2 + simulates a slightly bigger room, and Room 3 simulates a + big room. + + Hall 1 - 2 + This group of reverb variation simulates the natural + ambiance of a concert hall. It has greater depth than the + room variations. Again, Hall 1 simulates a small hall, + and Hall 2 simulates a larger hall. + + Plate + Back in the old days, reverb effects were sometimes + produced using a metal plate, and this type of reverb + produces a metallic echo. The SB AWE32's Plate variation + simulates this form of reverb. + + Delay + This reverb produces a delay, that is, echo effect. + + Panning Delay + This reverb variation produces a delay effect that is + continuously panned left and right. + + Chorus 1 - 4 + Chorus produces a "beating" effect. The chorus effects + are more prominent going from chorus 1 to chorus 4. + + Feedback Chorus + This chorus variation simulates a soft "swishing" effect. + + Flanger + This chorus variation produces a more prominent feedback + chorus effect. + + Short Delay + This chorus variation simulates a delay repeated in a + short time. + + Short Delay (feed back) + This chorus variation simulates a short delay repeated + (feedback) many times. + + + +Registers to write the Chorus Parameters to (all are 16-bit, unless noted): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +0x3409 +0x340C +0x3603 +0x1409 (32-Bit) +0x140A (32-Bit) +then write 0x8000 to 0x140D (32-Bit) +and then 0x0000 to 0x140E (32-Bit) + +Chorus Parameters: + +Chorus 1 Chorus 2 Chorus 3 Chorus 4 Feedback Flanger + +0xE600 0xE608 0xE610 0xE620 0xE680 0xE6E0 +0x03F6 0x031A 0x031A 0x0269 0x04D3 0x044E +0xBC2C 0xBC6E 0xBC84 0xBC6E 0xBCA6 0xBC37 +0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 +0x006D 0x017C 0x0083 0x017C 0x005B 0x0026 + +Short Delay Short Delay + Feedback + +0xE600 0xE6C0 +0x0B06 0x0B06 +0xBC00 0xBC00 +0xE000 0xE000 +0x0083 0x0083 + +// Chorus Params +typedef struct { + WORD FbkLevel; // Feedback Level (0xE600-0xE6FF) + WORD Delay; // Delay (0-0x0DA3) [1/44100 sec] + WORD LfoDepth; // LFO Depth (0xBC00-0xBCFF) + DWORD DelayR; // Right Delay (0-0xFFFFFFFF) [1/256/44100 sec] + DWORD LfoFreq; // LFO Frequency (0-0xFFFFFFFF) + } CHORUS_TYPE; + + +Registers to write the Reverb Parameters to (they are all 16-bit): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +0x2403,0x2405,0x361F,0x2407,0x2614,0x2616,0x240F,0x2417, +0x241F,0x2607,0x260F,0x2617,0x261D,0x261F,0x3401,0x3403, +0x2409,0x240B,0x2411,0x2413,0x2419,0x241B,0x2601,0x2603, +0x2609,0x260B,0x2611,0x2613 + +Reverb Parameters: + +Room 1: + +0xB488,0xA450,0x9550,0x84B5,0x383A,0x3EB5,0x72F4,0x72A4, +0x7254,0x7204,0x7204,0x7204,0x4416,0x4516,0xA490,0xA590, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Room 2: + +0xB488,0xA458,0x9558,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,0xA440,0xA540, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Room 3: + +0xB488,0xA460,0x9560,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4416,0x4516,0xA490,0xA590, +0x842C,0x852C,0x842C,0x852C,0x842B,0x852B,0x842B,0x852B, +0x842A,0x852A,0x842A,0x852A + +Hall 1: + +0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,0xA440,0xA540, +0x842B,0x852B,0x842B,0x852B,0x842A,0x852A,0x842A,0x852A, +0x8429,0x8529,0x8429,0x8529 + +Hall 2: + +0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7254,0x7234, +0x7224,0x7254,0x7264,0x7294,0x44C3,0x45C3,0xA404,0xA504, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Plate: + +0xB4FF,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7234,0x7234, +0x7234,0x7234,0x7234,0x7234,0x4448,0x4548,0xA440,0xA540, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Delay: + +0xB4FF,0xA470,0x9500,0x84B5,0x333A,0x39B5,0x7204,0x7204, +0x7204,0x7204,0x7204,0x72F4,0x4400,0x4500,0xA4FF,0xA5FF, +0x8420,0x8520,0x8420,0x8520,0x8420,0x8520,0x8420,0x8520, +0x8420,0x8520,0x8420,0x8520 + +Panning Delay: + +0xB4FF,0xA490,0x9590,0x8474,0x333A,0x39B5,0x7204,0x7204, +0x7204,0x7204,0x7204,0x72F4,0x4400,0x4500,0xA4FF,0xA5FF, +0x8420,0x8520,0x8420,0x8520,0x8420,0x8520,0x8420,0x8520, +0x8420,0x8520,0x8420,0x8520 + +Registers to write the EQ Parameters to (16-Bit): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +Bass: + +0x3601 +0x3611 + +Treble: + +0x3411 +0x3413 +0x341B +0x3607 +0x360B +0x360D +0x3617 +0x3619 + +Total: + +write the 0x0263 + 3rd parameter of the Bass EQ + 9th parameter of Treble EQ to 0x3615. +write the 0x8363 + 3rd parameter of the Bass EQ + 9th parameter of Treble EQ to 0x3615. + + +Bass Parameters: + +0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: + +0xD26A 0xD25B 0xD24C 0xD23D 0xD21F 0xC208 0xC219 0xC22A 0xC24C 0xC26E 0xC248 0xC26A +0xD36A 0xD35B 0xD34C 0xD33D 0xC31F 0xC308 0xC308 0xC32A 0xC34C 0xC36E 0xC384 0xC36A +0x0000 0x0000 0x0000 0x0000 0x0000 0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 + +Treble Parameters: + +0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: +0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821D 0x821C +0xC26A 0xC25B 0xC24C 0xC23D 0xC21F 0xD208 0xD208 0xD208 0xD208 0xD208 0xD219 0xD22A +0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031D 0x031C +0xC36A 0xC35B 0xC34C 0xC33D 0xC31F 0xD308 0xD308 0xD308 0xD308 0xD308 0xD319 0xD32A +0x021E 0x021E 0x021E 0x021E 0x021E 0x021E 0x021D 0x021C 0x021A 0x0219 0x0219 0x0219 +0xD208 0xD208 0xD208 0xD208 0xD208 0xD208 0xD219 0xD22A 0xD24C 0xD26E 0xD26E 0xD26E +0x831E 0x831E 0x831E 0x831E 0x831E 0x831E 0x831D 0x831C 0x831A 0x8319 0x8319 0x8319 +0xD308 0xD308 0xD308 0xD308 0xD308 0xD308 0xD3019 0xD32A 0xD34C 0xD36E 0xD36E 0xD36E +0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 +*/ + +#endif /* SOUND_EMU8K_H */ diff --git a/src/sound_gus.c b/src/sound_gus.c index 4cd84ec..05700c2 100644 --- a/src/sound_gus.c +++ b/src/sound_gus.c @@ -39,16 +39,17 @@ typedef struct gus_t int32_t out_l, out_r; - int16_t buffer[2][SOUNDBUFLEN]; + int16_t buffer[2][MAXSOUNDBUFLEN]; int pos; - int samp_timer, samp_latch; + pc_timer_t samp_timer; + uint64_t samp_latch; uint8_t *ram; int irqnext; - int timer_1, timer_2; + pc_timer_t timer_1, timer_2; int irq, dma, irq_midi; int latch_enable; @@ -84,40 +85,6 @@ int gusfreqs[]= 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, @@ -143,6 +110,73 @@ enum GUS_TIMER_CTRL_AUTO = 0x01 }; +void gus_update_int_status(gus_t *gus) +{ + int c; + int irq_pending = 0; + int midi_irq_pending = 0; + + gus->irqstatus&=~0x60; + gus->irqstatus2=0xE0; + 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); + irq_pending = 1; + break; + } + 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); + irq_pending = 1; + break; + } + } + if ((gus->tctrl & 4) && (gus->irqstatus & 0x04)) + irq_pending = 1; /*Timer 1 interrupt pending*/ + if ((gus->tctrl & 8) && (gus->irqstatus & 0x08)) + irq_pending = 1; /*Timer 2 interrupt pending*/ + if ((gus->irqstatus & 0x80) && (gus->dmactrl & 0x20)) + irq_pending = 1; /*DMA TC interrupt pending*/ + + midi_irq_pending = gus->midi_status & MIDI_INT_MASTER; + +// pclog("gus_update_int_status: tctrl=%02x irqstatus=%02x irq_pending=%i midi_irq_pending=%i gus->irq=%i gus->irq_midi=%i\n", +// gus->tctrl, gus->irqstatus, irq_pending, midi_irq_pending, gus->irq, gus->irq_midi); + if (gus->irq == gus->irq_midi && gus->irq != -1) + { + if (irq_pending || midi_irq_pending) + picintlevel(1 << gus->irq); + else + picintc(1 << gus->irq); + } + else + { + if (gus->irq != -1) + { + if (irq_pending) + picintlevel(1 << gus->irq); + else + picintc(1 << gus->irq); + } + if (gus->irq_midi != -1) + { + if (midi_irq_pending) + picintlevel(1 << gus->irq_midi); + else + picintc(1 << gus->irq_midi); + } + } +} + void gus_midi_update_int_status(gus_t *gus) { gus->midi_status &= ~MIDI_INT_MASTER; @@ -162,11 +196,7 @@ void gus_midi_update_int_status(gus_t *gus) 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); - } + gus_update_int_status(gus); } void writegus(uint16_t addr, uint8_t val, void *p) @@ -270,6 +300,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); case 0x45: /*Timer control*/ // printf("Timer control %02X\n",val); gus->tctrl=val; + gus_update_int_status(gus); break; } break; @@ -290,7 +321,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); old = gus->waveirqs[gus->voice]; gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; if (gus->waveirqs[gus->voice] != old) - pollgusirqs(gus); + gus_update_int_status(gus); break; case 1: /*Frequency control*/ gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8); @@ -354,7 +385,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); gus->rctrl[gus->voice] = val & 0x7F; gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; if (gus->rampirqs[gus->voice] != old) - pollgusirqs(gus); + gus_update_int_status(gus); // printf("Ramp control %02i %02X %02X %i\n",gus->voice,val,gus->rampirqs[gus->voice],ins); break; @@ -365,9 +396,9 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); gus->global=val; // printf("GUS voices %i\n",val&31); if (gus->voices < 14) - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); else - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); break; case 0x41: /*DMA*/ @@ -380,20 +411,34 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); 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; + if (val & 0x04) + { + uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); + d = gus->ram[gus_addr] | (gus->ram[gus_addr + 1] << 8); + if (val & 0x80) + d ^= 0x8080; + dma_result = dma_channel_write(gus->dma, d); + if (dma_result == DMA_NODATA) + break; + } + else + { + 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; + 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; + gus->irqnext = 1; } else { @@ -403,17 +448,29 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); d = dma_channel_read(gus->dma); if (d == DMA_NODATA) break; - if (val&0x80) d^=0x80; - gus->ram[gus->dmaaddr]=d; + if (val & 0x04) + { + uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); + if (val & 0x80) + d ^= 0x8080; + gus->ram[gus_addr] = d & 0xff; + gus->ram[gus_addr +1] = (d >> 8) & 0xff; + } + else + { + if (val & 0x80) + d ^= 0x80; + gus->ram[gus->dmaaddr] = d; + } gus->dmaaddr++; - gus->dmaaddr&=0xFFFFF; + 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; + gus->irqnext = 1; } // exit(-1); } @@ -450,6 +507,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); }*/ gus->tctrl=val; gus->sb_ctrl = val; + gus_update_int_status(gus); break; case 0x46: /*Timer 1*/ gus->t1 = gus->t1l = val; @@ -600,7 +658,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); uint8_t readgus(uint16_t addr, void *p) { gus_t *gus = (gus_t *)p; - uint8_t val; + uint8_t val = 0xff; // /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus->global); switch (addr) { @@ -647,7 +705,7 @@ uint8_t readgus(uint16_t addr, void *p) // pclog("Read IRQ status - %02X\n",val); gus->rampirqs[gus->irqstatus2&0x1F]=0; gus->waveirqs[gus->irqstatus2&0x1F]=0; - pollgusirqs(gus); + gus_update_int_status(gus); return val; case 0x00: case 0x01: case 0x02: case 0x03: @@ -695,7 +753,7 @@ uint8_t readgus(uint16_t addr, void *p) val=gus->irqstatus2; gus->rampirqs[gus->irqstatus2&0x1F]=0; gus->waveirqs[gus->irqstatus2&0x1F]=0; - pollgusirqs(gus); + gus_update_int_status(gus); // pclog("Read IRQ status - %02X %i %i\n",val, gus->waveirqs[gus->irqstatus2&0x1F], gus->rampirqs[gus->irqstatus2&0x1F]); return val; @@ -798,7 +856,7 @@ void gus_poll_timer_1(void *p) { gus_t *gus = (gus_t *)p; - gus->timer_1 += (TIMER_USEC * 80); + timer_advance_u64(&gus->timer_1, (uint64_t)(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) { @@ -810,8 +868,6 @@ void gus_poll_timer_1(void *p) 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"); @@ -823,17 +879,16 @@ void gus_poll_timer_1(void *p) // pclog("Take IRQ\n"); gus->irqnext=0; gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); } gus_midi_update_int_status(gus); + gus_update_int_status(gus); } void gus_poll_timer_2(void *p) { gus_t *gus = (gus_t *)p; - gus->timer_2 += (TIMER_USEC * 320); + timer_advance_u64(&gus->timer_2, (uint64_t)(TIMER_USEC * 320)); // pclog("pollgus2 %i %i %i %i %02X\n", gustime, gus->t2on, gus->t2, gus->t2l, gus->tctrl); if (gus->t2on) { @@ -845,8 +900,6 @@ void gus_poll_timer_2(void *p) 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"); @@ -858,9 +911,8 @@ void gus_poll_timer_2(void *p) // pclog("Take IRQ\n"); gus->irqnext=0; gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); } + gus_update_int_status(gus); } static void gus_update(gus_t *gus) @@ -893,7 +945,7 @@ void gus_poll_wave(void *p) gus_update(gus); - gus->samp_timer += gus->samp_latch; + timer_advance_u64(&gus->samp_timer, gus->samp_latch); gus->out_l = gus->out_r = 0; @@ -1048,7 +1100,7 @@ void gus_poll_wave(void *p) } if (update_irqs) - pollgusirqs(gus); + gus_update_int_status(gus); } static void gus_get_buffer(int32_t *buffer, int len, void *p) @@ -1094,7 +1146,7 @@ void *gus_init() 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->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); gus->t1l = gus->t2l = 0xff; @@ -1102,9 +1154,9 @@ void *gus_init() 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); + timer_add(&gus->samp_timer, gus_poll_wave, gus, 1); + timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1); + timer_add(&gus->timer_2, gus_poll_timer_2, gus, 1); sound_add_handler(gus_get_buffer, gus); @@ -1124,9 +1176,19 @@ 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)); + gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); else - gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); +} + +static void gus_add_status_info(char *s, int max_len, void *p) +{ + gus_t *gus = (gus_t *)p; + char temps[256]; + + sprintf(temps, "GUS max voices : %i\nGUS playback frequency : %iHz\n\n", + gus->voices, gusfreqs[gus->voices-14]); + strncat(s, temps, max_len); } device_t gus_device = @@ -1138,5 +1200,5 @@ device_t gus_device = NULL, gus_speed_changed, NULL, - NULL + gus_add_status_info }; diff --git a/src/sound_mpu401_uart.c b/src/sound_mpu401_uart.c index b75cfa8..22cb638 100644 --- a/src/sound_mpu401_uart.c +++ b/src/sound_mpu401_uart.c @@ -1,5 +1,6 @@ #include "ibm.h" #include "io.h" +#include "pic.h" #include "plat-midi.h" #include "sound_mpu401_uart.h" @@ -9,6 +10,14 @@ enum STATUS_INPUT_NOT_READY = 0x80 }; +static void mpu401_uart_raise_irq(void *p) +{ + mpu401_uart_t *mpu = (mpu401_uart_t *)p; + + if (mpu->irq != -1) + picint(1 << mpu->irq); +} + static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) { mpu401_uart_t *mpu = (mpu401_uart_t *)p; @@ -18,15 +27,30 @@ static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) switch (val) { case 0xff: /*Reset*/ + // From Roland: "An ACK will not be sent back upon sending a SYSTEM RESET to leave the UART MODE ($3F)." + // But actual behaviour is weird. For example, the MPU401 port test in the AZT1605 drivers for Windows NT + // want this to return an Ack but the IRQ test in the same driver wants this to raise no interrupts! mpu->rx_data = 0xfe; /*Acknowledge*/ - mpu->status = 0; mpu->uart_mode = 0; + if (mpu->is_aztech) + mpu->status = STATUS_OUTPUT_NOT_READY; + else + { + mpu->status = 0; + mpu401_uart_raise_irq(p); + } break; case 0x3f: /*Enter UART mode*/ mpu->rx_data = 0xfe; /*Acknowledge*/ - mpu->status = 0; mpu->uart_mode = 1; + if (mpu->is_aztech) + { + mpu->status = STATUS_OUTPUT_NOT_READY; + mpu401_uart_raise_irq(p); + } + else + mpu->status = 0; break; } return; @@ -45,14 +69,31 @@ static uint8_t mpu401_uart_read(uint16_t addr, void *p) return mpu->status; /*Data*/ - mpu->status |= STATUS_INPUT_NOT_READY; + mpu->status = STATUS_INPUT_NOT_READY; return mpu->rx_data; } -void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr) +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq, int is_aztech) { mpu->status = STATUS_INPUT_NOT_READY; mpu->uart_mode = 0; + mpu->addr = addr; + mpu->irq = irq; + mpu->is_aztech = is_aztech; io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); } + +void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr) +{ + io_removehandler(mpu->addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); + mpu->addr = addr; + if (addr != 0) + io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); +} + +void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq) +{ + mpu->irq = irq; +} + diff --git a/src/sound_mpu401_uart.h b/src/sound_mpu401_uart.h index 91f4119..9634d58 100644 --- a/src/sound_mpu401_uart.h +++ b/src/sound_mpu401_uart.h @@ -1,9 +1,20 @@ +#ifndef SOUND_MPU401_UART +#define SOUND_MPU401_UART + typedef struct mpu401_uart_t { uint8_t status; uint8_t rx_data; - int uart_mode; + int uart_mode; + uint16_t addr; + int irq; + + int is_aztech; } mpu401_uart_t; -void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr); +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr, int irq, int is_aztech); +void mpu401_uart_update_addr(mpu401_uart_t *mpu, uint16_t addr); +void mpu401_uart_update_irq(mpu401_uart_t *mpu, int irq); + +#endif /* SOUND_MPU401_UART */ diff --git a/src/sound_opl.c b/src/sound_opl.c index 0ec7643..368a1d8 100644 --- a/src/sound_opl.c +++ b/src/sound_opl.c @@ -5,6 +5,7 @@ #include "sound.h" #include "sound_opl.h" #include "sound_dbopl.h" +#include "x86.h" /*Interfaces between PCem and the actual OPL emulator*/ @@ -83,8 +84,8 @@ void opl2_update2(opl_t *opl) 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); + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); } } } @@ -96,8 +97,8 @@ void opl3_update2(opl_t *opl) 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); + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); } } } @@ -106,71 +107,62 @@ 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; + if (period) + timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[0][timer]); } 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; + if (period) + timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[1][timer]); } 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; + if (period) + timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20); + else + timer_disable(&opl->timers[0][timer]); } 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); + opl_init(ym3812_timer_set_0, opl, 0, 0, 0); + opl_init(ym3812_timer_set_1, opl, 1, 0, 0); + timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); + timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); + timer_add(&opl->timers[1][0], opl_timer_callback10, (void *)opl, 0); + timer_add(&opl->timers[1][1], opl_timer_callback11, (void *)opl, 0); } -void opl3_init(opl_t *opl) +void opl3_init(opl_t *opl, int opl_emu) { - 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); + opl_init(ymf262_timer_set, opl, 0, 1, opl_emu); + timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0); + timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0); } diff --git a/src/sound_opl.h b/src/sound_opl.h index 047808e..06f5cd7 100644 --- a/src/sound_opl.h +++ b/src/sound_opl.h @@ -1,13 +1,14 @@ +#include "sound.h" + typedef struct opl_t { int chip_nr[2]; - int timers[2][2]; - int timers_enable[2][2]; + pc_timer_t timers[2][2]; int16_t filtbuf[2]; - int16_t buffer[SOUNDBUFLEN * 2]; + int16_t buffer[MAXSOUNDBUFLEN * 2]; int pos; } opl_t; @@ -24,7 +25,10 @@ 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 opl3_init(opl_t *opl, int opl_emu); void opl2_update2(opl_t *opl); void opl3_update2(opl_t *opl); + +#define OPL_DBOPL 0 +#define OPL_NUKED 1 diff --git a/src/sound_pas16.c b/src/sound_pas16.c index 2e6f4be..e88ec2e 100644 --- a/src/sound_pas16.c +++ b/src/sound_pas16.c @@ -12,6 +12,7 @@ #include "sound_pas16.h" #include "sound_sb_dsp.h" #include "timer.h" +#include "x86.h" /* Original PAS uses 2 x OPL2 @@ -118,7 +119,8 @@ typedef struct pas16_t struct { uint32_t l[3]; - int c[3]; + int c[3]; + pc_timer_t timer[3]; uint8_t m[3]; uint8_t ctrl, ctrls[2]; int wp, rm[3], wm[3]; @@ -132,7 +134,7 @@ typedef struct pas16_t opl_t opl; sb_dsp_t dsp; - int16_t pcm_buffer[2][SOUNDBUFLEN]; + int16_t pcm_buffer[2][MAXSOUNDBUFLEN]; int pos; } pas16_t; @@ -398,7 +400,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) { if (!(val & 0x20)) { - if (val & 2) pas16->pit.rl[0] = pas16->pit.c[0] / (PITCONST * (1 << TIMER_SHIFT)); + if (val & 2) pas16->pit.rl[0] = timer_get_remaining_u64(&pit.timer[0]) / PITCONST;; if (val & 4) pas16->pit.rl[1] = pas16->pit.c[1]; if (val & 8) pas16->pit.rl[2] = pas16->pit.c[2]; } @@ -413,11 +415,14 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) } 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; + if (!t) + pas16->pit.rl[t] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; + else + { + pas16->pit.rl[t] = pas16->pit.c[t]; + 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; @@ -431,9 +436,10 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) 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)); + if (!t) + pas16->pit.rl[t] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; + else + pas16->pit.rl[t] = pas16->pit.c[t]; } pas16->pit.rereadlatch[t] = 1; } @@ -449,7 +455,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.thit[t] = 0; pas16->pit.c[t] = pas16->pit.l[t]; if (!t) - pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); pas16->pit.enable[t] = 1; break; case 2: @@ -457,7 +463,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.thit[t] = 0; pas16->pit.c[t] = pas16->pit.l[t]; if (!t) - pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); pas16->pit.enable[t] = 1; break; case 0: @@ -465,7 +471,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.l[t] |= (val << 8); pas16->pit.c[t] = pas16->pit.l[t]; if (!t) - pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); pas16->pit.thit[t] = 0; pas16->pit.wm[t] = 3; pas16->pit.enable[t] = 1; @@ -481,7 +487,7 @@ static void pas16_pit_out(uint16_t port, uint8_t val, void *p) pas16->pit.l[t] |= 0x10000; pas16->pit.c[t] = pas16->pit.l[t]; if (!t) - pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + timer_set_delay_u64(&pas16->pit.timer[t], pas16->pit.c[t] * PITCONST); } break; } @@ -501,8 +507,8 @@ static uint8_t pas16_pit_in(uint16_t port, void *p) 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] = timer_get_remaining_u64(&pit.timer[t]) / PITCONST; + if ((timer_get_remaining_u64(&pit.timer[t]) / PITCONST) > 65536) pas16->pit.rl[t] = 0xFFFF; } else @@ -557,13 +563,12 @@ static void pas16_pcm_poll(void *p) if (pas16->pit.m[0] & 2) { if (pas16->pit.l[0]) - pas16->pit.c[0] += (pas16->pit.l[0] * PITCONST * (1 << TIMER_SHIFT)); + timer_advance_u64(&pas16->pit.timer[0], pas16->pit.l[0] * PITCONST); else - pas16->pit.c[0] += (0x10000 * PITCONST * (1 << TIMER_SHIFT)); + timer_advance_u64(&pas16->pit.timer[0], 0x10000 * PITCONST); } else { - pas16->pit.c[0] = -1; pas16->pit.enable[0] = 0; } // if (pas16->pcm_ctrl & PAS16_PCM_ENA) @@ -731,12 +736,12 @@ 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); + opl3_init(&pas16->opl, 0); + sb_dsp_init(&pas16->dsp, SB2, SB_SUBTYPE_DEFAULT, pas16); 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); + timer_add(&pas16->pit.timer[0], pas16_pcm_poll, pas16, 0); sound_add_handler(pas16_get_buffer, pas16); diff --git a/src/sound_ps1.c b/src/sound_ps1.c index a7de420..27c5767 100644 --- a/src/sound_ps1.c +++ b/src/sound_ps1.c @@ -13,7 +13,8 @@ typedef struct ps1_audio_t uint8_t status, ctrl; - int timer_latch, timer_count, timer_enable; + uint64_t timer_latch; + pc_timer_t timer; uint8_t fifo[2048]; int fifo_read_idx, fifo_write_idx; @@ -21,7 +22,7 @@ typedef struct ps1_audio_t uint8_t dac_val; - int16_t buffer[SOUNDBUFLEN]; + int16_t buffer[MAXSOUNDBUFLEN]; int pos; } ps1_audio_t; @@ -89,8 +90,10 @@ static void ps1_audio_write(uint16_t port, uint8_t val, void *p) break; case 3: /*Timer reload value*/ ps1->timer_latch = val; - ps1->timer_count = (0xff-val) * TIMER_USEC; - ps1->timer_enable = (val != 0); + if (val) + timer_set_delay_u64(&ps1->timer, (0xff-val) * TIMER_USEC); + else + timer_disable(&ps1->timer); break; case 4: /*Almost empty*/ ps1->fifo_threshold = val * 4; @@ -124,7 +127,7 @@ static void ps1_audio_callback(void *p) ps1->status |= 0x10; /*ADC data ready*/ ps1_update_irq_status(ps1); - ps1->timer_count += ps1->timer_latch * TIMER_USEC; + timer_advance_u64(&ps1->timer, ps1->timer_latch * TIMER_USEC); } static void ps1_audio_get_buffer(int32_t *buffer, int len, void *p) @@ -149,7 +152,7 @@ static void *ps1_audio_init() 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); + timer_add(&ps1->timer, ps1_audio_callback, ps1, 0); sound_add_handler(ps1_audio_get_buffer, ps1); return ps1; diff --git a/src/sound_pssj.c b/src/sound_pssj.c index 3ffaaae..4169c4a 100644 --- a/src/sound_pssj.c +++ b/src/sound_pssj.c @@ -21,13 +21,13 @@ typedef struct pssj_t int amplitude; int irq; - int timer_count; + pc_timer_t timer; int enable; int wave_pos; int pulse_width; - int16_t buffer[SOUNDBUFLEN]; + int16_t buffer[MAXSOUNDBUFLEN]; int pos; } pssj_t; @@ -46,7 +46,13 @@ static void pssj_write(uint16_t port, uint8_t val, void *p) { case 0: pssj->ctrl = val; + + if (!pssj->enable && ((val & 4) && (pssj->ctrl & 3))) + timer_set_delay_u64(&pssj->timer, (TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400))); pssj->enable = (val & 4) && (pssj->ctrl & 3); + if (!pssj->enable) + timer_disable(&pssj->timer); + sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); if (!(val & 8)) pssj->irq = 0; @@ -166,7 +172,7 @@ static void pssj_callback(void *p) pssj->wave_pos = (pssj->wave_pos + 1) & 31; } - pssj->timer_count += (int)(TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400)); + timer_advance_u64(&pssj->timer, (TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400))); } static void pssj_get_buffer(int32_t *buffer, int len, void *p) @@ -190,7 +196,7 @@ void *pssj_init() 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); + timer_add(&pssj->timer, pssj_callback, pssj, 0); sound_add_handler(pssj_get_buffer, pssj); return pssj; diff --git a/src/sound_sb.c b/src/sound_sb.c index d4212ca..08830d0 100644 --- a/src/sound_sb.c +++ b/src/sound_sb.c @@ -14,44 +14,41 @@ #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; +//#define SB_DSP_RECORD_DEBUG - int index; - uint8_t regs[256]; -} sb_mixer_t; +#ifdef SB_DSP_RECORD_DEBUG +FILE* soundfsb = 0/*NULL*/; +FILE* soundfsbin = 0/*NULL*/; +#endif -typedef struct sb_t -{ - opl_t opl; - sb_dsp_t dsp; - sb_mixer_t mixer; - mpu401_uart_t mpu; - emu8k_t emu8k; - - int pos; - - uint8_t pos_regs[8]; -} 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 +/* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps. + Note that for positive dB values, this is not amplitude, it is amplitude-1. */ +const float sb_bass_treble_4bits[]= { + 0.199526231, 0.25, 0.316227766, 0.398107170, 0.5, 0.63095734, 0.794328234, 1, + 0, 0.25892541, 0.584893192, 1, 1.511886431, 2.16227766, 3, 4.011872336 }; -static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) +/* Attenuation tables for the mixer. Max volume = 32767 in order to give 6dB of + * headroom and avoid integer overflow */ +const int32_t sb_att_2dbstep_5bits[]= +{ + 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, + 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, + 16422,20674,26027,32767 +}; +const int32_t sb_att_4dbstep_3bits[]= +{ + 164,2067,3276,5193,8230,13045,20675,32767 +}; +const int32_t sb_att_7dbstep_2bits[]= +{ + 164,6537,14637,32767 +}; + +/* sb 1, 1.5, 2, 2 mvc do not have a mixer, so signal is hardwired */ +static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; int c; @@ -59,39 +56,13 @@ static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) 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; + int32_t out; + out = ((sb->opl.buffer[c] * 51000) >> 16); + //TODO: Recording: Mic and line In with AGC + out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * 65536) / 3) >> 16; + + buffer[c] += out; + buffer[c + 1] += out; } sb->pos = 0; @@ -99,48 +70,71 @@ static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) sb->dsp.pos = 0; } -static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p) +static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; int c; - opl3_update2(&sb->opl); + opl2_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int32_t out; + + out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * 51000) >> 15); + /* TODO: Recording : I assume it has direct mic and line in like sb2 */ + /* It is unclear from the docs if it has a filter, but it probably does */ + out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice) / 3) >> 15; + + out = (out * mixer->master) >> 15; + + buffer[c] += out; + buffer[c + 1] += out; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} + +void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + int c; + + if (sb->dsp.sb_type == SBPRO) + opl2_update2(&sb->opl); + else + opl3_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 = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + + /*TODO: Implement the stereo switch on the mixer instead of on the dsp? */ + if (mixer->output_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; + out_l += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 15; + out_r += (int32_t)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 15; } 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 += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 15; } + //TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. - out_l = (out_l * mixer->master_l) >> 16; - out_r = (out_r * mixer->master_r) >> 16; + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; - 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; } @@ -148,200 +142,621 @@ static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p) sb->pos = 0; sb->opl.pos = 0; sb->dsp.pos = 0; - sb->emu8k.pos = 0; } +static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + int c; + + opl3_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + const int dsp_rec_pos = sb->dsp.record_pos_write; + for (c = 0; c < len * 2; c += 2) + { + int32_t out_l, out_r, in_l, in_r; + + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + + /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ + in_l = (mixer->input_selector_left&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_left&INPUT_MIDI_R) ? out_r : 0; + in_r = (mixer->input_selector_right&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_right&INPUT_MIDI_R) ? out_r : 0; + + out_l += ((int32_t)(low_fir_sb16(0, (float)sb->dsp.buffer[c]) * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(low_fir_sb16(1, (float)sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3) >> 15; + + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ + if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); + if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); + if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); + if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); + if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); + if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); + if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); + if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); + } + if (sb->dsp.sb_enable_i) + { + int c_record = dsp_rec_pos; + c_record +=(((c/2) * sb->dsp.sb_freq) / 48000)*2; + in_l <<= mixer->input_gain_L; + in_r <<= mixer->input_gain_R; + // Clip signal + if (in_l < -32768) + in_l = -32768; + else if (in_l > 32767) + in_l = 32767; + + if (in_r < -32768) + in_r = -32768; + else if (in_r > 32767) + in_r = 32767; + sb->dsp.record_buffer[c_record&0xFFFF] = in_l; + sb->dsp.record_buffer[(c_record+1)&0xFFFF] = in_r; + } + + buffer[c] += (out_l << mixer->output_gain_L); + buffer[c + 1] += (out_r << mixer->output_gain_R); + } + sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; + sb->dsp.record_pos_write&=0xFFFF; + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} +#ifdef SB_DSP_RECORD_DEBUG +int old_dsp_rec_pos=0; +int buf_written=0; +int last_crecord=0; +#endif 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; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; int c; opl3_update2(&sb->opl); - sb_dsp_update(&sb->dsp); emu8k_update(&sb->emu8k); + sb_dsp_update(&sb->dsp); + const int dsp_rec_pos = sb->dsp.record_pos_write; for (c = 0; c < len * 2; c += 2) { + int32_t out_l, out_r, in_l, in_r; 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->opl.buffer[c] * mixer->fm_l) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 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 += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 15); + out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_r) >> 15); - out_l = (out_l * mixer->master_l) >> 16; - out_r = (out_r * mixer->master_r) >> 16; + /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ + in_l = (mixer->input_selector_left&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_left&INPUT_MIDI_R) ? out_r : 0; + in_r = (mixer->input_selector_right&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_right&INPUT_MIDI_R) ? out_r : 0; + + out_l += ((int32_t)(low_fir_sb16(0, (float)sb->dsp.buffer[c]) * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(low_fir_sb16(1, (float)sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3) >> 15; + + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; 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; + /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ + if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); + if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); + if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); + if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); + if (mixer->bass_l<8) out_l = (int32_t)(out_l *sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); + if (mixer->bass_r<8) out_r = (int32_t)(out_r *sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); + if (mixer->treble_l<8) out_l = (int32_t)(out_l *sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); + if (mixer->treble_r<8) out_r = (int32_t)(out_r *sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); } - - buffer[c] += out_l; - buffer[c + 1] += out_r; - } + if (sb->dsp.sb_enable_i) + { +// in_l += (mixer->input_selector_left&INPUT_CD_L) ? audio_cd_buffer[cd_read_pos+c_emu8k] : 0 + (mixer->input_selector_left&INPUT_CD_R) ? audio_cd_buffer[cd_read_pos+c_emu8k+1] : 0; +// in_r += (mixer->input_selector_right&INPUT_CD_L) ? audio_cd_buffer[cd_read_pos+c_emu8k]: 0 + (mixer->input_selector_right&INPUT_CD_R) ? audio_cd_buffer[cd_read_pos+c_emu8k+1] : 0; + int c_record = dsp_rec_pos; + c_record +=(((c/2) * sb->dsp.sb_freq) / 48000)*2; + #ifdef SB_DSP_RECORD_DEBUG + if (c_record > 0xFFFF && !buf_written) + { + if (!soundfsb) soundfsb=fopen("sound_sb.pcm","wb"); + fwrite(sb->dsp.record_buffer,2,0x10000,soundfsb); + old_dsp_rec_pos = dsp_rec_pos; + buf_written=1; + } + #endif + in_l <<= mixer->input_gain_L; + in_r <<= mixer->input_gain_R; + // Clip signal + if (in_l < -32768) + in_l = -32768; + else if (in_l > 32767) + in_l = 32767; + + if (in_r < -32768) + in_r = -32768; + else if (in_r > 32767) + in_r = 32767; + sb->dsp.record_buffer[c_record&0xFFFF] = in_l; + sb->dsp.record_buffer[(c_record+1)&0xFFFF] = in_r; + #ifdef SB_DSP_RECORD_DEBUG + if (c_record != last_crecord) + { + if (!soundfsbin) soundfsbin=fopen("sound_sb_in.pcm","wb"); + fwrite(&sb->dsp.record_buffer[c_record&0xFFFF],2,2,soundfsbin); + last_crecord=c_record; + } + #endif + } + + buffer[c] += (out_l << mixer->output_gain_L); + buffer[c + 1] += (out_r << mixer->output_gain_R); + } + #ifdef SB_DSP_RECORD_DEBUG + if (old_dsp_rec_pos > dsp_rec_pos) + { + buf_written=0; + old_dsp_rec_pos=dsp_rec_pos; + } + #endif + + sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; + sb->dsp.record_pos_write&=0xFFFF; 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) + +void sb_ct1335_mixer_write(uint16_t addr, uint8_t val, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; 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; + mixer->regs[0x01] = val; + } else { - mixer->regs[mixer->index] = val; - switch (mixer->index) + if (mixer->index == 0) { - 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; + /* Reset */ + mixer->regs[0x02] = 4 << 1; + mixer->regs[0x06] = 4 << 1; + mixer->regs[0x08] = 0 << 1; + /* changed default from -46dB to 0dB*/ + mixer->regs[0x0A] = 3 << 1; } - 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); + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + case 0x00: case 0x02: case 0x06: case 0x08: case 0x0A: + break; + + default: + pclog("sb_ct1335: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + } + mixer->master = sb_att_4dbstep_3bits[(mixer->regs[0x02] >> 1)&0x7]; + mixer->fm = sb_att_4dbstep_3bits[(mixer->regs[0x06] >> 1)&0x7]; + mixer->cd = sb_att_4dbstep_3bits[(mixer->regs[0x08] >> 1)&0x7]; + mixer->voice = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; + + sound_set_cd_volume(((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535, + ((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535); } } -uint8_t sb_16_mixer_read(uint16_t addr, void *p) +uint8_t sb_ct1335_mixer_read(uint16_t addr, void *p) { sb_t *sb = (sb_t *)p; - sb_mixer_t *mixer = &sb->mixer; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; 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*/ - } + case 0x00: case 0x02: case 0x06: case 0x08: case 0x0A: + return mixer->regs[mixer->index]; + default: + pclog("sb_ct1335: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); 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]; + + return 0xff; } -void sb_mixer_init(sb_mixer_t *mixer) +void sb_ct1335_mixer_reset(sb_t* sb) { - 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; + sb_ct1335_mixer_write(0x254,0,sb); + sb_ct1335_mixer_write(0x255,0,sb); } +void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + if (!(addr & 1)) + { + mixer->index = val; + mixer->regs[0x01] = val; + } + else + { + if (mixer->index == 0) + { + /* Reset */ + mixer->regs[0x0A] = 0 << 1; + mixer->regs[0x0C] = (0 << 5) | (0 << 3) | (0 << 1); + mixer->regs[0x0E] = (0 << 5) | (0 << 1); + /* changed default from -11dB to 0dB */ + mixer->regs[0x04] = (7 << 5) | (7 << 1); + mixer->regs[0x22] = (7 << 5) | (7 << 1); + mixer->regs[0x26] = (7 << 5) | (7 << 1); + mixer->regs[0x28] = (0 << 5) | (0 << 1); + mixer->regs[0x2E] = (0 << 5) | (0 << 1); + sb_dsp_set_stereo(&sb->dsp, mixer->regs[0x0E] & 2); + } + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ + case 0x02: case 0x06: + mixer->regs[mixer->index+0x20]=((val&0xE) << 4) | (val&0xE); + break; + + case 0x22: case 0x26: + mixer->regs[mixer->index-0x20]=(val&0xE); + break; + + /* More compatibility: SoundBlaster Pro selects register 020h for 030h, 022h for 032h, 026h for 036h,028h for 038h. */ + case 0x30: case 0x32: case 0x36: case 0x38: + mixer->regs[mixer->index-0x10]=(val&0xEE); + break; + + case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: + case 0x28: case 0x2e: + break; + + + default: + pclog("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + } + + mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5)&0x7]; + mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1)&0x7]; + mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5)&0x7]; + mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1)&0x7]; + mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5)&0x7]; + mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1)&0x7]; + mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5)&0x7]; + mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1)&0x7]; + mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2E] >> 5)&0x7]; + mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2E] >> 1)&0x7]; + + mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; + + mixer->output_filter = !(mixer->regs[0xE] & 0x20); + mixer->input_filter = !(mixer->regs[0xC] & 0x20); + mixer->in_filter_freq = ((mixer->regs[0xC] & 0x8) == 0) ? 3200 : 8800; + mixer->stereo = mixer->regs[0xE] & 2; + if (mixer->index == 0xE) + sb_dsp_set_stereo(&sb->dsp, val & 2); + + switch ((mixer->regs[0xc]&6)) + { + case 2: + mixer->input_selector = INPUT_CD_L|INPUT_CD_R; + break; + case 6: + mixer->input_selector = INPUT_LINE_L|INPUT_LINE_R; + break; + default: + mixer->input_selector = INPUT_MIC; + break; + } + + /* TODO: pcspeaker volume? Or is it not worth? */ + 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); + } +} + +uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) + { + case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: + case 0x22: case 0x26: case 0x28: case 0x2e: case 0x02: case 0x06: + case 0x30: case 0x32: case 0x36: case 0x38: + return mixer->regs[mixer->index]; + + default: + pclog("sb_ct1345: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + return 0xff; +} +void sb_ct1345_mixer_reset(sb_t* sb) +{ + sb_ct1345_mixer_write(4,0,sb); + sb_ct1345_mixer_write(5,0,sb); +} + +void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + if (!(addr & 1)) + { + mixer->index = val; + } + else + { + // TODO: and this? 001h: + /*DESCRIPTION + Contains previously selected register value. Mixer Data Register value + NOTES + * SoundBlaster 16 sets bit 7 if previous mixer index invalid. + * Status bytes initially 080h on startup for all but level bytes (SB16) + */ + + if (mixer->index == 0) + { + /* Reset */ + /* Changed defaults from -14dB to 0dB*/ + mixer->regs[0x30]=31 << 3; + mixer->regs[0x31]=31 << 3; + mixer->regs[0x32]=31 << 3; + mixer->regs[0x33]=31 << 3; + mixer->regs[0x34]=31 << 3; + mixer->regs[0x35]=31 << 3; + mixer->regs[0x36]=0 << 3; + mixer->regs[0x37]=0 << 3; + mixer->regs[0x38]=0 << 3; + mixer->regs[0x39]=0 << 3; + + mixer->regs[0x3A]=0 << 3; + mixer->regs[0x3B]=0 << 6; + mixer->regs[0x3C] = OUTPUT_MIC|OUTPUT_CD_R|OUTPUT_CD_L|OUTPUT_LINE_R|OUTPUT_LINE_L; + mixer->regs[0x3D] = INPUT_MIC|INPUT_CD_L|INPUT_LINE_L|INPUT_MIDI_L; + mixer->regs[0x3E] = INPUT_MIC|INPUT_CD_R|INPUT_LINE_R|INPUT_MIDI_R; + + mixer->regs[0x3F] = mixer->regs[0x40] = 0 << 6; + mixer->regs[0x41] = mixer->regs[0x42] = 0 << 6; + + mixer->regs[0x44] = mixer->regs[0x45] = 8 << 4; + mixer->regs[0x46] = mixer->regs[0x47] = 8 << 4; + + mixer->regs[0x43] = 0; + } + else + { + mixer->regs[mixer->index] = val; + } + switch (mixer->index) + { + /* SBPro compatibility. Copy values to sb16 registers. */ + case 0x22: + mixer->regs[0x30] = (mixer->regs[0x22] & 0xF0) | 0x8; + mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) << 4) | 0x8; + break; + case 0x04: + mixer->regs[0x32] = (mixer->regs[0x04] & 0xF0) | 0x8; + mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) << 4) | 0x8; + break; + case 0x26: + mixer->regs[0x34] = (mixer->regs[0x26] & 0xF0) | 0x8; + mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) << 4) | 0x8; + break; + case 0x28: + mixer->regs[0x36] = (mixer->regs[0x28] & 0xF0) | 0x8; + mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) << 4) | 0x8; + break; + case 0x2E: + mixer->regs[0x38] = (mixer->regs[0x2E] & 0xF0) | 0x8; + mixer->regs[0x39] = ((mixer->regs[0x2E] & 0xf) << 4) | 0x8; + break; + case 0x0A: + mixer->regs[0x3A] = (mixer->regs[0x0A]*3)+10; + break; + + /* + (DSP 4.xx feature) The Interrupt Setup register, addressed as register 80h on the Mixer register map, is used to configure or determine the Interrupt request line. The DMA setup register, addressed as register 81h on the Mixer register map, is used to configure or determine the DMA channels. + + Note: Registers 80h and 81h are Read-only for PnP boards. + */ + case 0x80: + if (val & 1) sb_dsp_setirq(&sb->dsp,2); + if (val & 2) sb_dsp_setirq(&sb->dsp,5); + if (val & 4) sb_dsp_setirq(&sb->dsp,7); + if (val & 8) sb_dsp_setirq(&sb->dsp,10); + break; + + case 0x81: + /* The documentation is confusing. sounds as if multple dma8 channels could be set. */ + if (val & 1) sb_dsp_setdma8(&sb->dsp,0); + if (val & 2) sb_dsp_setdma8(&sb->dsp,1); + if (val & 8) sb_dsp_setdma8(&sb->dsp,3); + if (val & 0x20) sb_dsp_setdma16(&sb->dsp,5); + if (val & 0x40) sb_dsp_setdma16(&sb->dsp,6); + if (val & 0x80) sb_dsp_setdma16(&sb->dsp,7); + break; + } + + mixer->output_selector = mixer->regs[0x3C]; + mixer->input_selector_left = mixer->regs[0x3D]; + mixer->input_selector_right = mixer->regs[0x3E]; + + mixer->master_l = sb_att_2dbstep_5bits[mixer->regs[0x30] >> 3]; + mixer->master_r = sb_att_2dbstep_5bits[mixer->regs[0x31] >> 3]; + mixer->voice_l = sb_att_2dbstep_5bits[mixer->regs[0x32] >> 3]; + mixer->voice_r = sb_att_2dbstep_5bits[mixer->regs[0x33] >> 3]; + mixer->fm_l = sb_att_2dbstep_5bits[mixer->regs[0x34] >> 3]; + mixer->fm_r = sb_att_2dbstep_5bits[mixer->regs[0x35] >> 3]; + mixer->cd_l = (mixer->output_selector&OUTPUT_CD_L) ? sb_att_2dbstep_5bits[mixer->regs[0x36] >> 3] : 0; + mixer->cd_r = (mixer->output_selector&OUTPUT_CD_R) ? sb_att_2dbstep_5bits[mixer->regs[0x37] >> 3] : 0; + mixer->line_l = (mixer->output_selector&OUTPUT_LINE_L) ? sb_att_2dbstep_5bits[mixer->regs[0x38] >> 3] : 0; + mixer->line_r = (mixer->output_selector&OUTPUT_LINE_R) ? sb_att_2dbstep_5bits[mixer->regs[0x39] >> 3] : 0; + + mixer->mic = sb_att_2dbstep_5bits[mixer->regs[0x3A] >> 3]; + mixer->speaker = sb_att_2dbstep_5bits[mixer->regs[0x3B]*3 + 22]; + + + mixer->input_gain_L = (mixer->regs[0x3F] >> 6); + mixer->input_gain_R = (mixer->regs[0x40] >> 6); + mixer->output_gain_L = (mixer->regs[0x41] >> 6); + mixer->output_gain_R = (mixer->regs[0x42] >> 6); + + 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; + + /*TODO: pcspeaker volume, with "output_selector" check? or better not? */ + 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("sb_ct1745: Received register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + } +} + +uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + if (!(addr & 1)) + return mixer->index; + +// pclog("sb_ct1745: received register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + + if (mixer->index>=0x30 && mixer->index<=0x47) + { + return mixer->regs[mixer->index]; + } + switch (mixer->index) + { + case 0x00: + return mixer->regs[mixer->index]; + + /*SB Pro compatibility*/ + case 0x04: + return ((mixer->regs[0x33] >> 4) & 0x0f) | (mixer->regs[0x32] & 0xf0); + case 0x0a: + return (mixer->regs[0x3a] - 10) / 3; + case 0x22: + return ((mixer->regs[0x31] >> 4) & 0x0f) | (mixer->regs[0x30] & 0xf0); + case 0x26: + return ((mixer->regs[0x35] >> 4) & 0x0f) | (mixer->regs[0x34] & 0xf0); + case 0x28: + return ((mixer->regs[0x37] >> 4) & 0x0f) | (mixer->regs[0x36] & 0xf0); + case 0x2e: + return ((mixer->regs[0x39] >> 4) & 0x0f) | (mixer->regs[0x38] & 0xf0); + + case 0x48: + // Undocumented. The Creative Windows Mixer calls this after calling 3C (input selector). even when writing. + // Also, the version I have (5.17) does not use the MIDI.L/R input selectors. it uses the volume to mute (Affecting the output, obviously) + return mixer->regs[mixer->index]; + + case 0x80: + /*TODO: Unaffected by mixer reset or soft reboot. + * Enabling multiple bits enables multiple IRQs. + */ + + switch (sb->dsp.sb_irqnum) + { + case 2: return 1; + case 5: return 2; + case 7: return 4; + case 10: return 8; + } + break; + + case 0x81: + { + /* TODO: Unaffected by mixer reset or soft reboot. + * Enabling multiple 8 or 16-bit DMA bits enables multiple DMA channels. + * Disabling all 8-bit DMA channel bits disables 8-bit DMA requests, + including translated 16-bit DMA requests. + * Disabling all 16-bit DMA channel bits enables translation of 16-bit DMA + requests to 8-bit ones, using the selected 8-bit DMA channel.*/ + + uint8_t result=0; + switch (sb->dsp.sb_8_dmanum) + { + case 0: result |= 1; break; + case 1: result |= 2; break; + case 3: result |= 8; break; + } + switch (sb->dsp.sb_16_dmanum) + { + case 5: result |= 0x20; break; + case 6: result |= 0x40; break; + case 7: result |= 0x80; break; + } + return result; + } + + /* The Interrupt status register, addressed as register 82h on the Mixer register map, + is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, + in which case it should chain to the previous routine. + */ + case 0x82: + /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ + /* 0x02000 DSP v4.04, 0x4000 DSP v4.05 0x8000 DSP v4.12. I haven't seen this making any difference, but I'm keeping it for now. */ + return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | 0x4000; + + /* TODO: creative drivers read and write on 0xFE and 0xFF. not sure what they are supposed to be. */ + + + default: + pclog("sb_ct1745: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + return 0xff; +} + +void sb_ct1745_mixer_reset(sb_t* sb) +{ + sb_ct1745_mixer_write(4,0,sb); + sb_ct1745_mixer_write(5,0,sb); +} + + static uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x270}; uint8_t sb_mcv_read(int port, void *p) @@ -366,6 +781,7 @@ void sb_mcv_write(int port, uint8_t val, void *p) addr = sb_mcv_addr[sb->pos_regs[4] & 7]; io_removehandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, 0); sb->pos_regs[port & 7] = val; @@ -376,6 +792,7 @@ void sb_mcv_write(int port, uint8_t val, void *p) 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); + /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, addr); } } @@ -405,7 +822,8 @@ void sb_pro_mcv_write(int port, uint8_t val, void *p) io_removehandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_removehandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - io_removehandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + io_removehandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, 0); sb->pos_regs[port & 7] = val; @@ -417,158 +835,200 @@ void sb_pro_mcv_write(int port, uint8_t val, void *p) 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, 0x0004, 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); - + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ sb_dsp_setaddr(&sb->dsp, addr); } sb_dsp_setirq(&sb->dsp, sb_pro_mcv_irqs[(sb->pos_regs[5] >> 4) & 3]); sb_dsp_setdma8(&sb->dsp, sb->pos_regs[4] & 3); } - + void *sb_1_init() { + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ 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_init(&sb->dsp, SB1, SB_SUBTYPE_DEFAULT, sb); 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); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ 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); + sound_add_handler(sb_get_buffer_sb2, sb); return sb; } void *sb_15_init() { + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ 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_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); 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); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ 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); + sound_add_handler(sb_get_buffer_sb2, sb); return sb; } void *sb_mcv_init() { + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ sb_t *sb = malloc(sizeof(sb_t)); memset(sb, 0, sizeof(sb_t)); opl2_init(&sb->opl); - sb_dsp_init(&sb->dsp, SB15); + sb_dsp_init(&sb->dsp, SB15, SB_SUBTYPE_DEFAULT, sb); sb_dsp_setaddr(&sb->dsp, 0);//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); - sound_add_handler(sb_get_buffer_opl2, sb); - mca_add(sb_mcv_read, sb_mcv_write, sb); + sound_add_handler(sb_get_buffer_sb2, sb); + /* I/O handlers activated in sb_mcv_write */ + mca_add(sb_mcv_read, sb_mcv_write, NULL, sb); sb->pos_regs[0] = 0x84; sb->pos_regs[1] = 0x50; return sb; } void *sb_2_init() { + /*sb2 port mappings. 220h or 240h. + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip + "CD version" also uses 250h or 260h for + 2x0 to 2x3 -> CDROM interface + 2x4 to 2x5 -> Mixer interface*/ + /*My SB 2.0 mirrors the OPL2 at ports 2x0/2x1. Presumably this mirror is + disabled when the CMS chips are present. + This mirror may also exist on SB 1.5 & MCV, however I am unable to + test this. It shouldn't exist on SB 1.0 as the CMS chips are always + present there. + Syndicate requires this mirror for music to play.*/ 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_init(&sb->dsp, SB2, SB_SUBTYPE_DEFAULT, sb); 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); + sb_ct1335_mixer_reset(sb); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ + if (!GAMEBLASTER) + io_sethandler(addr, 0x0002, opl2_read, NULL, NULL, opl2_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); - sound_add_handler(sb_get_buffer_opl2, sb); + + int mixer_addr = device_get_config_int("mixaddr"); + if (mixer_addr > 0) + { + io_sethandler(mixer_addr+4, 0x0002, sb_ct1335_mixer_read, NULL, NULL, sb_ct1335_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sb2_mixer, sb); + } + else + sound_add_handler(sb_get_buffer_sb2, sb); + return sb; } void *sb_pro_v1_init() { + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip, Left and Right (9*2 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface.*/ 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_init(&sb->dsp, SBPRO, SB_SUBTYPE_DEFAULT, sb); 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); + sb_ct1345_mixer_reset(sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ 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; + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sbpro, sb); return sb; } void *sb_pro_v2_init() { + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface.*/ 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); + uint16_t addr = device_get_config_int("addr"); + sb->opl_emu = device_get_config_int("opl_emu"); + opl3_init(&sb->opl, sb->opl_emu); + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); 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); + sb_ct1345_mixer_reset(sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ 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, 0x0004, 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; + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sbpro, sb); return sb; } void *sb_pro_mcv_init() { + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip, Left and Right (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices)*/ 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(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); - sound_add_handler(sb_get_buffer_opl3, sb); + sb->opl_emu = device_get_config_int("opl_emu"); + opl3_init(&sb->opl, sb->opl_emu); + sb_dsp_init(&sb->dsp, SBPRO2, SB_SUBTYPE_DEFAULT, sb); + sb_ct1345_mixer_reset(sb); + /* I/O handlers activated in sb_mcv_write */ + sound_add_handler(sb_get_buffer_sbpro, sb); - sb->mixer.regs[0x22] = 0xff; - sb->mixer.regs[0x04] = 0xff; - sb->mixer.regs[0x26] = 0xff; - sb->mixer.regs[0xe] = 0; - - mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb); + /* I/O handlers activated in sb_pro_mcv_write */ + mca_add(sb_pro_mcv_read, sb_pro_mcv_write, NULL, sb); sb->pos_regs[0] = 0x03; sb->pos_regs[1] = 0x51; @@ -580,37 +1040,27 @@ 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); + uint16_t addr = device_get_config_int("addr"); + sb->opl_emu = device_get_config_int("opl_emu"); + opl3_init(&sb->opl, sb->opl_emu); + sb_dsp_init(&sb->dsp, SB16, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + // TODO: irq and dma options too? + sb_ct1745_mixer_reset(sb); + io_sethandler(addr, 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, 0x0004, 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); + io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sb16, sb); + mpu401_uart_init(&sb->mpu, 0x330, -1, 0); - 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"); + return rom_present("awe32.raw"); } void *sb_awe32_init() @@ -619,38 +1069,41 @@ void *sb_awe32_init() 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); + uint16_t addr = device_get_config_int("addr"); + uint16_t emu_addr = device_get_config_int("emu_addr"); + sb->opl_emu = device_get_config_int("opl_emu"); + opl3_init(&sb->opl, sb->opl_emu); + sb_dsp_init(&sb->dsp, SB16 + 1, SB_SUBTYPE_DEFAULT, sb); + sb_dsp_setaddr(&sb->dsp, addr); + // TODO: irq and dma options too? + sb_ct1745_mixer_reset(sb); + io_sethandler(addr, 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, 0x0004, 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); + io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_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); + mpu401_uart_init(&sb->mpu, 0x330, -1, 0); + emu8k_init(&sb->emu8k, emu_addr, 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; + sb_dsp_close(&sb->dsp); + #ifdef SB_DSP_RECORD_DEBUG + if (soundfsb != 0) + { + fclose(soundfsb); + soundfsb=0; + } + if (soundfsbin!= 0) + { + fclose(soundfsbin); + soundfsbin=0; + } + #endif free(sb); } @@ -661,7 +1114,7 @@ void sb_awe32_close(void *p) emu8k_close(&sb->emu8k); - free(sb); + sb_close(sb); } void sb_speed_changed(void *p) @@ -683,7 +1136,97 @@ static device_config_t sb_config[] = { .name = "addr", .description = "Address", - .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x210", + .value = 0x210 + }, + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x230", + .value = 0x230 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x250", + .value = 0x250 + }, + { + .description = "0x260", + .value = 0x260 + }, + { + .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 sb2_config[] = +{ + { + .name = "addr", + .description = "Address", .type = CONFIG_SELECTION, .selection = { @@ -701,6 +1244,30 @@ static device_config_t sb_config[] = }, .default_int = 0x220 }, + { + .name = "mixaddr", + .description = "Mixer Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "No mixer", + .value = 0 + }, + { + .description = "0x250", + .value = 0x250 + }, + { + .description = "0x260", + .value = 0x260 + }, + { + .description = "" + } + }, + .default_int = 0 + }, { .name = "irq", .description = "IRQ", @@ -805,12 +1372,11 @@ static device_config_t sb_mcv_config[] = } }; -static device_config_t sb_pro_config[] = +static device_config_t sb_pro_v1_config[] = { { .name = "addr", .description = "Address", - .type = CONFIG_BINARY, .type = CONFIG_SELECTION, .selection = { @@ -881,14 +1447,175 @@ static device_config_t sb_pro_config[] = } }; +static device_config_t sb_pro_v2_config[] = +{ + { + .name = "addr", + .description = "Address", + .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 + }, + { + .name = "opl_emu", + .description = "OPL emulator", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DBOPL", + .value = OPL_DBOPL + }, + { + .description = "NukedOPL", + .value = OPL_NUKED + }, + }, + .default_int = OPL_DBOPL + }, + { + .type = -1 + } +}; + +static device_config_t sb_pro_mcv_config[] = +{ + { + .name = "opl_emu", + .description = "OPL emulator", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DBOPL", + .value = OPL_DBOPL + }, + { + .description = "NukedOPL", + .value = OPL_NUKED + }, + }, + .default_int = OPL_DBOPL + }, + { + .type = -1 + } +}; + static device_config_t sb_16_config[] = { + { + .name = "addr", + .description = "Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x260", + .value = 0x260 + }, + { + .description = "0x280", + .value = 0x280 + }, + { + .description = "" + } + }, + .default_int = 0x220 + }, { .name = "midi", .description = "MIDI out device", .type = CONFIG_MIDI, .default_int = 0 }, + { + .name = "opl_emu", + .description = "OPL emulator", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DBOPL", + .value = OPL_DBOPL + }, + { + .description = "NukedOPL", + .value = OPL_NUKED + }, + }, + .default_int = OPL_DBOPL + }, { .type = -1 } @@ -897,7 +1624,62 @@ static device_config_t sb_16_config[] = static device_config_t sb_awe32_config[] = { { - .name = "midi", + .name = "addr", + .description = "Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "0x260", + .value = 0x260 + }, + { + .description = "0x280", + .value = 0x280 + }, + { + .description = "" + } + }, + .default_int = 0x220 + }, + { + .name = "emu_addr", + .description = "EMU8000 Address", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x620", + .value = 0x620 + }, + { + .description = "0x640", + .value = 0x640 + }, + { + .description = "0x660", + .value = 0x660 + }, + { + .description = "0x680", + .value = 0x680 + }, + { + .description = "" + } + }, + .default_int = 0x620 + }, + { .name = "midi", .description = "MIDI out device", .type = CONFIG_MIDI, .default_int = 0 @@ -934,6 +1716,23 @@ static device_config_t sb_awe32_config[] = }, .default_int = 512 }, + { + .name = "opl_emu", + .description = "OPL emulator", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DBOPL", + .value = OPL_DBOPL + }, + { + .description = "NukedOPL", + .value = OPL_NUKED + }, + }, + .default_int = OPL_DBOPL + }, { .type = -1 } @@ -985,7 +1784,7 @@ device_t sb_2_device = sb_speed_changed, NULL, sb_add_status_info, - sb_config + sb2_config }; device_t sb_pro_v1_device = { @@ -997,7 +1796,7 @@ device_t sb_pro_v1_device = sb_speed_changed, NULL, sb_add_status_info, - sb_pro_config + sb_pro_v1_config }; device_t sb_pro_v2_device = { @@ -1009,7 +1808,7 @@ device_t sb_pro_v2_device = sb_speed_changed, NULL, sb_add_status_info, - sb_pro_config + sb_pro_v2_config }; device_t sb_pro_mcv_device = { @@ -1021,7 +1820,7 @@ device_t sb_pro_mcv_device = sb_speed_changed, NULL, sb_add_status_info, - NULL + sb_pro_mcv_config }; device_t sb_16_device = { @@ -1040,7 +1839,7 @@ device_t sb_awe32_device = "Sound Blaster AWE32", 0, sb_awe32_init, - sb_close, + sb_awe32_close, sb_awe32_available, sb_speed_changed, NULL, diff --git a/src/sound_sb.h b/src/sound_sb.h index fb856c8..405bd39 100644 --- a/src/sound_sb.h +++ b/src/sound_sb.h @@ -1,3 +1,10 @@ +#ifndef SOUND_SB_H +#define SOUND_SB_H + +#include "sound_emu8k.h" +#include "sound_mpu401_uart.h" +#include "sound_sb_dsp.h" + extern device_t sb_1_device; extern device_t sb_15_device; extern device_t sb_mcv_device; @@ -7,3 +14,110 @@ extern device_t sb_pro_v2_device; extern device_t sb_pro_mcv_device; extern device_t sb_16_device; extern device_t sb_awe32_device; + +/* SB 2.0 CD version */ +typedef struct sb_ct1335_mixer_t +{ + int32_t master; + int32_t voice; + int32_t fm; + int32_t cd; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1335_mixer_t; +/* SB PRO */ +typedef struct sb_ct1345_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + /*see sb_ct1745_mixer for values for input selector*/ + int32_t input_selector; + + int input_filter; + int in_filter_freq; + int output_filter; + + int stereo; + int stereo_isleft; + + uint8_t index; + uint8_t regs[256]; + +} sb_ct1345_mixer_t; +/* SB16 and AWE32 */ +typedef struct sb_ct1745_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + int32_t speaker; + + int bass_l, bass_r; + int treble_l, treble_r; + + int output_selector; + #define OUTPUT_MIC 1 + #define OUTPUT_CD_R 2 + #define OUTPUT_CD_L 4 + #define OUTPUT_LINE_R 8 + #define OUTPUT_LINE_L 16 + + int input_selector_left; + int input_selector_right; + #define INPUT_MIC 1 + #define INPUT_CD_R 2 + #define INPUT_CD_L 4 + #define INPUT_LINE_R 8 + #define INPUT_LINE_L 16 + #define INPUT_MIDI_R 32 + #define INPUT_MIDI_L 64 + + int mic_agc; + + int32_t input_gain_L; + int32_t input_gain_R; + int32_t output_gain_L; + int32_t output_gain_R; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1745_mixer_t; + +typedef struct sb_t +{ + opl_t opl; + sb_dsp_t dsp; + union { + sb_ct1335_mixer_t mixer_sb2; + sb_ct1345_mixer_t mixer_sbpro; + sb_ct1745_mixer_t mixer_sb16; + }; + mpu401_uart_t mpu; + emu8k_t emu8k; + + int pos; + + uint8_t pos_regs[8]; + + int opl_emu; +} sb_t; + +// exported for clone cards +void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p); +void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p); +uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p); +void sb_ct1345_mixer_reset(sb_t* sb); + +void sb_close(void *p); +void sb_speed_changed(void *p); +void sb_add_status_info(char *s, int max_len, void *p); + +#endif /* SOUND_SB_H */ diff --git a/src/sound_sb_dsp.c b/src/sound_sb_dsp.c index 29dc3f0..3edf0d6 100644 --- a/src/sound_sb_dsp.c +++ b/src/sound_sb_dsp.c @@ -6,20 +6,37 @@ #include #include +#include #include "ibm.h" +#include "device.h" #include "dma.h" +#include "filters.h" #include "io.h" #include "pic.h" #include "sound.h" +#include "sound_azt2316a.h" #include "sound_sb_dsp.h" #include "timer.h" +#include "x86.h" + +/*The recording safety margin is intended for uneven "len" calls to the get_buffer mixer calls on sound_sb*/ +#define SB_DSP_REC_SAFEFTY_MARGIN 4096 void pollsb(void *p); void sb_poll_i(void *p); +//#define SB_DSP_RECORD_DEBUG +//#define SB_TEST_RECORDING_SAW +#ifdef SB_DSP_RECORD_DEBUG +FILE* soundf = 0/*NULL*/; +#endif + +#ifdef SB_TEST_RECORDING_SAW +int counttest; +#endif static int sbe2dat[4][9] = { { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, @@ -96,6 +113,42 @@ uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x 252, 0, 252, 0 }; +float low_fir_sb16_coef[SB16_NCoef]; + +static inline double sinc(double x) +{ + return sin(M_PI * x) / (M_PI * x); +} + +static void recalc_sb16_filter(int playback_freq) +{ + /*Cutoff frequency = playback / 2*/ + float fC = ((float)playback_freq / 2.0) / 48000.0; + float gain; + int n; + + for (n = 0; n < SB16_NCoef; n++) + { + /*Blackman window*/ + double w = 0.42 - (0.5 * cos((2.0*n*M_PI)/(double)(SB16_NCoef-1))) + (0.08 * cos((4.0*n*M_PI)/(double)(SB16_NCoef-1))); + /*Sinc filter*/ + double h = sinc(2.0 * fC * ((double)n - ((double)(SB16_NCoef-1) / 2.0))); + + /*Create windowed-sinc filter*/ + low_fir_sb16_coef[n] = w * h; + } + + low_fir_sb16_coef[(SB16_NCoef - 1) / 2] = 1.0; + + gain = 0.0; + for (n = 0; n < SB16_NCoef; n++) + gain += low_fir_sb16_coef[n]; + + /*Normalise filter, to produce unity gain*/ + for (n = 0; n < SB16_NCoef; n++) + low_fir_sb16_coef[n] /= gain; +} + void sb_irq(sb_dsp_t *dsp, int irq8) @@ -114,7 +167,9 @@ void sb_irqc(sb_dsp_t *dsp, int irq8) void sb_dsp_reset(sb_dsp_t *dsp) { - dsp->sbenable = dsp->sb_enable_i = 0; + timer_disable(&dsp->output_timer); + timer_disable(&dsp->input_timer); + dsp->sb_command = 0; dsp->sb_8_length = 0xffff; @@ -131,11 +186,21 @@ void sb_dsp_reset(sb_dsp_t *dsp) dsp->sbe2count = 0; dsp->sbreset = 0; - dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0; + dsp->record_pos_read=0; + dsp->record_pos_write=SB_DSP_REC_SAFEFTY_MARGIN; + picintc(1 << dsp->sb_irqnum); dsp->asp_data_len = 0; + + #ifdef SB_DSP_RECORD_DEBUG + if (soundf != 0) + { + fclose(soundf); + soundf=0; + } + #endif } void sb_doreset(sb_dsp_t *dsp) @@ -143,10 +208,18 @@ 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; - + + if (IS_AZTECH(dsp)) + { + sb_commands[8] = 1; + sb_commands[9] = 1; + } + else + { + 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; @@ -158,12 +231,12 @@ 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))); + dsp->sblatcho = (uint64_t)(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))); + dsp->sblatchi = (uint64_t)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256))); } void sb_add_data(sb_dsp_t *dsp, uint8_t v) @@ -188,9 +261,8 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len 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(); + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); dsp->sbleftright = 0; dsp->sbdacpos = 0; // pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); @@ -204,9 +276,8 @@ void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len 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(); + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); // pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len); } } @@ -215,6 +286,13 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l { if (dma8) { +#ifdef SB_TEST_RECORDING_SAW + switch (dsp->sb_8_format) + { + case 00:case 20:counttest=0x80;break; + case 10:case 30:counttest=0;break; + } +#endif dsp->sb_8_length = len; dsp->sb_8_format = format; dsp->sb_8_autoinit = autoinit; @@ -222,13 +300,19 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l 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(); + if (!timer_is_enabled(&dsp->input_timer)) + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); // pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); } else { +#ifdef SB_TEST_RECORDING_SAW + switch (dsp->sb_16_format) + { + case 00:case 20:counttest=0x8000;break; + case 10:case 30:counttest=0;break; + } +#endif dsp->sb_16_length = len; dsp->sb_16_format = format; dsp->sb_16_autoinit = autoinit; @@ -236,11 +320,20 @@ void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int l 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(); + if (!timer_is_enabled(&dsp->input_timer)) + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); // pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); } + memset(dsp->record_buffer,0,sizeof(dsp->record_buffer)); + + #ifdef SB_DSP_RECORD_DEBUG + if (soundf != 0) + { + fclose(soundf); + soundf=0; + } + #endif + } int sb_8_read_dma(sb_dsp_t *dsp) @@ -250,14 +343,23 @@ int sb_8_read_dma(sb_dsp_t *dsp) void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) { dma_channel_write(dsp->sb_8_dmanum, val); +#ifdef SB_DSP_RECORD_DEBUG + if (!soundf) soundf=fopen("sound_dsp.pcm","wb"); + fwrite(&val,1,1,soundf); +#endif } -uint16_t sb_16_read_dma(sb_dsp_t *dsp) +int sb_16_read_dma(sb_dsp_t *dsp) { - return dma_channel_read(5); + return dma_channel_read(dsp->sb_16_dmanum); } -void sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) +int sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) { - dma_channel_write(5, val); + int ret = dma_channel_write(dsp->sb_16_dmanum, val); +#ifdef SB_DSP_RECORD_DEBUG + if (!soundf) soundf=fopen("sound_dsp.pcm","wb"); + fwrite(&val,2,1,soundf); +#endif + return (ret == DMA_NODATA); } void sb_dsp_setirq(sb_dsp_t *dsp, int irq) @@ -270,6 +372,10 @@ void sb_dsp_setdma8(sb_dsp_t *dsp, int dma) dsp->sb_8_dmanum = dma; } +void sb_dsp_setdma16(sb_dsp_t *dsp, int dma) +{ + dsp->sb_16_dmanum = dma; +} void sb_exec_command(sb_dsp_t *dsp) { int temp,c; @@ -298,6 +404,8 @@ void sb_exec_command(sb_dsp_t *dsp) 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--; + if (dsp->sb_command == 0x17) + dsp->sb_8_length--; break; case 0x1C: /*8-bit autoinit DMA output*/ if (dsp->sb_type < SB15) break; @@ -310,7 +418,17 @@ void sb_exec_command(sb_dsp_t *dsp) dsp->sb_8_length--; break; case 0x20: /*8-bit direct input*/ - sb_add_data(dsp, 0); + sb_add_data(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); + /*Due to the current implementation, I need to emulate a samplerate, even if this + * mode does not imply such samplerate. Position is increased in sb_poll_i*/ + if (!timer_is_enabled(&dsp->input_timer)) + { + dsp->sb_timei = 256 - 22; + dsp->sblatchi = TIMER_USEC * 22; + temp = 1000000 / 22; + dsp->sb_freq = temp; + timer_set_delay_u64(&dsp->input_timer, dsp->sblatchi); + } 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)); @@ -325,17 +443,22 @@ void sb_exec_command(sb_dsp_t *dsp) temp = 256 - dsp->sb_data[0]; temp = 1000000 / temp; // pclog("Sample rate - %ihz (%i)\n",temp, dsp->sblatcho); + if (dsp->sb_freq != temp && dsp->sb_type >= SB16) + recalc_sb16_filter(temp); 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)))); + dsp->sblatcho = (uint64_t)(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); + temp = dsp->sb_freq; 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; + if (dsp->sb_freq != temp && dsp->sb_type >= SB16) + recalc_sb16_filter(dsp->sb_freq); break; case 0x48: /*Set DSP block transfer size*/ dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); @@ -348,6 +471,8 @@ void sb_exec_command(sb_dsp_t *dsp) 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--; + if (dsp->sb_command == 0x75) + dsp->sb_8_length--; break; case 0x77: /*2.6-bit ADPCM output with reference*/ dsp->sbref = sb_8_read_dma(dsp); @@ -357,6 +482,8 @@ void sb_exec_command(sb_dsp_t *dsp) 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--; + if (dsp->sb_command == 0x77) + dsp->sb_8_length--; break; case 0x7D: /*4-bit ADPCM autoinit output*/ if (dsp->sb_type < SB15) break; @@ -373,9 +500,8 @@ void sb_exec_command(sb_dsp_t *dsp) 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(); + if (!timer_is_enabled(&dsp->output_timer)) + timer_set_delay_u64(&dsp->output_timer, dsp->sblatcho); break; case 0x90: /*High speed 8-bit autoinit DMA output*/ if (dsp->sb_type < SB2) break; @@ -395,6 +521,8 @@ void sb_exec_command(sb_dsp_t *dsp) break; case 0xA0: /*Set input mode to mono*/ case 0xA8: /*Set input mode to stereo*/ + if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) break; + //TODO: Implement. 3.xx-only command. break; case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: /*16-bit DMA output*/ @@ -424,9 +552,17 @@ void sb_exec_command(sb_dsp_t *dsp) dsp->sb_8_pause = 1; break; case 0xD1: /*Speaker on*/ + if (dsp->sb_type < SB15 ) + dsp->sb_8_pause = 1; + else if ( dsp->sb_type < SB16 ) + dsp->muted = 0; dsp->sb_speaker = 1; break; case 0xD3: /*Speaker off*/ + if (dsp->sb_type < SB15 ) + dsp->sb_8_pause = 1; + else if ( dsp->sb_type < SB16 ) + dsp->muted = 1; dsp->sb_speaker = 0; break; case 0xD4: /*Continue 8-bit DMA*/ @@ -454,6 +590,20 @@ void sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, ~dsp->sb_data[0]); break; case 0xE1: /*Get DSP version*/ + if (IS_AZTECH(dsp)) + { + if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) + { + sb_add_data(dsp, 0x3); + sb_add_data(dsp, 0x1); + } + else if (dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) + { + sb_add_data(dsp, 0x2); + sb_add_data(dsp, 0x1); + } + break; + } sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); break; @@ -481,6 +631,10 @@ void sb_exec_command(sb_dsp_t *dsp) // pclog("Trigger IRQ\n"); sb_irq(dsp, 1); break; + case 0xF3: /*Trigger 16-bit IRQ*/ +// pclog("Trigger IRQ\n"); + sb_irq(dsp, 0); + break; case 0xE7: /*???*/ case 0xFA: /*???*/ break; @@ -488,6 +642,32 @@ void sb_exec_command(sb_dsp_t *dsp) case 0xFF: break; case 0x08: /*ASP get version*/ + if (IS_AZTECH(dsp)) + { + if ((dsp->sb_data[0] == 0x55 || dsp->sb_data[0] == 0x05) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11) + sb_add_data(dsp, 0x11); /* AZTECH get type, WASHINGTON/latest - according to devkit. E.g.: The one in the Itautec Infoway Multimidia */ + else if ((dsp->sb_data[0] == 0x55 || dsp->sb_data[0] == 0x05) && dsp->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) + sb_add_data(dsp, 0x0C); /* AZTECH get type, CLINTON - according to devkit. E.g.: The one in the Packard Bell Legend 100CD */ + else if (dsp->sb_data[0] == 0x08) + { + // EEPROM address to write followed by byte + if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) + fatal("AZT EEPROM: out of bounds write to %02X\n", dsp->sb_data[1]); + dsp->azt_eeprom[dsp->sb_data[1]] = dsp->sb_data[2]; + break; + } + else if (dsp->sb_data[0] == 0x07) + { + // EEPROM address to read + if (dsp->sb_data[1] < 0 || dsp->sb_data[1] >= AZTECH_EEPROM_SIZE) + fatal("AZT EEPROM: out of bounds read to %02X\n", dsp->sb_data[1]); + sb_add_data(dsp, dsp->azt_eeprom[dsp->sb_data[1]]); + break; + } + else + pclog("AZT2316A: UNKNOWN 0x08 COMMAND: %02X\n", dsp->sb_data[0]); // 0x08 (when shutting down, driver tries to read 1 byte of response), 0x55, 0x0D, 0x08D seen + break; + } if (dsp->sb_type < SB16) break; sb_add_data(dsp, 0x18); break; @@ -501,6 +681,10 @@ void sb_exec_command(sb_dsp_t *dsp) // 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 0xF8: + if (dsp->sb_type >= SB16) break; + sb_add_data(dsp, 0); break; case 0xF9: if (dsp->sb_type < SB16) break; @@ -511,8 +695,43 @@ void sb_exec_command(sb_dsp_t *dsp) case 0x04: case 0x05: break; + case 0x09: /*AZTECH mode set*/ + if (IS_AZTECH(dsp)) + { + if (dsp->sb_data[0] == 0x00) + { + pclog("AZT2316A: WSS MODE!\n"); + azt2316a_enable_wss(1, dsp->parent); + } + else if (dsp->sb_data[0] == 0x01) + { + pclog("AZT2316A: SB8PROV2 MODE!\n"); + azt2316a_enable_wss(0, dsp->parent); + } + else + pclog("AZT2316A: UNKNOWN MODE!\n"); // sequences 0x02->0xFF, 0x04->0xFF seen + } + break; + case 0x38: /*TODO: AZTECH MIDI-related? */ + break; // default: -// fatal("Exec bad SB command %02X\n",sb_command); +// fatal("Exec bad SB command %02X\n",dsp->sb_command); + + + /*TODO: Some more data about the DSP registeres + * http://the.earth.li/~tfm/oldpage/sb_dsp.html + * http://www.synchrondata.com/pheaven/www/area19.htm + * http://www.dcee.net/Files/Programm/Sound/ + 0E3h DSP Copyright SBPro2??? + 0F0h Sine Generator SB + 0F1h DSP Auxiliary Status (Obsolete) SB-Pro2 + 0F2h IRQ Request, 8-bit SB + 0F3h IRQ Request, 16-bit SB16 + 0FBh DSP Status SB16 + 0FCh DSP Auxiliary Status SB16 + 0FDh DSP Command Status SB16 + */ + } } @@ -531,10 +750,7 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->sbreset = v; return; case 0xC: /*Command/data write*/ - timer_process(); - dsp->wb_time = TIMER_USEC * 1; - dsp->wb_full = 1; - timer_update_outstanding(); + timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1); if (dsp->asp_data_len) { // pclog("ASP data %i\n", dsp->asp_data_len); @@ -553,11 +769,27 @@ void sb_write(uint16_t a, uint8_t v, void *priv) dsp->sb_data_stat++; } else - dsp->sb_data[dsp->sb_data_stat++] = v; + { + dsp->sb_data[dsp->sb_data_stat++] = v; + if (IS_AZTECH(dsp)) + { + // variable length commands + if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x08) + sb_commands[dsp->sb_command] = 3; + else if (dsp->sb_command == 0x08 && dsp->sb_data_stat == 1 && dsp->sb_data[0] == 0x07) + sb_commands[dsp->sb_command] = 2; + } + } 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; + if (IS_AZTECH(dsp)) + { + // variable length commands + if (dsp->sb_command == 0x08) + sb_commands[dsp->sb_command] = 1; + } } break; } @@ -566,7 +798,6 @@ void sb_write(uint16_t a, uint8_t v, void *priv) 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) { @@ -580,16 +811,38 @@ uint8_t sb_read(uint16_t a, void *priv) // pclog("SB read %02X\n",sbreaddat); return dsp->sbreaddat; case 0xC: /*Write data ready*/ - if (dsp->wb_full) + if (dsp->sb_8_enable || dsp->sb_type >= SB16) + dsp->busy_count = (dsp->busy_count + 1) & 3; + else + dsp->busy_count = 0; + if (dsp->wb_full || (dsp->busy_count & 2)) { - dsp->wb_full = dsp->wb_time; - return 0xff; + dsp->wb_full = timer_is_enabled(&dsp->wb_timer); +// pclog("SB read 0x80\n"); + if (IS_AZTECH(dsp)) + return 0x80; + else + return 0xFF; } - return 0x7f; +// pclog("SB read 0x00\n"); + if (IS_AZTECH(dsp)) + return 0x00; + else + 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; + // Only bit 7 is defined but aztech diagnostics fail if the others are set. Keep the original behavior to not interfere with what's already working. + if (IS_AZTECH(dsp)) + { +// pclog("SB read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80); + return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x00 : 0x80; + } + else + { +// pclog("SB read %02X\n",(dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7F : 0xFF); + 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); @@ -600,23 +853,28 @@ uint8_t sb_read(uint16_t a, void *priv) 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) +void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent) { dsp->sb_type = type; + dsp->sb_subtype = subtype; + dsp->parent = parent; + // Default values. Use sb_dsp_setxxx() methods to change. dsp->sb_irqnum = 7; dsp->sb_8_dmanum = 1; + dsp->sb_16_dmanum = 5; 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); + timer_add(&dsp->output_timer, pollsb, dsp, 0); + timer_add(&dsp->input_timer, sb_poll_i, dsp, 0); + timer_add(&dsp->wb_timer, sb_wb_clear, dsp, 0); + + /*Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when + a set frequency command is sent.*/ + recalc_sb16_filter(3200*2); } void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) @@ -642,7 +900,8 @@ void pollsb(void *p) sb_dsp_t *dsp = (sb_dsp_t *)p; int tempi,ref; - dsp->sbcount += dsp->sblatcho; + timer_advance_u64(&dsp->output_timer, 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) { @@ -666,7 +925,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; dsp->sb_8_length--; break; case 0x10: /*Mono signed*/ @@ -681,7 +940,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; dsp->sb_8_length--; break; case 0x20: /*Stereo unsigned*/ @@ -733,7 +992,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; break; case ADPCM_26: @@ -767,7 +1026,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; break; case ADPCM_2: @@ -797,7 +1056,7 @@ void pollsb(void *p) dsp->sbleftright = !dsp->sbleftright; } else - dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; break; // default: @@ -806,36 +1065,56 @@ void pollsb(void *p) 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; + if (dsp->sb_8_autoinit) + dsp->sb_8_length = dsp->sb_8_autolen; + else + { + dsp->sb_8_enable = 0; + timer_disable(&dsp->output_timer); + } sb_irq(dsp, 1); } } if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && dsp->sb_16_output) { + int data[2]; + sb_dsp_update(dsp); switch (dsp->sb_16_format) { case 0x00: /*Mono unsigned*/ - dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + data[0] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdatl = dsp->sbdatr = data[0] ^ 0x8000; dsp->sb_16_length--; break; case 0x10: /*Mono signed*/ - dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp); + data[0] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdatl = dsp->sbdatr = data[0]; 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; + data[0] = sb_16_read_dma(dsp); + data[1] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0] ^ 0x8000; + dsp->sbdatr = data[1] ^ 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); + data[0] = sb_16_read_dma(dsp); + data[1] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0]; + dsp->sbdatr = data[1]; dsp->sb_16_length -= 2; break; - // default: // fatal("Unrecognised SB 16-bit format %02X\n",sb_16_format); } @@ -843,8 +1122,13 @@ void pollsb(void *p) 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; + if (dsp->sb_16_autoinit) + dsp->sb_16_length = dsp->sb_16_autolen; + else + { + dsp->sb_16_enable = 0; + timer_disable(&dsp->output_timer); + } sb_irq(dsp, 0); } } @@ -854,7 +1138,8 @@ void pollsb(void *p) if (dsp->sb_pausetime < 0) { sb_irq(dsp, 1); - dsp->sbenable = dsp->sb_8_enable; + if (!dsp->sb_8_enable) + timer_disable(&dsp->output_timer); // pclog("SB pause over\n"); } } @@ -863,32 +1148,59 @@ void pollsb(void *p) void sb_poll_i(void *p) { sb_dsp_t *dsp = (sb_dsp_t *)p; - - dsp->sb_count_i += dsp->sblatchi; + int processed=0; + + timer_advance_u64(&dsp->input_timer, 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); +#ifdef SB_TEST_RECORDING_SAW + case 0x00: /*Unsigned mono. As the manual says, only the left channel is recorded*/ + case 0x10: /*Signed mono. As the manual says, only the left channel is recorded*/ + sb_8_write_dma(dsp, counttest); + counttest+=0x10; + counttest&=0xFF; dsp->sb_8_length--; break; - case 0x10: /*Mono signed*/ - sb_8_write_dma(dsp, 0x00); + case 0x20: /*Unsigned stereo*/ + case 0x30: /*Signed stereo*/ + sb_8_write_dma(dsp, counttest); + sb_8_write_dma(dsp, counttest); + counttest+=0x10; + counttest&=0xFF; + dsp->sb_8_length -= 2; + break; +#else + case 0x00: /*Mono unsigned As the manual says, only the left channel is recorded*/ + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); dsp->sb_8_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x10: /*Mono signed As the manual says, only the left channel is recorded*/ + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)); + dsp->sb_8_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; break; case 0x20: /*Stereo unsigned*/ - sb_8_write_dma(dsp, 0x80); - sb_8_write_dma(dsp, 0x80); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)^0x80); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read+1]>>8)^0x80); dsp->sb_8_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; break; case 0x30: /*Stereo signed*/ - sb_8_write_dma(dsp, 0x00); - sb_8_write_dma(dsp, 0x00); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read+1]>>8)); dsp->sb_8_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; break; - +#endif // default: // fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format); } @@ -896,34 +1208,71 @@ void sb_poll_i(void *p) 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; + if (dsp->sb_8_autoinit) + dsp->sb_8_length = dsp->sb_8_autolen; + else + { + dsp->sb_8_enable = 0; + timer_disable(&dsp->input_timer); + } sb_irq(dsp, 1); } + processed=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); +#ifdef SB_TEST_RECORDING_SAW + case 0x00: /*Unsigned mono. As the manual says, only the left channel is recorded*/ + case 0x10: /*Signed mono. As the manual says, only the left channel is recorded*/ + if (sb_16_write_dma(dsp, counttest)) + return; + counttest+=0x1000; + counttest&=0xFFFF; dsp->sb_16_length--; break; case 0x20: /*Unsigned stereo*/ - sb_16_write_dma(dsp, 0x8000); - sb_16_write_dma(dsp, 0x8000); + case 0x30: /*Signed stereo*/ + if (sb_16_write_dma(dsp, counttest)) + return; + sb_16_write_dma(dsp, counttest); + counttest+=0x1000; + counttest&=0xFFFF; dsp->sb_16_length -= 2; break; +#else + case 0x00: /*Unsigned mono. As the manual says, only the left channel is recorded*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]^0x8000)) + return; + dsp->sb_16_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x10: /*Signed mono. As the manual says, only the left channel is recorded*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read])) + return; + dsp->sb_16_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x20: /*Unsigned stereo*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]^0x8000)) + return; + sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read+1]^0x8000); + dsp->sb_16_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; case 0x30: /*Signed stereo*/ - sb_16_write_dma(dsp, 0); - sb_16_write_dma(dsp, 0); + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read])) + return; + sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read+1]); dsp->sb_16_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; break; - +#endif // default: // fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format); } @@ -931,21 +1280,48 @@ void sb_poll_i(void *p) 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; + if (dsp->sb_16_autoinit) + dsp->sb_16_length = dsp->sb_16_autolen; + else + { + dsp->sb_16_enable = 0; + timer_disable(&dsp->input_timer); + } sb_irq(dsp, 0); } + processed=1; + } + //Assume this is direct mode + if (!processed) + { + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; } } void sb_dsp_update(sb_dsp_t *dsp) { + if (dsp->muted) + { + dsp->sbdatl=0; + dsp->sbdatr=0; + } 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_close(sb_dsp_t *dsp) +{ + #ifdef SB_DSP_RECORD_DEBUG + if (soundf != 0) + { + fclose(soundf); + soundf=0; + } + #endif +} void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp) { @@ -1009,4 +1385,5 @@ void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp) sprintf(temps, "SB playback frequency : %iHz\n", freq); strncat(s, temps, max_len); } + strncat(s, "\n", max_len); } diff --git a/src/sound_sb_dsp.h b/src/sound_sb_dsp.h index 81b4641..33661c0 100644 --- a/src/sound_sb_dsp.h +++ b/src/sound_sb_dsp.h @@ -1,15 +1,31 @@ +#ifndef SOUND_SB_DSP_H +#define SOUND_SB_DSP_H + +/*Sound Blaster Clones, for quirks*/ +#define SB_SUBTYPE_DEFAULT 0 /*Handle as a Creative card*/ +#define SB_SUBTYPE_CLONE_AZT2316A_0X11 1 /*Aztech Sound Galaxy Pro 16 AB, DSP 3.1 - SBPRO2 clone*/ +#define SB_SUBTYPE_CLONE_AZT1605_0X0C 2 /*Aztech Sound Galaxy Nova 16 Extra / Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone*/ + +// aztech-related +#define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C) // check for future AZT cards here +#define AZTECH_EEPROM_SIZE 16 + typedef struct sb_dsp_t { int sb_type; + int sb_subtype; // which clone + void *parent; // "sb_t *" if default subtype, "azt2316a_t *" if aztech. 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_16_dmanum; int sb_pausetime; uint8_t sb_read_data[256]; int sb_read_wp, sb_read_rp; int sb_speaker; + int muted; int sb_data_stat; @@ -45,9 +61,9 @@ typedef struct sb_dsp_t int sbenable, sb_enable_i; - int sbcount, sb_count_i; + pc_timer_t output_timer, input_timer; - int sblatcho, sblatchi; + uint64_t sblatcho, sblatchi; uint16_t sb_addr; @@ -55,16 +71,26 @@ typedef struct sb_dsp_t int asp_data_len; - int wb_time, wb_full; + pc_timer_t wb_timer; + int wb_full; - int16_t buffer[SOUNDBUFLEN * 2]; + int busy_count; + + int record_pos_read; + int record_pos_write; + int16_t record_buffer[0xFFFF]; + int16_t buffer[MAXSOUNDBUFLEN * 2]; int pos; + + uint8_t azt_eeprom[AZTECH_EEPROM_SIZE]; // the eeprom in the Aztech cards is attached to the DSP } sb_dsp_t; -void sb_dsp_init(sb_dsp_t *dsp, int type); +void sb_dsp_init(sb_dsp_t *dsp, int type, int subtype, void *parent); +void sb_dsp_close(sb_dsp_t *dsp); void sb_dsp_setirq(sb_dsp_t *dsp, int irq); void sb_dsp_setdma8(sb_dsp_t *dsp, int dma); +void sb_dsp_setdma16(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); @@ -76,3 +102,5 @@ 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); + +#endif /* SOUND_SB_DSP_H */ diff --git a/src/sound_sn76489.c b/src/sound_sn76489.c index 6acb24f..3dbbd2f 100644 --- a/src/sound_sn76489.c +++ b/src/sound_sn76489.c @@ -92,7 +92,7 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) case 0: sn76489->freqlo[3] = data & 0xf; sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6; - if (sn76489->extra_divide) + if (!sn76489->extra_divide) sn76489->latch[3] &= 0x3ff; if (!sn76489->latch[3]) sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6; @@ -105,7 +105,7 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) case 0x20: sn76489->freqlo[2] = data & 0xf; sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6; - if (sn76489->extra_divide) + if (!sn76489->extra_divide) sn76489->latch[2] &= 0x3ff; if (!sn76489->latch[2]) sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6; @@ -118,7 +118,7 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) case 0x40: sn76489->freqlo[1] = data & 0xf; sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6; - if (sn76489->extra_divide) + if (!sn76489->extra_divide) sn76489->latch[1] &= 0x3ff; if (!sn76489->latch[1]) sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6; @@ -134,8 +134,6 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) 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; @@ -161,7 +159,7 @@ void sn76489_write(uint16_t addr, uint8_t data, void *p) { sn76489->freqhi[sn76489->lasttone] = data & 0x7F; freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4); - if (sn76489->extra_divide) + if (!sn76489->extra_divide) freq &= 0x3ff; if (!freq) freq = sn76489->extra_divide ? 2048 : 1024; diff --git a/src/sound_sn76489.h b/src/sound_sn76489.h index 2f7a687..d5acb62 100644 --- a/src/sound_sn76489.h +++ b/src/sound_sn76489.h @@ -1,3 +1,5 @@ +#include "sound.h" + enum { SN76496, @@ -23,7 +25,7 @@ typedef struct sn76489_t int type; int extra_divide; - int16_t buffer[SOUNDBUFLEN]; + int16_t buffer[MAXSOUNDBUFLEN]; int pos; double psgconst; diff --git a/src/sound_speaker.c b/src/sound_speaker.c index a6c386d..d70651c 100644 --- a/src/sound_speaker.c +++ b/src/sound_speaker.c @@ -4,7 +4,7 @@ int speaker_mute = 0; -static int16_t speaker_buffer[SOUNDBUFLEN]; +static int16_t speaker_buffer[MAXSOUNDBUFLEN]; static int speaker_pos = 0; diff --git a/src/sound_ssi2001.c b/src/sound_ssi2001.c index ff83041..2efc15c 100644 --- a/src/sound_ssi2001.c +++ b/src/sound_ssi2001.c @@ -10,7 +10,7 @@ typedef struct ssi2001_t { void *psid; - int16_t buffer[SOUNDBUFLEN * 2]; + int16_t buffer[MAXSOUNDBUFLEN * 2]; int pos; } ssi2001_t; diff --git a/src/sound_wss.c b/src/sound_wss.c index bd94c38..edbc272 100644 --- a/src/sound_wss.c +++ b/src/sound_wss.c @@ -78,12 +78,13 @@ static void wss_get_buffer(int32_t *buffer, int len, void *p) void *wss_init() { + int opl_emu; wss_t *wss = malloc(sizeof(wss_t)); - memset(wss, 0, sizeof(wss_t)); - opl3_init(&wss->opl); - ad1848_init(&wss->ad1848); + opl_emu = device_get_config_int("opl_emu"); + opl3_init(&wss->opl, opl_emu); + ad1848_init(&wss->ad1848, AD1848_TYPE_DEFAULT); ad1848_setirq(&wss->ad1848, 7); ad1848_setdma(&wss->ad1848, 3); @@ -111,6 +112,30 @@ void wss_speed_changed(void *p) ad1848_speed_changed(&wss->ad1848); } +static device_config_t wss_config[] = +{ + { + .name = "opl_emu", + .description = "OPL emulator", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DBOPL", + .value = OPL_DBOPL + }, + { + .description = "NukedOPL", + .value = OPL_NUKED + }, + }, + .default_int = OPL_DBOPL + }, + { + .type = -1 + } +}; + device_t wss_device = { "Windows Sound System", @@ -120,5 +145,6 @@ device_t wss_device = NULL, wss_speed_changed, NULL, - NULL + NULL, + wss_config }; diff --git a/src/soundopenal.c b/src/soundopenal.c index 639bbcc..a77a492 100644 --- a/src/soundopenal.c +++ b/src/soundopenal.c @@ -2,10 +2,16 @@ #include #include #include +#include #ifdef USE_OPENAL +#ifdef __APPLE__ +#include +#include +#else #include #include #endif +#endif #include "ibm.h" #include "sound.h" @@ -16,6 +22,9 @@ ALuint buffers_cd[4]; // front and back buffers static ALuint source[2]; // audio source #endif #define FREQ 48000 + +int SOUNDBUFLEN = 48000/20; + #define BUFLEN SOUNDBUFLEN void closeal(); @@ -172,6 +181,9 @@ void givealbuffer(int32_t *buf) { int c; ALuint buffer; + double gain = pow(10.0, (double)sound_gain / 20.0); + + alListenerf(AL_GAIN, gain); alSourceUnqueueBuffers(source[0], 1, &buffer); // printf("U "); @@ -236,6 +248,9 @@ void givealbuffer_cd(int16_t *buf) if (processed>=1) { ALuint buffer; + double gain = pow(10.0, (double)sound_gain / 20.0); + + alListenerf(AL_GAIN, gain); alSourceUnqueueBuffers(source[1], 1, &buffer); // printf("U "); diff --git a/src/sst39sf010.c b/src/sst39sf010.c new file mode 100644 index 0000000..b2283f1 --- /dev/null +++ b/src/sst39sf010.c @@ -0,0 +1,271 @@ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "sst39sf010.h" +#include "xi8088.h" + +typedef struct sst_t +{ + int command_state; + int id_mode; + int erase; + int dirty; + + char flash_path[1024]; + uint8_t data[0x20000]; +} sst_t; + +#define SST_CHIP_ERASE 0x10 +#define SST_SECTOR_ERASE 0x30 +#define SST_ERASE 0x80 +#define SST_SET_ID_MODE 0x90 +#define SST_BYTE_PROGRAM 0xa0 +#define SST_CLEAR_ID_MODE 0xf0 + +static void set_id_mode(sst_t *sst); +static void clear_id_mode(sst_t *sst); + +static uint32_t sst_masked_rom_addr(uint32_t addr) +{ + // The flipped MSB of the Xi 8088 is only present in the on-disk files, + // in ram the mapping is as the software sees. This does not cause + // problems with the programming commands because they only use the + // lower 2 bytes. + if (romset == ROM_XI8088 && !xi8088_bios_128kb()) + return addr & 0xffff; + else + return addr & 0x1ffff; +} + +static void sst_new_command(sst_t *sst, uint8_t val) +{ + switch (val) + { + case SST_CHIP_ERASE: + if (sst->erase) + { + memset(rom, 0xff, 0x20000); + memset(sst->data, 0xff, 0x20000); + } + sst->command_state = 0; + sst->erase = 0; + break; + + case SST_ERASE: + sst->command_state = 0; + sst->erase = 1; + break; + + case SST_SET_ID_MODE: + if (!sst->id_mode) + set_id_mode(sst); + sst->command_state = 0; + sst->erase = 0; + break; + + case SST_BYTE_PROGRAM: + sst->command_state = 3; + sst->erase = 0; + break; + + case SST_CLEAR_ID_MODE: + if (sst->id_mode) + clear_id_mode(sst); + sst->command_state = 0; + sst->erase = 0; + break; + + default: + sst->command_state = 0; + sst->erase = 0; + } +} + +static void sst_sector_erase(sst_t *sst, uint32_t sst_addr) +{ +// pclog("SST sector erase sst_addr %08x\n", sst_addr); + memset(&rom[sst_addr & 0x1f000], 0xff, 4096); + memset(&sst->data[sst_addr & 0x1f000], 0xff, 4096); + sst->dirty = 1; +} + +static uint8_t sst_read_id(uint32_t addr, void *p) +{ + if ((addr & 0xffff) == 0) + return 0xbf; /*SST*/ + else if ((addr & 0xffff) == 1) + return 0xb5; /*39SF010*/ + else + return 0xff; +// fatal("sst_read_id: addr=%08x\n", addr); +} + +static void sst_write(uint32_t addr, uint8_t val, void *p) +{ + sst_t *sst = (sst_t *)p; + +// pclog("sst_write: addr=%08x val=%02x state=%i\n", addr, val, sst->command_state); + switch (sst->command_state) + { + case 0: + if (val == 0xf0) + { + if (sst->id_mode) + clear_id_mode(sst); + } + else if ((addr & 0xffff) == 0x5555 && val == 0xaa) + sst->command_state = 1; + else + sst->command_state = 0; + break; + case 1: + if ((addr & 0xffff) == 0x2aaa && val == 0x55) + sst->command_state = 2; + else + sst->command_state = 0; + break; + case 2: + if ((addr & 0xffff) == 0x5555) + sst_new_command(sst, val); + else if (val == SST_SECTOR_ERASE && sst->erase) + { + sst_sector_erase(sst, sst_masked_rom_addr(addr)); + sst->command_state = 0; + } + else + sst->command_state = 0; + break; + case 3: +// pclog("Byte program %08x %02x\n", addr, val); + rom[sst_masked_rom_addr(addr)] = val; + sst->data[sst_masked_rom_addr(addr)] = val; + sst->command_state = 0; + sst->dirty = 1; + break; + } +} + +static void set_id_mode(sst_t *sst) +{ + int c; + + for (c = 0; c < 8; c++) + { + mem_mapping_set_handler(&bios_mapping[c], + sst_read_id, NULL, NULL, + sst_write, NULL, NULL); + mem_mapping_set_p(&bios_mapping[c], sst); + mem_mapping_set_handler(&bios_high_mapping[c], + sst_read_id, NULL, NULL, + sst_write, NULL, NULL); + mem_mapping_set_p(&bios_high_mapping[c], sst); + } + sst->id_mode = 1; +} + +static void clear_id_mode(sst_t *sst) +{ + int c; + + for (c = 0; c < 8; c++) + { + mem_mapping_set_handler(&bios_mapping[c], + mem_read_bios, mem_read_biosw, mem_read_biosl, + sst_write, NULL, NULL); + mem_mapping_set_p(&bios_mapping[c], sst); + mem_mapping_set_handler(&bios_high_mapping[c], + mem_read_bios, mem_read_biosw, mem_read_biosl, + sst_write, NULL, NULL); + mem_mapping_set_p(&bios_high_mapping[c], sst); + } + sst->id_mode = 0; +} + +static void *sst_39sf010_init() +{ + FILE *f; + sst_t *sst = malloc(sizeof(sst_t)); + memset(sst, 0, sizeof(sst_t)); + + switch(romset) + { + case ROM_XI8088: + strcpy(sst->flash_path, "xi8088/"); + break; + + case ROM_FIC_VA503P: + strcpy(sst->flash_path, "fic_va503p/"); + break; + + default: + fatal("sst_39sf010_init on unsupported ROM set %i\n", romset); + } + strcat(sst->flash_path, "flash.bin"); + f = romfopen(sst->flash_path, "rb"); + if (f) + { + switch(romset) + { + case ROM_XI8088: + if (xi8088_bios_128kb()) + fread(rom + 0x10000, 0x10000, 1, f); + fread(rom, 0x10000, 1, f); + break; + + case ROM_FIC_VA503P: + fread(rom, 0x20000, 1, f); + break; + + default: + fatal("sst_39sf010_init on unsupported ROM set %i\n", romset); + } + fclose(f); + } + memcpy(sst->data, rom, 0x20000); + + clear_id_mode(sst); + + return sst; +} + +static void sst_39sf010_close(void *p) +{ + sst_t *sst = (sst_t *)p; + + if (sst->dirty) + { + FILE *f = romfopen(sst->flash_path, "wb"); + switch(romset) + { + case ROM_XI8088: + if (xi8088_bios_128kb()) + fwrite(sst->data + 0x10000, 0x10000, 1, f); + fwrite(sst->data, 0x10000, 1, f); + break; + + case ROM_FIC_VA503P: + fwrite(sst->data, 0x20000, 1, f); + break; + + default: + fatal("sst_39sf010_init on unsupported ROM set %i\n", romset); + } + fclose(f); + } + + free(sst); +} + +device_t sst_39sf010_device = +{ + "SST 39SF010 Flash BIOS", + 0, + sst_39sf010_init, + sst_39sf010_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sst39sf010.h b/src/sst39sf010.h new file mode 100644 index 0000000..97d4a63 --- /dev/null +++ b/src/sst39sf010.h @@ -0,0 +1 @@ +extern device_t sst_39sf010_device; diff --git a/src/superxt.c b/src/superxt.c new file mode 100644 index 0000000..5c3bed4 --- /dev/null +++ b/src/superxt.c @@ -0,0 +1,60 @@ +/*This is the Chips and Technologies C82100 chipset used in the Amstrad PC5086 model*/ +#include "ibm.h" +#include "io.h" +#include "x86.h" +#include "superxt.h" + +static uint8_t superxt_regs[256]; +static int superxt_index; +static int superxt_emspage[4]; + +void superxt_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port) + { + case 0x22: + superxt_index = val; + break; + + case 0x23: + superxt_regs[superxt_index] = val; + + case 0x0208: case 0x4208: case 0x8208: case 0xC208: + superxt_emspage[port >> 14] = val; + break; + + // default: + // pclog("%04X:%04X SUPERXT WRITE : %04X, %02X\n", CS, cpu_state.pc, port, val); + } +} + +uint8_t superxt_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x22: + return superxt_index; + + case 0x23: + return superxt_regs[superxt_index]; + + case 0x0208: case 0x4208: case 0x8208: case 0xC208: + return superxt_emspage[port >> 14]; + + // default: + // pclog("%04X:%04X SUPERXT READ : %04X\n", CS, cpu_state.pc, port); + } + return 0xff; +} + +void superxt_init() +{ + /* Set register 0x42 to invalid configuration at startup */ + superxt_regs[0x42] = 0; + + io_sethandler(0x0022, 0x0002, superxt_read, NULL, NULL, superxt_write, NULL, NULL, NULL); + io_sethandler(0x0208, 0x0001, superxt_read, NULL, NULL, superxt_write, NULL, NULL, NULL); + io_sethandler(0x4208, 0x0001, superxt_read, NULL, NULL, superxt_write, NULL, NULL, NULL); + io_sethandler(0x8208, 0x0001, superxt_read, NULL, NULL, superxt_write, NULL, NULL, NULL); + io_sethandler(0xc208, 0x0001, superxt_read, NULL, NULL, superxt_write, NULL, NULL, NULL); +} diff --git a/src/superxt.h b/src/superxt.h new file mode 100644 index 0000000..f21eb6a --- /dev/null +++ b/src/superxt.h @@ -0,0 +1 @@ +void superxt_init(); diff --git a/src/t1000.c b/src/t1000.c new file mode 100644 index 0000000..aa8c959 --- /dev/null +++ b/src/t1000.c @@ -0,0 +1,700 @@ +#include +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "io.h" +#include "fdc.h" +#include "fdd.h" +#include "mouse.h" +#include "mem.h" +#include "nmi.h" +#include "nvr.h" +#include "nvr_tc8521.h" +#include "pit.h" +#include "device.h" +#include "keyboard_xt.h" +#include "vid_t1000.h" + +/* The T1000 is the T3100e's little brother -- a real laptop with a + * rechargeable battery. + * + * Features: 80C88 at 4.77MHz + * 512k system RAM + * 640x200 monochrome LCD + * 82-key keyboard + * Real-time clock. Not the normal 146818, but a TC8521, which + * is a 4-bit chip. + * A ROM drive (128k, 256k or 512k) which acts as a mini hard + * drive and contains a copy of DOS 2.11. + * 160 bytes of non-volatile RAM for the CONFIG.SYS used when + * booting from the ROM drive. Possibly physically located + * in the keyboard controller RAM. + * + * An optional memory expansion board can be fitted. This adds 768k of RAM, + * which can be used for up to three purposes: + * > Conventional memory -- 128k between 512k and 640k + * > HardRAM -- a battery-backed RAM drive. + * > EMS + * + * This means that there are up to three different implementations of + * non-volatile RAM in the same computer (52 nibbles in the TC8521, 160 + * bytes of CONFIG.SYS, and up to 768k of HardRAM). + * + * The T1200 is a slightly upgraded version with a turbo mode (double CPU + * clock, 9.54MHz) and an optional hard drive. The interface for this is + * proprietary both at the physical and programming level. + * + * 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb] or 0Dh [10Mb]. + * + */ + +void common_init(); + +uint8_t t1000_nvram[160]; +uint8_t t1200_nvram[2048]; + +static struct t1000_system +{ + /* ROM drive */ + uint8_t *romdrive; + uint8_t rom_ctl; + uint32_t rom_offset; + mem_mapping_t rom_mapping; + + /* System control registers */ + uint8_t sys_ctl[16]; + uint8_t syskeys; + uint8_t turbo; + + /* NVRAM control */ + uint8_t nvr_c0; + uint8_t nvr_tick; + int nvr_addr; + uint8_t nvr_active; + mem_mapping_t nvr_mapping; /* T1200 NVRAM mapping */ + + /* EMS data */ + uint8_t ems_reg[4]; + mem_mapping_t mapping[4]; + uint32_t page_exec[4]; + uint8_t ems_port_index; + uint16_t ems_port; + uint8_t is_640k; + uint32_t ems_base; + int32_t ems_pages; +} t1000; + +#define T1000_ROMSIZE (512 * 1024) /* Maximum ROM drive size is 512k */ + +/* The CONFIG.SYS storage (160 bytes) and battery-backed EMS (all RAM + * above 512k) are implemented as NVR devices */ + +void t1000_configsys_loadnvr() +{ + FILE *f; + + memset(t1000_nvram, 0x1A, sizeof(t1000_nvram)); + f = nvrfopen("t1000_config.nvr", "rb"); + if (f) + { + fread(t1000_nvram, sizeof(t1000_nvram), 1, f); + fclose(f); + } +} + +void t1200_state_loadnvr() +{ + FILE *f; + + memset(t1200_nvram, 0, sizeof(t1200_nvram)); + f = nvrfopen("t1200_state.nvr", "rb"); + if (f) + { + fread(t1200_nvram, sizeof(t1200_nvram), 1, f); + fclose(f); + } +} + + +/* All RAM beyond 512k is non-volatile */ +void t1000_emsboard_loadnvr() +{ + FILE *f; + + if (mem_size > 512) + { + f = nvrfopen("t1000_ems.nvr", "rb"); + if (f) + { + fread(&ram[512 * 1024], + 1024, (mem_size - 512), f); + fclose(f); + } + } +} + +void t1000_configsys_savenvr() +{ + FILE *f; + + f = nvrfopen("t1000_config.nvr", "wb"); + if (f) + { + fwrite(t1000_nvram, sizeof(t1000_nvram), 1, f); + fclose(f); + } +} + +void t1200_state_savenvr() +{ + FILE *f; + + f = nvrfopen("t1200_state.nvr", "wb"); + if (f) + { + fwrite(t1200_nvram, sizeof(t1200_nvram), 1, f); + fclose(f); + } +} + + + + +void t1000_emsboard_savenvr() +{ + FILE *f; + + if (mem_size > 512) + { + f = nvrfopen("t1000_ems.nvr", "wb"); + if (f) + { + fwrite(&ram[512 * 1024], + 1024, (mem_size - 512), f); + fclose(f); + } + } +} + + + +/* Given an EMS page ID, return its physical address in RAM. */ +uint32_t ems_execaddr(struct t1000_system *sys, int pg, uint16_t val) +{ + if (!(val & 0x80)) return 0; /* Bit 7 reset => not mapped */ + if (!sys->ems_pages) return 0; /* No EMS available: all used by + * HardRAM or conventional RAM */ + + val &= 0x7F; + +/* pclog("Select EMS page: %d of %d\n", val, sys->ems_pages); */ + if (val < sys->ems_pages) + { +/* EMS is any memory above 512k, with ems_base giving the start address */ + return (512 * 1024) + (sys->ems_base * 0x10000) + (0x4000 * val); + } + return 0; +} + + +static uint8_t ems_in(uint16_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + +/* pclog("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]); */ + return sys->ems_reg[(addr >> 14) & 3]; +} + +static void ems_out(uint16_t addr, uint8_t val, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + int pg = (addr >> 14) & 3; + +/* pclog("ems_out(%04x, %02x) pg=%d\n", addr, val, pg); */ + sys->ems_reg[pg] = val; + sys->page_exec[pg] = ems_execaddr(sys, pg, val); + if (sys->page_exec[pg]) /* Page present */ + { + mem_mapping_enable(&sys->mapping[pg]); + mem_mapping_set_exec(&sys->mapping[pg], ram + sys->page_exec[pg]); + } + else + { + mem_mapping_disable(&sys->mapping[pg]); + } +} + + +/* Hardram size is in 64k units */ +static void ems_set_hardram(struct t1000_system *sys, uint8_t val) +{ + int n; + + val &= 0x1F; /* Mask off pageframe address */ + if (val && mem_size > 512) + { + sys->ems_base = val; + } + else + { + sys->ems_base = 0; + } +/* pclog("EMS base set to %02x\n", val); */ + sys->ems_pages = ((mem_size - 512) / 16) - 4 * sys->ems_base; + if (sys->ems_pages < 0) sys->ems_pages = 0; + /* Recalculate EMS mappings */ + for (n = 0; n < 4; n++) + { + ems_out(n << 14, sys->ems_reg[n], sys); + } +} + + +static void ems_set_640k(struct t1000_system *sys, uint8_t val) +{ + if (val && mem_size >= 640) + { + mem_mapping_set_addr(&ram_low_mapping, 0, 640 * 1024); + sys->is_640k = 1; + } + else + { + mem_mapping_set_addr(&ram_low_mapping, 0, 512 * 1024); + sys->is_640k = 0; + } +} + +static void ems_set_port(struct t1000_system *sys, uint8_t val) +{ + int n; + +/* pclog("ems_set_port(%d)", val & 0x0F); */ + if (sys->ems_port) + { + for (n = 0; n <= 0xC000; n += 0x4000) + { + io_removehandler(sys->ems_port + n, 0x01, + ems_in, NULL, NULL, ems_out, NULL, NULL, sys); + } + sys->ems_port = 0; + } + val &= 0x0F; + sys->ems_port_index = val; + if (val == 7) /* No EMS */ + { + sys->ems_port = 0; + } + else + { + sys->ems_port = 0x208 | (val << 4); + for (n = 0; n <= 0xC000; n += 0x4000) + { + io_sethandler(sys->ems_port + n, 0x01, + ems_in, NULL, NULL, ems_out, NULL, NULL, sys); + } + sys->ems_port = 0; + } +/* pclog(" -> %04x\n", sys->ems_port); */ +} + +static int addr_to_page(uint32_t addr) +{ + return (addr - 0xD0000) / 0x4000; +} + +/* Read RAM in the EMS page frame */ +static uint8_t ems_read_ram(uint32_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + addr = sys->page_exec[pg] + (addr & 0x3FFF); + return ram[addr]; +} + + + + +static uint16_t ems_read_ramw(uint32_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + /* pclog("ems_read_ramw addr=%05x ", addr); */ + addr = sys->page_exec[pg] + (addr & 0x3FFF); + /* pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); */ + return *(uint16_t *)&ram[addr]; +} + + +static uint32_t ems_read_raml(uint32_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + addr = sys->page_exec[pg] + (addr & 0x3FFF); + return *(uint32_t *)&ram[addr]; +} + +/* Write RAM in the EMS page frame */ +static void ems_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + addr = sys->page_exec[pg] + (addr & 0x3FFF); + if (ram[addr] != val) nvr_dosave = 1; + ram[addr] = val; +} + + +static void ems_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + /* pclog("ems_write_ramw addr=%05x ", addr); */ + addr = sys->page_exec[pg] + (addr & 0x3FFF); + /* pclog("-> %06x val=%04x\n", addr, val); */ + + if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; + *(uint16_t *)&ram[addr] = val; +} + + +static void ems_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + addr = sys->page_exec[pg] + (addr & 0x3FFF); + if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; + *(uint32_t *)&ram[addr] = val; +} + + + + + +void t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask) +{ + t1000.syskeys &= ~andmask; + t1000.syskeys |= ormask; + t1000.syskeys ^= xormask; +} + + + +static uint8_t read_t1000_ctl(uint16_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + + switch (addr & 0x0F) + { + case 1: return sys->syskeys; +/* Detect EMS board */ + case 0x0F: switch (sys->sys_ctl[0x0E]) + { + case 0x50: if (mem_size <= 512) + return 0xFF; + return 0x90 | sys->ems_port_index; +/* 0x60 is the page frame address: (0xD000 - 0xC400) / 0x20 */ + case 0x51: return sys->ems_base | 0x60; + case 0x52: return sys->is_640k ? 0x80 : 0; + } + return 0xFF; + default: return sys->sys_ctl[addr & 0x0F]; + } +} + +static void t1200_turbo_set(uint8_t value) +{ + if (value == t1000.turbo) + { + return; + } + t1000.turbo = value; + if (!value) + cpu_set_turbo(0); + else + cpu_set_turbo(1); +} + +static void write_t1000_ctl(uint16_t addr, uint8_t val, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + + sys->sys_ctl[addr & 0x0F] = val; + switch (addr & 0x0F) + { + /* Video control */ + case 4: if (sys->sys_ctl[3] == 0x5A) + { + t1000_video_options_set((val & 0x20) ? 1 : 0); + t1000_display_set((val & 0x40) ? 0 : 1); + if (romset == ROM_T1200) + { + t1200_turbo_set((val & 0x80) ? 1 : 0); + } + } + break; + /* It looks as if the T1200, like the T3100, can disable + * its builtin video chipset if it detects the presence of + * another video card. */ + case 6: if (romset == ROM_T1200) + { + t1000_video_enable(val & 0x01 ? 0 : 1); + } + break; + /* EMS control*/ + case 0x0F: + switch (sys->sys_ctl[0x0E]) + { + case 0x50: ems_set_port(sys, val); break; + case 0x51: ems_set_hardram(sys, val); break; + case 0x52: ems_set_640k(sys, val); break; + } + break; + + } +} + +/* Ports 0xC0 to 0xC3 appear to have two purposes: + * + * > Access to the 160 bytes of non-volatile RAM containing CONFIG.SYS + * > Reading the floppy changeline. I don't know why the Toshiba doesn't + * use the normal port 0x3F7 for this, but it doesn't. + * + */ +static uint8_t read_t1000_nvram(uint16_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + uint8_t tmp; + + switch (addr) + { + case 0xC2: /* Read next byte from NVRAM */ + tmp = 0xFF; + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) + tmp = t1000_nvram[sys->nvr_addr]; + ++sys->nvr_addr; + return tmp; + + case 0xC3: /* Read floppy changeline and NVRAM ready state */ + tmp = fdc_read(0x3F7, NULL); + + tmp = (tmp & 0x80) >> 3; /* Bit 4 is changeline */ + tmp |= (sys->nvr_active & 0xC0);/* Bits 6,7 are r/w mode */ + tmp |= 0x2E; /* Bits 5,3,2,1 always 1 */ + tmp |= (sys->nvr_active & 0x40) >> 6; /* Ready state */ + return tmp; + } + return 0xFF; +} + +static void write_t1000_nvram(uint16_t addr, uint8_t val, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + + switch (addr) + { +/* On the real T1000, port 0xC1 is only usable as the high byte of a 16-bit + * write to port 0xC0, with 0x5A in the low byte. */ + case 0xC0: sys->nvr_c0 = val; + break; +/* Write next byte to NVRAM */ + case 0xC1: if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) + { + if (t1000_nvram[sys->nvr_addr] != val) + nvr_dosave = 1; + t1000_nvram[sys->nvr_addr] = val; + } + ++sys->nvr_addr; + break; + case 0xC2: break; +/* At start of NVRAM read / write, 0x80 is written to port 0xC3. This seems + * to reset the NVRAM address counter. A single byte is then written (0xFF + * for write, 0x00 for read) which appears to be ignored. Simulate that by + * starting the address counter off at -1 */ + case 0xC3: sys->nvr_active = val; + if (val == 0x80) sys->nvr_addr = -1; + break; + } +} + +/* Port 0xC8 controls the ROM drive */ +static uint8_t read_t1000_rom_ctl(uint16_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + + return sys->rom_ctl; +} + +static void write_t1000_rom_ctl(uint16_t addr, uint8_t val, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + + sys->rom_ctl = val; + if (sys->romdrive && (val & 0x80)) /* Enable */ + { + sys->rom_offset = ((val & 0x7F) * 0x10000) % T1000_ROMSIZE; + mem_mapping_set_addr(&sys->rom_mapping, 0xA0000, 0x10000); + mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + + sys->rom_offset); + mem_mapping_enable(&sys->rom_mapping); + } + else + { + mem_mapping_disable(&sys->rom_mapping); + } +} + + +/* Read the ROM drive */ +static uint8_t t1000_read_rom(uint32_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + + if (!sys->romdrive) return 0xFF; + return sys->romdrive[sys->rom_offset + (addr & 0xFFFF)]; +} + +static uint16_t t1000_read_romw(uint32_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + + if (!sys->romdrive) return 0xFFFF; + return *(uint16_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xFFFF)]); +} + + +static uint32_t t1000_read_roml(uint32_t addr, void *priv) +{ + struct t1000_system *sys = (struct t1000_system *)priv; + + if (!sys->romdrive) return 0xFFFFFFFF; + return *(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xFFFF)]); +} + +static uint8_t read_t1200_nvram(uint32_t addr, void *priv) +{ + return t1200_nvram[addr & 0x7FF]; +} + +static void write_t1200_nvram(uint32_t addr, uint8_t value, void *priv) +{ + if (t1200_nvram[addr & 0x7FF] != value) + { + nvr_dosave = 1; + } + t1200_nvram[addr & 0x7FF] = value; +} + +void xt_t1000_init() +{ + FILE *f; + int pg; + + memset(&t1000, 0, sizeof(t1000)); + t1000.turbo = 0xff; + t1000.ems_port_index = 7; /* EMS disabled */ +/* The ROM drive is optional. If the file is missing, continue to boot; the + * BIOS will complain 'No ROM drive' but boot normally from floppy. */ + + f = romfopen("t1000/t1000dos.rom", "rb"); + if (f) + { + t1000.romdrive = malloc(T1000_ROMSIZE); + if (t1000.romdrive) + { + memset(t1000.romdrive, 0xFF, T1000_ROMSIZE); + fread(t1000.romdrive, T1000_ROMSIZE, 1, f); + } + fclose(f); + } + mem_mapping_add(&t1000.rom_mapping, 0xA0000, 0x10000, + t1000_read_rom, t1000_read_romw, t1000_read_roml, + NULL, NULL, NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); + mem_mapping_disable(&t1000.rom_mapping); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) + { + mem_mapping_add(&t1000.mapping[pg], + 0xD0000 + (0x4000 * pg), 16384, + ems_read_ram, ems_read_ramw, ems_read_raml, + ems_write_ram, ems_write_ramw, ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, + &t1000); + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* Non-volatile RAM for CONFIG.SYS */ + io_sethandler(0xC0, 4, read_t1000_nvram, NULL, NULL, + write_t1000_nvram, NULL, NULL, &t1000); + /* ROM drive */ + io_sethandler(0xC8, 1, read_t1000_rom_ctl, NULL, NULL, + write_t1000_rom_ctl, NULL, NULL, &t1000); + /* System control functions, and add-on memory board */ + io_sethandler(0xE0, 0x10, read_t1000_ctl, NULL, NULL, + write_t1000_ctl, NULL, NULL, &t1000); + + common_init(); + mem_add_bios(); + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + keyboard_xt_init(); + nmi_init(); + nvr_tc8521_init(); +/* No gameport, and no provision to fit one device_add(&gameport_device); */ +} + + +void xt_t1200_init() +{ + int pg; + + memset(&t1000, 0, sizeof(t1000)); + t1000.ems_port_index = 7; /* EMS disabled */ + + mem_mapping_add(&t1000.rom_mapping, 0xA0000, 0x10000, + t1000_read_rom, t1000_read_romw, t1000_read_roml, + NULL, NULL, NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); + mem_mapping_disable(&t1000.rom_mapping); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) + { + mem_mapping_add(&t1000.mapping[pg], + 0xD0000 + (0x4000 * pg), 16384, + ems_read_ram, ems_read_ramw, ems_read_raml, + ems_write_ram, ems_write_ramw, ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, + &t1000); + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* System control functions, and add-on memory board */ + io_sethandler(0xE0, 0x10, read_t1000_ctl, NULL, NULL, + write_t1000_ctl, NULL, NULL, &t1000); + + common_init(); + mem_add_bios(); + mem_mapping_add(&t1000.nvr_mapping, + 0xF0000, 2048, read_t1200_nvram, NULL, NULL, + write_t1200_nvram, NULL, NULL, + NULL, 0, &t1000); + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + keyboard_xt_init(); + nmi_init(); + nvr_tc8521_init(); +/* No gameport, and no provision to fit one device_add(&gameport_device); */ +} + diff --git a/src/t1000.h b/src/t1000.h new file mode 100644 index 0000000..f822fc8 --- /dev/null +++ b/src/t1000.h @@ -0,0 +1,9 @@ +void t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask); + +void t1000_configsys_loadnvr(); +void t1000_emsboard_loadnvr(); +void t1200_state_loadnvr(); + +void t1000_configsys_savenvr(); +void t1000_emsboard_savenvr(); +void t1200_state_savenvr(); diff --git a/src/t3100e.c b/src/t3100e.c new file mode 100644 index 0000000..5456c23 --- /dev/null +++ b/src/t3100e.c @@ -0,0 +1,708 @@ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "io.h" +#include "fdd.h" +#include "mouse.h" +#include "mem.h" +#include "device.h" +#include "t3100e.h" +#include "vid_t3100e.h" + +/* The Toshiba 3100e is a 286-based portable. + * + * To bring up the BIOS setup screen hold down the 'Fn' key on booting + * + * Memory management + * ~~~~~~~~~~~~~~~~~ + * + * Motherboard memory is divided into: + * - Conventional memory: Either 512k or 640k + * - Upper memory: Either 512k or 384k, depending on amount of + * conventional memory. Upper memory can be + * used either as EMS or XMS. + * - High memory: 0-4Mb, depending on RAM installed. The BIOS + * setup screen allows some or all of this to be + * used as EMS; the remainder is XMS. + * + * Additional memory (either EMS or XMS) can also be provided by ISA + * expansion cards. + * + * Under test in PCEM, the BIOS will boot with up to 65368Kb of memory in + * total (16Mb less 16k). However it will give an error with RAM sizes + * above 8Mb, if any of the high memory is allocated as EMS, because the + * builtin EMS page registers can only access up to 8Mb. + * + * Memory is controlled by writes to I/O port 8084h: + * Bit 7: Always 0 } + * Bit 6: Always 1 } These bits select which motherboard function to + * Bit 5: Always 0 } access. + * Bit 4: Set to treat upper RAM as XMS + * Bit 3: Enable external RAM boards? + * Bit 2: Set for 640k conventional memory, clear for 512k + * Bit 1: Enable RAM beyond 1Mb. + * Bit 0: Enable EMS. + * + * The last value written to this port is saved at 0040:0093h, and in + * CMOS memory at offset 0x37. If the top bit of the CMOS byte is set, + * then high memory is being provided by an add-on card rather than the + * mainboard; accordingly, the BIOS will not allow high memory to be + * used as EMS. + * + * EMS is controlled by 16 page registers: + * + * Page mapped at 0xD000 0xD400 0xD800 0xDC00 + * ------------------------------------------------------ + * Pages 0x00-0x7F 0x208 0x4208 0x8208 0xc208 + * Pages 0x80-0xFF 0x218 0x4218 0x8218 0xc218 + * Pages 0x100-0x17F 0x258 0x4258 0x8258 0xc258 + * Pages 0x180-0x1FF 0x268 0x4268 0x8268 0xc268 + * + * The value written has bit 7 set to enable EMS, reset to disable it. + * + * So: OUT 0x208, 0x80 will page in the first 16k page at 0xD0000. + * OUT 0x208, 0x00 will page out EMS, leaving nothing at 0xD0000. + * OUT 0x4208, 0x80 will page in the first 16k page at 0xD4000. + * OUT 0x218, 0x80 will page in the 129th 16k page at 0xD0000. + * + * etc. + * + * To use EMS from DOS, you will need the Toshiba EMS driver (TOSHEMM.ZIP). + * This supports the above system, plus further ranges of ports at + * 0x_2A8, 0x_2B8, 0x_2C8. + * + */ + +static const int t3100e_log = 0; + +extern uint8_t *ram; /* Physical RAM */ + +/* Features not implemented: + * > Four video fonts. + * > BIOS-controlled mapping of serial ports to IRQs. + * > Custom keyboard controller. This has a number of extra commands in the + * 0xB0-0xBC range, for such things as turbo on/off, and switching the + * keyboard between AT and PS/2 modes. Currently I have only implemented + * command 0xBB, so that self-test completes successfully. Commands include: + * + * 0xB0: Turbo on + * 0xB1: Turbo off + * 0xB2: Internal display on? + * 0xB3: Internal display off? + * 0xB5: Get settings byte (bottom bit is colour / mono setting) + * 0xB6: Set settings byte + * 0xB7: Behave as 101-key PS/2 keyboard + * 0xB8: Behave as 84-key AT keyboard + * 0xBB: Return a byte, bit 2 is Fn key state, other bits unknown. + * + * The other main I/O port needed to POST is: + * 0x8084: System control. + * Top 3 bits give command, bottom 5 bits give parameters. + * 000 => set serial port IRQ / addresses + * bit 4: IRQ5 serial port base: 1 => 0x338, 0 => 0x3E8 + * bits 3, 2, 0 specify serial IRQs for COM1, COM2, COM3: + * 00 0 => 4, 3, 5 + * 00 1 => 4, 5, 3 + * 01 0 => 3, 4, 5 + * 01 1 => 3, 5, 4 + * 10 0 => 4, -, 3 + * 10 1 => 3, -, 4 + * 010 => set memory mappings + * bit 4 set if upper RAM is XMS + * bit 3 enable add-on memory boards beyond 5Mb? + * bit 2 set for 640k sysram, clear for 512k sysram + * bit 1 enable mainboard XMS + * bit 0 enable mainboard EMS + * 100 => set parallel mode / LCD settings + * bit 4 set for bidirectional parallel port + * bit 3 set to disable internal CGA + * bit 2 set for single-pixel LCD font + * bits 0,1 for display font + */ + +void at_init(); + +/* The T3100e motherboard can (and does) dynamically reassign RAM between + * conventional, XMS and EMS. This translates to monkeying with the mappings. + */ + +extern mem_mapping_t base_mapping; + +extern mem_mapping_t ram_low_mapping; /* This is to switch conventional RAM + * between 512k and 640k */ + +extern mem_mapping_t ram_mid_mapping; /* This will not be used */ + +extern mem_mapping_t ram_high_mapping; /* This is RAM beyond 1Mb if any */ + +extern mem_mapping_t ram_remapped_mapping; /* This will not be used */ + +extern uint8_t *ram; + +static unsigned t3100e_ems_page_reg[] = +{ + 0x208, 0x4208, 0x8208, 0xc208, /* The first four map the first 2Mb */ + /* of RAM into the page frame */ + 0x218, 0x4218, 0x8218, 0xc218, /* The next four map the next 2Mb */ + /* of RAM */ + 0x258, 0x4258, 0x8258, 0xc258, /* and so on. */ + 0x268, 0x4268, 0x8268, 0xc268, +}; + +struct t3100e_ems_regs +{ + uint8_t page[16]; + mem_mapping_t mapping[4]; + uint32_t page_exec[4]; /* Physical location of memory pages */ + uint32_t upper_base; /* Start of upper RAM */ + uint8_t upper_pages; /* Pages of EMS available from upper RAM */ + uint8_t upper_is_ems; /* Upper RAM is EMS? */ + mem_mapping_t upper_mapping; + uint8_t notify; /* Notification from keyboard controller */ + uint8_t turbo; /* 0 for 6MHz, else full speed */ + uint8_t mono; /* Emulates PC/AT 'mono' motherboard switch */ + /* Bit 0 is 0 for colour, 1 for mono */ +} t3100e_ems; + +void t3100e_ems_out(uint16_t addr, uint8_t val, void *p); + + +/* Given a memory address (which ought to be in the page frame at 0xD0000), + * which page does it relate to? */ +static int addr_to_page(uint32_t addr) +{ + if ((addr & 0xF0000) == 0xD0000) + { + return ((addr >> 14) & 3); + } + return -1; +} + +/* And vice versa: Given a page slot, which memory address does it + * correspond to? */ +static uint32_t page_to_addr(int pg) +{ + return 0xD0000 + ((pg & 3) * 16384); +} + +/* Given an EMS page ID, return its physical address in RAM. */ +uint32_t t3100e_ems_execaddr(struct t3100e_ems_regs *regs, + int pg, uint16_t val) +{ + uint32_t addr; + + if (!(val & 0x80)) return 0; /* Bit 7 reset => not mapped */ + + val &= 0x7F; + val += (0x80 * (pg >> 2)); /* The high bits of the register bank */ + /* are used to extend val to allow up */ + /* to 8Mb of EMS to be accessed */ + + /* Is it in the upper memory range? */ + if (regs->upper_is_ems) + { + if (val < regs->upper_pages) + { + addr = regs->upper_base + 0x4000 * val; + return addr; + } + val -= regs->upper_pages; + } + /* Otherwise work down from the top of high RAM (so, the more EMS, + * the less XMS) */ + if ((val * 0x4000) + 0x100000 >= (mem_size * 1024)) + { + return 0; /* Not enough high RAM for this page */ + } + /* High RAM found */ + addr = (mem_size * 1024) - 0x4000 * (val + 1); + + return addr; +} + + +/* The registers governing the EMS ports are in rather a nonintuitive order */ +static int port_to_page(uint16_t addr) +{ + switch (addr) + { + case 0x208: return 0; + case 0x4208: return 1; + case 0x8208: return 2; + case 0xC208: return 3; + case 0x218: return 4; + case 0x4218: return 5; + case 0x8218: return 6; + case 0xC218: return 7; + case 0x258: return 8; + case 0x4258: return 9; + case 0x8258: return 10; + case 0xC258: return 11; + case 0x268: return 12; + case 0x4268: return 13; + case 0x8268: return 14; + case 0xC268: return 15; + } + return -1; +} + +/* Used to dump the memory mapping table, for debugging +void dump_mappings() +{ + mem_mapping_t *mm = base_mapping.next; + + if (!t3100e_log) return; + while (mm) + { + const char *name = ""; + uint32_t offset = (uint32_t)(mm->exec - ram); + + if (mm == &ram_low_mapping ) name = "LOW "; + if (mm == &ram_mid_mapping ) name = "MID "; + if (mm == &ram_high_mapping) name = "HIGH"; + if (mm == &t3100e_ems.upper_mapping) name = "UPPR"; + if (mm == &t3100e_ems.mapping[0]) + { + name = "EMS0"; + offset = t3100e_ems.page_exec[0]; + } + if (mm == &t3100e_ems.mapping[1]) + { + name = "EMS1"; + offset = t3100e_ems.page_exec[1]; + } + if (mm == &t3100e_ems.mapping[2]) + { + name = "EMS2"; + offset = t3100e_ems.page_exec[2]; + } + if (mm == &t3100e_ems.mapping[3]) + { + name = "EMS3"; + offset = t3100e_ems.page_exec[3]; + } + + pclog(" %p | base=%05x size=%05x %c @ %06x %s\n", mm, + mm->base, mm->size, mm->enable ? 'Y' : 'N', + offset, name); + + mm = mm->next; + } +}*/ + +void t3100e_map_ram(uint8_t val) +{ + int n; + int32_t upper_len; + + if (t3100e_log) + { + pclog("OUT 0x8084, %02x [ set memory mapping :", val | 0x40); + if (val & 1) pclog("ENABLE_EMS "); + if (val & 2) pclog("ENABLE_XMS "); + if (val & 4) pclog("640K "); + if (val & 8) pclog("X8X "); + if (val & 16) pclog("UPPER_IS_XMS "); + pclog("\n"); + } + /* Bit 2 controls size of conventional memory */ + if (val & 4) + { + t3100e_ems.upper_base = 0xA0000; + t3100e_ems.upper_pages = 24; + } + else + { + t3100e_ems.upper_base = 0x80000; + t3100e_ems.upper_pages = 32; + } + upper_len = t3100e_ems.upper_pages * 16384; + + mem_mapping_set_addr(&ram_low_mapping, 0, t3100e_ems.upper_base); + /* Bit 0 set if upper RAM is EMS */ + t3100e_ems.upper_is_ems = (val & 1); + + /* Bit 1 set if high RAM is enabled */ + if (val & 2) + { + mem_mapping_enable(&ram_high_mapping); + } + else + { + mem_mapping_disable(&ram_high_mapping); + } + + /* Bit 4 set if upper RAM is mapped to high memory + * (and bit 1 set if XMS enabled) */ + if ((val & 0x12) == 0x12) + { + mem_mapping_set_addr(&t3100e_ems.upper_mapping, + mem_size * 1024, + upper_len); + mem_mapping_enable(&t3100e_ems.upper_mapping); + mem_mapping_set_exec(&t3100e_ems.upper_mapping, ram + t3100e_ems.upper_base); + } + else + { + mem_mapping_disable(&t3100e_ems.upper_mapping); + } + /* Recalculate EMS mappings */ + for (n = 0; n < 4; n++) + { + t3100e_ems_out(t3100e_ems_page_reg[n], t3100e_ems.page[n], + &t3100e_ems); + } + + //dump_mappings(); +} + + +void t3100e_notify_set(uint8_t value) +{ + t3100e_ems.notify = value; +} + +void t3100e_mono_set(uint8_t value) +{ + t3100e_ems.mono = value; +} + +uint8_t t3100e_mono_get(void) +{ + return t3100e_ems.mono; +} + +void t3100e_turbo_set(uint8_t value) +{ + t3100e_ems.turbo = value; + if (!value) + cpu_set_turbo(0); + else + cpu_set_turbo(1); +} + + + +uint8_t t3100e_sys_in(uint16_t addr, void *p) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + + /* The low 4 bits always seem to be 0x0C. The high 4 are a + * notification sent by the keyboard controller when it detects + * an [Fn] key combination */ + if (t3100e_log) pclog("IN 0x8084\n"); + return 0x0C | (regs->notify << 4); +} + + + +/* Handle writes to the T3100e system control port at 0x8084 */ +void t3100e_sys_out(uint16_t addr, uint8_t val, void *p) +{ +// struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + + switch (val & 0xE0) + { + case 0x00: /* Set serial port IRQs. Not implemented */ + if (t3100e_log) pclog("OUT 0x8084, %02x [ set serial port IRQs]\n", val); + break; + case 0x40: /* Set RAM mappings. */ + t3100e_map_ram(val & 0x1F); + break; + + case 0x80: /* Set video options. */ + t3100e_video_options_set(val & 0x1F); break; + + /* Other options not implemented. */ + default: if (t3100e_log) pclog("OUT 0x8084, %02x\n", val); break; + } +} + + +uint8_t t3100e_config_get(void) +{ +/* The byte returned: + Bit 7: Set if internal plasma display enabled + Bit 6: Set if running at 6MHz, clear at full speed + Bit 5: Always 1? + Bit 4: Set if the FD2MB jumper is present (internal floppy is ?tri-mode) + Bit 3: Clear if the FD2 jumper is present (two internal floppies) + Bit 2: Set if the internal drive is A:, clear if B: + Bit 1: Set if the parallel port is configured as a floppy connector + for the second drive. + Bit 0: Set if the F2HD jumper is present (internal floppy is 720k) + */ + uint8_t value = 0x28; /* Start with bits 5 and 3 set. */ + + int type_a = fdd_get_type(0); + int type_b = fdd_get_type(1); + int prt_switch; /* External drive type: 0=> none, 1=>A, 2=>B */ + +/* Get display setting */ + if (t3100e_display_get()) value |= 0x80; + if (!t3100e_ems.turbo) value |= 0x40; + +/* Try to determine the floppy types.*/ + + prt_switch = (type_b ? 2 : 0); + switch(type_a) + { +/* Since a T3100e cannot have an internal 5.25" drive, mark 5.25" A: drive as + * being external, and set the internal type based on type_b. */ + case 1: /* 360k */ + case 2: /* 1.2Mb */ + case 3: /* 1.2Mb RPMx2*/ + prt_switch = 1; /* External drive is A: */ + switch (type_b) + { + case 1: /* 360k */ + case 4: value |= 1; break; /* 720k */ + case 6: value |= 0x10; break; /* Tri-mode */ + /* All others will be treated as 1.4M */ + } + break; + case 4: value |= 0x01; /* 720k */ + if (type_a == type_b) + { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + case 5: /* 1.4M */ + case 7: /* 2.8M */ + if (type_a == type_b) + { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + case 6: /* 3-mode */ + value |= 0x10; + if (type_a == type_b) + { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + } /* End switch */ + switch (prt_switch) + { + case 0: value |= 4; break; /* No external floppy */ + case 1: value |= 2; break; /* External floppy is A: */ + case 2: value |= 6; break; /* External floppy is B: */ + } + return value; +} + + +/* Read EMS page register */ +uint8_t t3100e_ems_in(uint16_t addr, void *p) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + + return regs->page[port_to_page(addr)]; + +} + +/* Write EMS page register */ +void t3100e_ems_out(uint16_t addr, uint8_t val, void *p) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + int pg = port_to_page(addr); + + regs->page_exec[pg & 3] = t3100e_ems_execaddr(regs, pg, val); + if (t3100e_log) pclog("EMS: page %d %02x -> %02x [%06x]\n", + pg, regs->page[pg], val, regs->page_exec[pg & 3]); + regs->page[pg] = val; + + pg &= 3; +/* Bit 7 set if page is enabled, reset if page is disabled */ + if (regs->page_exec[pg]) + { + if (t3100e_log) pclog("Enabling EMS RAM at %05x\n", + page_to_addr(pg)); + mem_mapping_enable(®s->mapping[pg]); + mem_mapping_set_exec(®s->mapping[pg], ram + regs->page_exec[pg]); + } + else + { + if (t3100e_log) pclog("Disabling EMS RAM at %05x\n", + page_to_addr(pg)); + mem_mapping_disable(®s->mapping[pg]); + } +} + + +/* Read RAM in the EMS page frame */ +static uint8_t ems_read_ram(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + return ram[addr]; +} + + + + +static uint16_t ems_read_ramw(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + //pclog("ems_read_ramw addr=%05x ", addr); + addr = regs->page_exec[pg] + (addr & 0x3FFF); + //pclog("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); + return *(uint16_t *)&ram[addr]; +} + + +static uint32_t ems_read_raml(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + return *(uint32_t *)&ram[addr]; +} + +/* Write RAM in the EMS page frame */ +static void ems_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + ram[addr] = val; +} + + +static void ems_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + //pclog("ems_write_ramw addr=%05x ", addr); + addr = regs->page_exec[pg] + (addr & 0x3FFF); + //pclog("-> %06x val=%04x\n", addr, val); + + *(uint16_t *)&ram[addr] = val; +} + + +static void ems_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + *(uint32_t *)&ram[addr] = val; +} + + + +/* Read RAM in the upper area. This is basically what the 'remapped' + * mapping in mem.c does, except that the upper area can move around */ +static uint8_t upper_read_ram(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return ram[addr]; +} + +static uint16_t upper_read_ramw(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return *(uint16_t *)&ram[addr]; +} + +static uint32_t upper_read_raml(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return *(uint32_t *)&ram[addr]; +} + + +static void upper_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + ram[addr] = val; +} + + +static void upper_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + *(uint16_t *)&ram[addr] = val; +} + + + +static void upper_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + *(uint32_t *)&ram[addr] = val; +} + + + + +void at_t3100e_init() +{ + int pg; + + memset(&t3100e_ems, 0, sizeof(t3100e_ems)); + + at_init(); + /* Hook up system control port */ + io_sethandler(0x8084, 0x0001, + t3100e_sys_in, NULL, NULL, + t3100e_sys_out, NULL, NULL, &t3100e_ems); + + /* Start monitoring all 16 EMS registers */ + for (pg = 0; pg < 16; pg++) + { + io_sethandler(t3100e_ems_page_reg[pg], 0x0001, + t3100e_ems_in, NULL, NULL, + t3100e_ems_out, NULL, NULL, &t3100e_ems); + } + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) + { + if (t3100e_log) pclog("Adding memory map at %x for page %d\n", page_to_addr(pg), pg); + mem_mapping_add(&t3100e_ems.mapping[pg], + page_to_addr(pg), 16384, + ems_read_ram, ems_read_ramw, ems_read_raml, + ems_write_ram, ems_write_ramw, ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, + &t3100e_ems); + /* Start them all off disabled */ + mem_mapping_disable(&t3100e_ems.mapping[pg]); + } + /* Mapping for upper RAM when in use as XMS*/ + mem_mapping_add(&t3100e_ems.upper_mapping, mem_size * 1024, 384 * 1024, + upper_read_ram, upper_read_ramw, upper_read_raml, + upper_write_ram, upper_write_ramw, upper_write_raml, + NULL, MEM_MAPPING_INTERNAL, &t3100e_ems); + mem_mapping_disable(&t3100e_ems.upper_mapping); + mem_mapping_disable(&ram_remapped_mapping); +} diff --git a/src/t3100e.h b/src/t3100e.h new file mode 100644 index 0000000..ab41153 --- /dev/null +++ b/src/t3100e.h @@ -0,0 +1,7 @@ +void t3100e_notify_set(uint8_t value); +void t3100e_display_set(uint8_t value); +uint8_t t3100e_display_get(); +uint8_t t3100e_config_get(); +void t3100e_turbo_set(uint8_t value); +uint8_t t3100e_mono_get(); +void t3100e_mono_set(uint8_t value); diff --git a/src/tandy_eeprom.c b/src/tandy_eeprom.c index a29e272..0682a52 100644 --- a/src/tandy_eeprom.c +++ b/src/tandy_eeprom.c @@ -3,6 +3,7 @@ #include "io.h" #include "device.h" #include "tandy_eeprom.h" +#include "nvr.h" typedef struct { @@ -126,10 +127,10 @@ void *tandy_eeprom_init() switch (romset) { case ROM_TANDY1000HX: - f = romfopen("nvr/tandy1000hx.bin" ,"rb"); + f = nvrfopen("tandy1000hx.bin" ,"rb"); break; case ROM_TANDY1000SL2: - f = romfopen("nvr/tandy1000sl2.bin" ,"rb"); + f = nvrfopen("tandy1000sl2.bin" ,"rb"); break; } if (f) @@ -153,10 +154,10 @@ void tandy_eeprom_close(void *p) switch (eeprom->romset) { case ROM_TANDY1000HX: - f = romfopen("nvr/tandy1000hx.bin" ,"wb"); + f = nvrfopen("tandy1000hx.bin" ,"wb"); break; case ROM_TANDY1000SL2: - f = romfopen("nvr/tandy1000sl2.bin" ,"wb"); + f = nvrfopen("tandy1000sl2.bin" ,"wb"); break; } fwrite(eeprom->store, 128, 1, f); diff --git a/src/tandy_rom.c b/src/tandy_rom.c index becf8d7..df49d87 100644 --- a/src/tandy_rom.c +++ b/src/tandy_rom.c @@ -56,8 +56,8 @@ void *tandy_rom_init() tandy_rom = malloc(0x80000); - f = romfopen("roms/tandy1000sl2/8079047.hu1" ,"rb"); - ff = romfopen("roms/tandy1000sl2/8079048.hu2","rb"); + f = romfopen("tandy1000sl2/8079047.hu1" ,"rb"); + ff = romfopen("tandy1000sl2/8079048.hu2","rb"); for (c = 0x0000; c < 0x80000; c += 2) { tandy_rom[c] = getc(f); diff --git a/src/thread.h b/src/thread.h index fb47f28..0fe75aa 100644 --- a/src/thread.h +++ b/src/thread.h @@ -9,4 +9,10 @@ void thread_reset_event(event_t *_event); int thread_wait_event(event_t *event, int timeout); void thread_destroy_event(event_t *_event); +typedef void mutex_t; +mutex_t *thread_create_mutex(void); +void thread_lock_mutex(mutex_t *mutex); +void thread_unlock_mutex(mutex_t *mutex); +void thread_destroy_mutex(mutex_t *mutex); + void thread_sleep(int t); diff --git a/src/timer.c b/src/timer.c index 964e19a..a999d4f 100644 --- a/src/timer.c +++ b/src/timer.c @@ -1,117 +1,134 @@ #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 +uint64_t TIMER_USEC; +uint32_t timer_target; -int TIMER_USEC; +/*Enabled timers are stored in a linked list, with the first timer to expire at + the head.*/ +static pc_timer_t *timer_head = NULL; -static struct +void timer_enable(pc_timer_t *timer) { - int present; - void (*callback)(void *priv); - void *priv; - int *enable; - int *count; -} timers[TIMERS_MAX]; + pc_timer_t *timer_node = timer_head; -int timers_present = 0; -int timer_one = 1; - -int timer_count = 0, timer_latch = 0; -int timer_start = 0; +// pclog("timer->enable %p %i\n", timer, timer->enabled); + if (timer->enabled) + timer_disable(timer); + + if (timer->next || timer->prev) + fatal("timer_enable - timer->next\n"); + + timer->enabled = 1; + + /*List currently empty - add to head*/ + if (!timer_head) + { + timer_head = timer; + timer->next = timer->prev = NULL; + timer_target = timer_head->ts_integer; + return; + } + + timer_node = timer_head; + + while (1) + { + /*Timer expires before timer_node. Add to list in front of timer_node*/ + if (TIMER_LESS_THAN(timer, timer_node)) + { + timer->next = timer_node; + timer->prev = timer_node->prev; + timer_node->prev = timer; + if (timer->prev) + timer->prev->next = timer; + else + { + timer_head = timer; + timer_target = timer_head->ts_integer; + } + return; + } + + /*timer_node is last in the list. Add timer to end of list*/ + if (!timer_node->next) + { + timer_node->next = timer; + timer->prev = timer_node; + return; + } + + timer_node = timer_node->next; + } +} +void timer_disable(pc_timer_t *timer) +{ +// pclog("timer->disable %p\n", timer); + if (!timer->enabled) + return; + + if (!timer->next && !timer->prev && timer != timer_head) + fatal("timer_disable - !timer->next\n"); + + timer->enabled = 0; + + if (timer->prev) + timer->prev->next = timer->next; + else + timer_head = timer->next; + if (timer->next) + timer->next->prev = timer->prev; + timer->prev = timer->next = NULL; +} +static void timer_remove_head() +{ + if (timer_head) + { + pc_timer_t *timer = timer_head; +// pclog("timer_remove_head %p %p\n", timer_head, timer_head->next); + timer_head = timer->next; + timer_head->prev = NULL; + timer->next = timer->prev = NULL; + timer->enabled = 0; + } +} void timer_process() { - int c; - int process = 0; - /*Get actual elapsed time*/ - int diff = timer_latch - timer_count; - int enable[TIMERS_MAX]; + if (!timer_head) + return; - 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++) + while (1) { - if (*timers[c].enable && *timers[c].count < timer_latch) - timer_latch = *timers[c].count; + pc_timer_t *timer = timer_head; + + if (!TIMER_LESS_THAN_VAL(timer, (uint32_t)tsc)) + break; + + timer_remove_head(); + timer->callback(timer->p); } - timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1)) >> TIMER_SHIFT; + + timer_target = timer_head->ts_integer; } void timer_reset() { pclog("timer_reset\n"); - timers_present = 0; - timer_latch = timer_count = 0; -// timer_process(); + timer_target = 0; + tsc = 0; + timer_head = NULL; } -int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv) +void timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer) { - 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; + memset(timer, 0, sizeof(pc_timer_t)); + + timer->callback = callback; + timer->p = p; + timer->enabled = 0; + timer->prev = timer->next = NULL; + if (start_timer) + timer_set_delay_u64(timer, 0); } diff --git a/src/timer.h b/src/timer.h index 43722d8..181c1ce 100644 --- a/src/timer.h +++ b/src/timer.h @@ -3,56 +3,140 @@ #include "cpu.h" -extern int timer_start; +/*Timers are based on the CPU Time Stamp Counter. Timer timestamps are in a + 32:32 fixed point format, with the integer part compared against the TSC. The + fractional part is used when advancing the timestamp to ensure a more accurate + period. + + As the timer only stores 32 bits of integer timestamp, and the TSC is 64 bits, + the timer period can only be at most 0x7fffffff CPU cycles. To allow room for + (optimistic) CPU frequency growth, timer period must be at most 1 second. -#define timer_start_period(cycles) \ - timer_start = cycles; + When a timer callback is called, the timer has been disabled. If the timer is + to repeat, the callback must call timer_advance_u64(). This is a change from + the old timer API.*/ +typedef struct pc_timer_t +{ + uint32_t ts_integer; + uint32_t ts_frac; + int enabled; -#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) + void (*callback)(void *p); + void *p; -#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) + struct pc_timer_t *prev, *next; +} pc_timer_t; +/*Timestamp of nearest enabled timer. CPU emulation must call timer_process() + when TSC matches or exceeds this.*/ +extern uint32_t timer_target; + +/*Enable timer, without updating timestamp*/ +void timer_enable(pc_timer_t *timer); +/*Disable timer*/ +void timer_disable(pc_timer_t *timer); + +/*Process any pending timers*/ void timer_process(); -void timer_update_outstanding(); + +/*Reset timer system*/ 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 +/*Add new timer. If start_timer is set, timer will be enabled with a zero + timestamp - this is useful for permanently enabled timers*/ +void timer_add(pc_timer_t *timer, void (*callback)(void *p), void *p, int start_timer); -extern int timer_count; -extern int timer_one; +/*1us in 32:32 format*/ +extern uint64_t TIMER_USEC; -#define TIMER_SHIFT 6 +/*True if timer a expires before timer b*/ +#define TIMER_LESS_THAN(a, b) ((int32_t)((a)->ts_integer - (b)->ts_integer) <= 0) +/*True if timer a expires before 32 bit integer timestamp b*/ +#define TIMER_LESS_THAN_VAL(a, b) ((int32_t)((a)->ts_integer - (b)) <= 0) +/*True if 32 bit integer timestamp a expires before 32 bit integer timestamp b*/ +#define TIMER_VAL_LESS_THAN_VAL(a, b) ((int32_t)((a) - (b)) <= 0) -extern int TIMER_USEC; +/*Advance timer by delay, specified in 32:32 format. This should be used to + resume a recurring timer in a callback routine*/ +static inline void timer_advance_u64(pc_timer_t *timer, uint64_t delay) +{ + uint32_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + if ((frac_delay + timer->ts_frac) < frac_delay) + timer->ts_integer++; + timer->ts_frac += frac_delay; + timer->ts_integer += int_delay; + + timer_enable(timer); +} + +/*Set a timer to the given delay, specified in 32:32 format. This should be used + when starting a timer*/ +static inline void timer_set_delay_u64(pc_timer_t *timer, uint64_t delay) +{ + uint32_t int_delay = delay >> 32; + uint32_t frac_delay = delay & 0xffffffff; + + timer->ts_frac = frac_delay; + timer->ts_integer = int_delay + (uint32_t)tsc; + + timer_enable(timer); +} + +/*True if timer currently enabled*/ +static inline int timer_is_enabled(pc_timer_t *timer) +{ + return timer->enabled; +} + +/*Return integer timestamp of timer*/ +static inline uint32_t timer_get_ts_int(pc_timer_t *timer) +{ + return timer->ts_integer; +} + +/*Return remaining time before timer expires, in us. If the timer has already + expired then return 0*/ +static inline uint32_t timer_get_remaining_us(pc_timer_t *timer) +{ + if (timer->enabled) + { + int64_t remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32); + + if (remaining < 0) + return 0; + return remaining / TIMER_USEC; + } + + return 0; +} + +/*Return remaining time before timer expires, in 32:32 timestamp format. If the + timer has already expired then return 0*/ +static inline uint64_t timer_get_remaining_u64(pc_timer_t *timer) +{ + if (timer->enabled) + { + int64_t remaining = (((uint64_t)timer->ts_integer << 32) | timer->ts_frac) - (tsc << 32); + + if (remaining < 0) + return 0; + return remaining; + } + + return 0; +} + +/*Set timer callback function*/ +static inline void timer_set_callback(pc_timer_t *timer, void (*callback)(void *p)) +{ + timer->callback = callback; +} +/*Set timer private data*/ +static inline void timer_set_p(pc_timer_t *timer, void *p) +{ + timer->p = p; +} #endif /*_TIMER_H_*/ diff --git a/src/um8669f.c b/src/um8669f.c index 8132ff0..67e2ba4 100644 --- a/src/um8669f.c +++ b/src/um8669f.c @@ -5,36 +5,21 @@ 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 +bit 7 - enable PnP registers -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 +PnP registers : -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 - - */ +07 - device : + 0 = FDC + 1 = COM1 + 2 = COM2 + 3 = LPT1 + 5 = Game port +30 - enable +60/61 - addr +70 - IRQ +74 - DMA*/ #include "ibm.h" @@ -44,91 +29,178 @@ COM2 : #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) +typedef struct um8669f_t { - int temp; -// pclog("um8669f_write : port=%04x reg %02X = %02X locked=%i\n", port, um8669f_curreg, val, um8669f_locked); - if (um8669f_locked) + int locked; + int cur_reg_108; + uint8_t regs_108[256]; + + int cur_reg; + int cur_device; + struct + { + int enable; + uint16_t addr; + int irq; + int dma; + } dev[8]; +} um8669f_t; + +static um8669f_t um8669f_global; + +#define DEV_FDC 0 +#define DEV_COM1 1 +#define DEV_COM2 2 +#define DEV_LPT1 3 +#define DEV_GAME 5 + +#define REG_DEVICE 0x07 +#define REG_ENABLE 0x30 +#define REG_ADDRHI 0x60 +#define REG_ADDRLO 0x61 +#define REG_IRQ 0x70 +#define REG_DMA 0x74 + +void um8669f_pnp_write(uint16_t port, uint8_t val, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + + if (port == 0x279) + um8669f->cur_reg = val; + else + { + if (um8669f->cur_reg == REG_DEVICE) + um8669f->cur_device = val & 7; + else + { +// pclog("Write UM8669F %02x [%02x] %02x\n", um8669f->cur_reg, um8669f->cur_device, val); + switch (um8669f->cur_reg) + { + case REG_ENABLE: + um8669f->dev[um8669f->cur_device].enable = val; + break; + case REG_ADDRLO: + um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0xff00) | val; + break; + case REG_ADDRHI: + um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0x00ff) | (val << 8); + break; + case REG_IRQ: + um8669f->dev[um8669f->cur_device].irq = val; + break; + case REG_DMA: + um8669f->dev[um8669f->cur_device].dma = val; + break; + } + + switch (um8669f->cur_device) + { + case DEV_FDC: + fdc_remove(); + if (um8669f->dev[DEV_FDC].enable & 1) + fdc_add(); + break; + case DEV_COM1: + serial1_remove(); + if (um8669f->dev[DEV_COM1].enable & 1) + serial1_set(um8669f->dev[DEV_COM1].addr, um8669f->dev[DEV_COM1].irq); + break; + case DEV_COM2: + serial2_remove(); + if (um8669f->dev[DEV_COM2].enable & 1) + serial2_set(um8669f->dev[DEV_COM2].addr, um8669f->dev[DEV_COM2].irq); + break; + case DEV_LPT1: + lpt1_remove(); + lpt2_remove(); + if (um8669f->dev[DEV_LPT1].enable & 1) + lpt1_init(um8669f->dev[DEV_LPT1].addr); + break; + } + } + } +} + +uint8_t um8669f_pnp_read(uint16_t port, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + +// pclog("Read UM8669F %02x\n", um8669f->cur_reg); + + switch (um8669f->cur_reg) + { + case REG_DEVICE: + return um8669f->cur_device; + case REG_ENABLE: + return um8669f->dev[um8669f->cur_device].enable; + case REG_ADDRLO: + return um8669f->dev[um8669f->cur_device].addr & 0xff; + case REG_ADDRHI: + return um8669f->dev[um8669f->cur_device].addr >> 8; + case REG_IRQ: + return um8669f->dev[um8669f->cur_device].irq; + case REG_DMA: + return um8669f->dev[um8669f->cur_device].dma; + } + + return 0xff; +} + +void um8669f_write(uint16_t port, uint8_t val, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + + if (um8669f->locked) { if (port == 0x108 && val == 0xaa) - um8669f_locked = 0; + um8669f->locked = 0; } else { if (port == 0x108) { if (val == 0x55) - um8669f_locked = 1; + um8669f->locked = 1; else - um8669f_curreg = val; + um8669f->cur_reg_108 = val; } else { - um8669f_regs[um8669f_curreg] = val; +// pclog("Write UM8669f register %02x %02x %04x:%04x %i\n", um8669f_curreg, val, CS,cpu_state.pc, ins); + um8669f->regs_108[um8669f->cur_reg_108] = val; - fdc_remove(); - if (um8669f_regs[0xc0] & 1) - fdc_add(); - - if (um8669f_regs[0xc0] & 2) + io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f); + if (um8669f->regs_108[0xc1] & 0x80) { - 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; - } - } - - 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; + io_sethandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_sethandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_sethandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f); } } } } -uint8_t um8669f_read(uint16_t port, void *priv) +uint8_t um8669f_read(uint16_t port, void *p) { -// pclog("um8669f_read : port=%04x reg %02X locked=%i\n", port, um8669f_curreg, um8669f_locked); - if (um8669f_locked) - return 0xff; + um8669f_t *um8669f = (um8669f_t *)p; + +// pclog("um8669f_read : port=%04x reg %02X locked=%i %02x\n", port, um8669f_curreg, um8669f_locked, um8669f_regs[um8669f_curreg]); + if (um8669f->locked) + return 0xff; if (port == 0x108) - return um8669f_curreg; /*???*/ + return um8669f->cur_reg_108; /*???*/ else - return um8669f_regs[um8669f_curreg]; + return um8669f->regs_108[um8669f->cur_reg_108]; } void um8669f_init() { - io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, NULL); - um8669f_locked = 1; + memset(&um8669f_global, 0, sizeof(um8669f_t)); + + um8669f_global.locked = 1; + + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, &um8669f_global); } diff --git a/src/um8881f.c b/src/um8881f.c index b469bbd..84c0434 100644 --- a/src/um8881f.c +++ b/src/um8881f.c @@ -33,8 +33,7 @@ void um8881f_write(int func, int addr, uint8_t val, void *priv) 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); +// shadowbios = val & 0x80; flushmmucache_nopc(); } } diff --git a/src/vid_ati18800.c b/src/vid_ati18800.c index f3a9cac..2b30d4c 100644 --- a/src/vid_ati18800.c +++ b/src/vid_ati18800.c @@ -19,6 +19,10 @@ typedef struct ati18800_t uint8_t regs[256]; int index; + + int is_ega; + int ega_switches; + int ega_switch_read; } ati18800_t; void ati18800_out(uint16_t addr, uint8_t val, void *p) @@ -56,6 +60,43 @@ void ati18800_out(uint16_t addr, uint8_t val, void *p) } break; + case 0x3c2: + if (ati18800->is_ega) + { + if ((val & 0x80) != (svga->miscout & 0x80)) + { + int c; + + if (val & 0x80) + { + for (c = 0; c < 256; c++) + { + ati18800->svga.pallook[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + ati18800->svga.pallook[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + } + ati18800->svga.vertical_linedbl = 0; + } + else + { + for (c = 0; c < 256; c++) + { + if ((c & 0x17) == 6) + ati18800->svga.pallook[c] = makecol32(0xaa, 0x55, 0x00); + else + { + ati18800->svga.pallook[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + ati18800->svga.pallook[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); + } + } + ati18800->svga.vertical_linedbl = 1; + } + + svga->fullchange = changeframecount; + } + ati18800->ega_switch_read = val & 0xc; + } + break; + case 0x3D4: svga->crtcreg = val & 0x3f; return; @@ -83,7 +124,7 @@ uint8_t ati18800_in(uint16_t addr, void *p) { ati18800_t *ati18800 = (ati18800_t *)p; svga_t *svga = &ati18800->svga; - uint8_t temp; + uint8_t temp = 0xff; // if (addr != 0x3da) pclog("ati18800_in : %04X ", addr); @@ -109,6 +150,20 @@ uint8_t ati18800_in(uint16_t addr, void *p) } break; + case 0x3c2: + if (ati18800->is_ega) + { + switch (ati18800->ega_switch_read) + { + case 0xc: return (ati18800->ega_switches & 1) ? 0x10 : 0; + case 0x8: return (ati18800->ega_switches & 2) ? 0x10 : 0; + case 0x4: return (ati18800->ega_switches & 4) ? 0x10 : 0; + case 0x0: return (ati18800->ega_switches & 8) ? 0x10 : 0; + } + } + break; + + case 0x3D4: temp = svga->crtcreg; break; @@ -119,16 +174,31 @@ uint8_t ati18800_in(uint16_t addr, void *p) temp = svga_in(addr, svga); break; } - if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); +// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); return temp; } +static void ega_wonder_800_recalctimings(svga_t *svga) +{ + ati18800_t *ati18800 = (ati18800_t *)svga->p; + int clksel = ((svga->miscout & 0xc) >> 2) | ((ati18800->regs[0xbe] & 0x10) ? 4 : 0); + + switch (clksel) + { + case 0: svga->clock = (cpuclock * (double)(1ull << 32)) / 25175000.0; break; + case 1: svga->clock = (cpuclock * (double)(1ull << 32)) / 28322000.0; break; + case 4: svga->clock = (cpuclock * (double)(1ull << 32)) / 14318181.0; break; + case 5: svga->clock = (cpuclock * (double)(1ull << 32)) / 16257000.0; break; + case 7: default: svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; + } +} + 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); + rom_init(&ati18800->bios_rom, "vgaedge16.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ NULL, @@ -146,9 +216,49 @@ void *ati18800_init() return ati18800; } +void *ega_wonder_800_init() +{ + int c; + + ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); + memset(ati18800, 0, sizeof(ati18800_t)); + + rom_init(&ati18800->bios_rom, "ATI EGA Wonder 800+ N1.00.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&ati18800->svga, ati18800, 1 << 18, /*256kb*/ + ega_wonder_800_recalctimings, + ati18800_in, ati18800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + io_sethandler(0x03c0, 0x0006, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + io_sethandler(0x03ca, 0x0016, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + + ati18800->svga.miscout = 1; + + for (c = 0; c < 256; c++) + { + ati18800->svga.pallook[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + ati18800->svga.pallook[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + } + + ati_eeprom_load(&ati18800->eeprom, "egawonder800.nvr", 0); + + ati18800->is_ega = 1; + ati18800->ega_switches = 9; + + return ati18800; +} + static int ati18800_available() { - return rom_present("roms/vgaedge16.vbi"); + return rom_present("vgaedge16.vbi"); +} + +static int ega_wonder_800_available() +{ + return rom_present("ATI EGA Wonder 800+ N1.00.BIN"); } void ati18800_close(void *p) @@ -193,3 +303,14 @@ device_t ati18800_device = ati18800_add_status_info }; +device_t ati_ega_wonder_800_device = +{ + "ATI EGA Wonder 800+", + 0, + ega_wonder_800_init, + ati18800_close, + ega_wonder_800_available, + ati18800_speed_changed, + ati18800_force_redraw, + ati18800_add_status_info +}; diff --git a/src/vid_ati18800.h b/src/vid_ati18800.h index 83fe2c0..0d667ab 100644 --- a/src/vid_ati18800.h +++ b/src/vid_ati18800.h @@ -1 +1,2 @@ extern device_t ati18800_device; +extern device_t ati_ega_wonder_800_device; diff --git a/src/vid_ati28800.c b/src/vid_ati28800.c index 2ab7e07..55ccad0 100644 --- a/src/vid_ati28800.c +++ b/src/vid_ati28800.c @@ -1,4 +1,4 @@ -/*ATI 28800 emulation (VGA Charger)*/ +/*ATI 28800 emulation (VGA Charger & Korean VGA)*/ #include #include "ibm.h" #include "device.h" @@ -20,6 +20,14 @@ typedef struct ati28800_t uint8_t regs[256]; int index; + + uint8_t port_03dd_val; + uint16_t get_korean_font_kind; + int in_get_korean_font_kind_set; + int get_korean_font_enabled; + int get_korean_font_index; + uint16_t get_korean_font_base; + int ksc5601_mode_enabled; } ati28800_t; void ati28800_out(uint16_t addr, uint8_t val, void *p) @@ -39,6 +47,7 @@ void ati28800_out(uint16_t addr, uint8_t val, void *p) ati28800->index = val; break; case 0x1cf: + old = ati28800->regs[ati28800->index]; ati28800->regs[ati28800->index] = val; switch (ati28800->index) { @@ -51,10 +60,24 @@ void ati28800_out(uint16_t addr, uint8_t val, void *p) } else /*Single bank mode*/ svga->read_bank = svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + if (ati28800->index == 0xbe && ((old ^ val) & 0x10)) + svga_recalctimings(svga); break; case 0xb3: ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1); break; + case 0xb6: + if ((old ^ val) & 0x10) + svga_recalctimings(svga); + break; + case 0xb8: + if ((old ^ val) & 0x40) + svga_recalctimings(svga); + break; + case 0xb9: + if ((old ^ val) & 2) + svga_recalctimings(svga); + break; } break; @@ -81,6 +104,75 @@ void ati28800_out(uint16_t addr, uint8_t val, void *p) svga_out(addr, val, svga); } +void ati28800k_out(uint16_t addr, uint8_t val, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1CF: + if (ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20)) + { + ati28800->ksc5601_mode_enabled = val & 0x20; +// pclog("Switching mode to %s at %04X:%04X\n", ksc5601_mode_enabled ? "DBCS" : "SBCS", CS, cpu_state.oldpc); + svga_recalctimings(svga); + } + ati28800_out(oldaddr, val, p); + break; + case 0x3DD: +// pclog("ati28800k_out : set port 03DD to %02X at %04X:%04X\n", val, CS, cpu_state.oldpc); + ati28800->port_03dd_val = val; + if (val == 1) + ati28800->get_korean_font_enabled = 0; + if (ati28800->in_get_korean_font_kind_set) + { + ati28800->get_korean_font_kind = (val << 8) | (ati28800->get_korean_font_kind & 0xFF); + ati28800->get_korean_font_enabled = 1; + ati28800->get_korean_font_index = 0; + ati28800->in_get_korean_font_kind_set = 0; + } + break; + case 0x3DE: +// pclog("ati28800k_out : set port 03DE to %02X at %04X:%04X\n", val, CS, cpu_state.oldpc); + ati28800->in_get_korean_font_kind_set = 0; + if(ati28800->get_korean_font_enabled) + { + if((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) + fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + (ati28800->get_korean_font_base & 0x7F) - 0x20][ati28800->get_korean_font_index] = val; + ati28800->get_korean_font_index++; + ati28800->get_korean_font_index &= 0x1F; + } + else + { + switch (ati28800->port_03dd_val) + { + case 0x10: + ati28800->get_korean_font_base = ((val & 0x7F) << 7) | (ati28800->get_korean_font_base & 0x7F); + break; + case 8: + ati28800->get_korean_font_base = (ati28800->get_korean_font_base & 0x3F80) | (val & 0x7F); + break; + case 1: + ati28800->get_korean_font_kind = (ati28800->get_korean_font_kind & 0xFF00) | val; + if (val & 2) + ati28800->in_get_korean_font_kind_set = 1; + break; + default: + break; + } + } + break; + default: + ati28800_out(oldaddr, val, p); + break; + } +} + uint8_t ati28800_in(uint16_t addr, void *p) { ati28800_t *ati28800 = (ati28800_t *)p; @@ -127,29 +219,111 @@ uint8_t ati28800_in(uint16_t addr, void *p) temp = svga_in(addr, svga); break; } - if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); +// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); + return temp; +} + +uint8_t ati28800k_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; + uint8_t temp = 0xFF; + +// if (addr != 0x3da) pclog("ati28800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x3DE: + if (ati28800->get_korean_font_enabled) + { + switch (ati28800->get_korean_font_kind >> 8) + { + case 4: /* ROM font */ + temp = fontdatksc5601[ati28800->get_korean_font_base][ati28800->get_korean_font_index++]; + break; + case 2: /* User defined font */ + if((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) + temp = fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + (ati28800->get_korean_font_base & 0x7F) - 0x20][ati28800->get_korean_font_index]; + else + temp = 0xFF; + ati28800->get_korean_font_index++; + break; + default: + break; + } + ati28800->get_korean_font_index &= 0x1F; + } + break; + default: + temp = ati28800_in(oldaddr, p); + break; + } +// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); return temp; } void ati28800_recalctimings(svga_t *svga) { ati28800_t *ati28800 = (ati28800_t *)svga->p; - pclog("ati28800_recalctimings\n"); + //pclog("ati28800_recalctimings\n"); + + switch (((ati28800->regs[0xbe] & 0x10) >> 1) | ((ati28800->regs[0xb9] & 2) << 1) | ((svga->miscout & 0x0C) >> 2)) + { + case 0x00: svga->clock = (cpuclock * (double)(1ull << 32)) / 42954000.0; break; + case 0x01: svga->clock = (cpuclock * (double)(1ull << 32)) / 48771000.0; break; + case 0x03: svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; + case 0x04: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; + case 0x05: svga->clock = (cpuclock * (double)(1ull << 32)) / 56640000.0; break; + case 0x07: svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; break; + case 0x08: svga->clock = (cpuclock * (double)(1ull << 32)) / 30240000.0; break; + case 0x09: svga->clock = (cpuclock * (double)(1ull << 32)) / 32000000.0; break; + case 0x0A: svga->clock = (cpuclock * (double)(1ull << 32)) / 37500000.0; break; + case 0x0B: svga->clock = (cpuclock * (double)(1ull << 32)) / 39000000.0; break; + case 0x0C: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; + case 0x0D: svga->clock = (cpuclock * (double)(1ull << 32)) / 56644000.0; break; + case 0x0E: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break; + case 0x0F: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + default: break; + } + if (ati28800->regs[0xb8] & 0x40) + svga->clock *= 2; + if (ati28800->regs[0xb6] & 0x10) + { + svga->hdisp <<= 1; + svga->htotal <<= 1; + svga->rowoffset <<= 1; + } + if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ { - pclog("8bpp_highres\n"); + //pclog("8bpp_highres\n"); svga->render = svga_render_8bpp_highres; svga->rowoffset <<= 1; svga->ma <<= 1; } } +void ati28800k_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *)svga->p; + + ati28800_recalctimings(svga); + + if (svga->render == svga_render_text_80 && ati28800->ksc5601_mode_enabled) + { + svga->render = svga_render_text_80_ksc5601; + } +} + void *ati28800_init() { ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); memset(ati28800, 0, sizeof(ati28800_t)); - rom_init(&ati28800->bios_rom, "roms/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&ati28800->bios_rom, "bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&ati28800->svga, ati28800, 1 << 19, /*512kb*/ ati28800_recalctimings, @@ -167,9 +341,125 @@ void *ati28800_init() return ati28800; } +void *ati28800k_init() +{ + ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); + + ati28800->port_03dd_val = 0; + ati28800->get_korean_font_base = 0; + ati28800->get_korean_font_index = 0; + ati28800->get_korean_font_enabled = 0; + ati28800->get_korean_font_kind = 0; + ati28800->in_get_korean_font_kind_set = 0; + ati28800->ksc5601_mode_enabled = 0; + + rom_init(&ati28800->bios_rom, "atikorvga.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont("ati_ksc5601.rom", FONT_KSC5601); + + svga_init(&ati28800->svga, ati28800, 1 << 19, /*512kb*/ + ati28800k_recalctimings, + ati28800k_in, ati28800k_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + io_sethandler(0x03c0, 0x0020, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + + ati28800->svga.miscout = 1; + ati28800->svga.ksc5601_sbyte_mask = 0; + ati28800->svga.ksc5601_udc_area_msb[0] = 0xC9; + ati28800->svga.ksc5601_udc_area_msb[1] = 0xFE; + ati28800->svga.ksc5601_swap_mode = 0; + ati28800->svga.ksc5601_english_font_type = 0; + + ati_eeprom_load(&ati28800->eeprom, "atikorvga.nvr", 0); + + return ati28800; +} + +void *ati28800k_spc4620p_init() +{ + ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); + + ati28800->port_03dd_val = 0; + ati28800->get_korean_font_base = 0; + ati28800->get_korean_font_index = 0; + ati28800->get_korean_font_enabled = 0; + ati28800->get_korean_font_kind = 0; + ati28800->in_get_korean_font_kind_set = 0; + ati28800->ksc5601_mode_enabled = 0; + + rom_init_interleaved(&ati28800->bios_rom, "spc4620p/31005h.u8", "spc4620p/31005h.u10", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont("spc4620p/svb6120a_font.rom", 6); + + svga_init(&ati28800->svga, ati28800, 1 << 19, /*512kb*/ + ati28800k_recalctimings, + ati28800k_in, ati28800k_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + io_sethandler(0x03c0, 0x0020, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + + ati28800->svga.miscout = 1; + ati28800->svga.ksc5601_sbyte_mask = 0; + ati28800->svga.ksc5601_udc_area_msb[0] = 0xC9; + ati28800->svga.ksc5601_udc_area_msb[1] = 0xFE; + ati28800->svga.ksc5601_swap_mode = 0; + ati28800->svga.ksc5601_english_font_type = 0; + + ati_eeprom_load(&ati28800->eeprom, "svb6120a.nvr", 0); + + return ati28800; +} + +void *ati28800k_spc6033p_init() +{ + ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); + + ati28800->port_03dd_val = 0; + ati28800->get_korean_font_base = 0; + ati28800->get_korean_font_index = 0; + ati28800->get_korean_font_enabled = 0; + ati28800->get_korean_font_kind = 0; + ati28800->in_get_korean_font_kind_set = 0; + ati28800->ksc5601_mode_enabled = 0; + + rom_init(&ati28800->bios_rom, "spc6033p/phoenix.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont("spc6033p/svb6120a_font.rom", 6); + + svga_init(&ati28800->svga, ati28800, 1 << 19, /*512kb*/ + ati28800k_recalctimings, + ati28800k_in, ati28800k_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + io_sethandler(0x03c0, 0x0020, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + + ati28800->svga.miscout = 1; + ati28800->svga.ksc5601_sbyte_mask = 0; + ati28800->svga.ksc5601_udc_area_msb[0] = 0xC9; + ati28800->svga.ksc5601_udc_area_msb[1] = 0xFE; + ati28800->svga.ksc5601_swap_mode = 0; + ati28800->svga.ksc5601_english_font_type = 0; + + ati_eeprom_load(&ati28800->eeprom, "svb6120a_spc6033p.nvr", 0); + + return ati28800; +} + static int ati28800_available() { - return rom_present("roms/bios.bin"); + return rom_present("bios.bin"); +} + +static int ati28800k_available() +{ + return rom_present("atikorvga.bin") && rom_present("ati_ksc5601.rom"); } void ati28800_close(void *p) @@ -202,6 +492,17 @@ void ati28800_add_status_info(char *s, int max_len, void *p) svga_add_status_info(s, max_len, &ati28800->svga); } +void ati28800k_add_status_info(char *s, int max_len, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + char temps[128]; + + ati28800_add_status_info(s, max_len, p); + + sprintf(temps, "Korean SVGA mode enabled : %s\n\n", ati28800->ksc5601_mode_enabled ? "Yes" : "No"); + strncat(s, temps, max_len); +} + device_t ati28800_device = { "ATI-28800", @@ -213,3 +514,39 @@ device_t ati28800_device = ati28800_force_redraw, ati28800_add_status_info }; + +device_t ati28800k_device = +{ + "ATI Korean VGA", + 0, + ati28800k_init, + ati28800_close, + ati28800k_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800k_add_status_info +}; + +device_t ati28800k_spc4620p_device = +{ + "SVB-6120A", + 0, + ati28800k_spc4620p_init, + ati28800_close, + NULL, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800k_add_status_info +}; + +device_t ati28800k_spc6033p_device = +{ + "SVB-6120A", + 0, + ati28800k_spc6033p_init, + ati28800_close, + NULL, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800k_add_status_info +}; diff --git a/src/vid_ati28800.h b/src/vid_ati28800.h index 6cb3617..2d2cd8a 100644 --- a/src/vid_ati28800.h +++ b/src/vid_ati28800.h @@ -1 +1,4 @@ extern device_t ati28800_device; +extern device_t ati28800k_device; +extern device_t ati28800k_spc4620p_device; +extern device_t ati28800k_spc6033p_device; diff --git a/src/vid_ati_eeprom.c b/src/vid_ati_eeprom.c index 61d7389..ce13701 100644 --- a/src/vid_ati_eeprom.c +++ b/src/vid_ati_eeprom.c @@ -1,4 +1,5 @@ #include "ibm.h" +#include "nvr.h" #include "vid_ati_eeprom.h" enum @@ -33,10 +34,10 @@ 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"); + f = nvrfopen(eeprom->fn, "rb"); if (!f) { - memset(eeprom->data, 0, eeprom->type ? 512 : 128); + memset(eeprom->data, 0xff, eeprom->type ? 512 : 128); return; } fread(eeprom->data, 1, eeprom->type ? 512 : 128, f); @@ -45,7 +46,7 @@ void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type) void ati_eeprom_save(ati_eeprom_t *eeprom) { - FILE *f = romfopen(eeprom->fn, "wb"); + FILE *f = nvrfopen(eeprom->fn, "wb"); if (!f) return; fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); fclose(f); diff --git a/src/vid_ati_mach64.c b/src/vid_ati_mach64.c index e7ff3f0..8b752f2 100644 --- a/src/vid_ati_mach64.c +++ b/src/vid_ati_mach64.c @@ -8,6 +8,7 @@ #include "rom.h" #include "thread.h" #include "video.h" +#include "vid_ddc.h" #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_ati68860_ramdac.h" @@ -71,6 +72,8 @@ typedef struct mach64_t int type; uint8_t pci_regs[256]; + uint8_t int_line; + int card; int bank_r[2]; int bank_w[2]; @@ -197,6 +200,7 @@ typedef struct mach64_t uint16_t pci_id; uint32_t config_chip_id; uint32_t block_decoded_io; + int use_block_decoded_io; int pll_addr; uint8_t pll_regs[16]; @@ -290,7 +294,11 @@ enum }; void mach64_write(uint32_t addr, uint8_t val, void *priv); +void mach64_writew(uint32_t addr, uint16_t val, void *priv); +void mach64_writel(uint32_t addr, uint32_t val, void *priv); uint8_t mach64_read(uint32_t addr, void *priv); +uint16_t mach64_readw(uint32_t addr, void *priv); +uint32_t mach64_readl(uint32_t addr, void *priv); void mach64_updatemapping(mach64_t *mach64); void mach64_recalctimings(svga_t *svga); void mach64_start_fill(mach64_t *mach64); @@ -415,7 +423,7 @@ void mach64_recalctimings(svga_t *svga) 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->clock = (cpuclock * (float)(1ull << 32)) / mach64->ics2595.output_clock; svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; svga->linedbl = svga->rowcount = 0; svga->split = 0xffffff; @@ -465,12 +473,12 @@ void mach64_recalctimings(svga_t *svga) break; } - svga->vrammask = mach64->vram_mask; + svga->vram_display_mask = 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; + svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; } } @@ -494,14 +502,14 @@ void mach64_updatemapping(mach64_t *mach64) 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_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); 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_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); mem_mapping_set_p(&mach64->svga.mapping, mach64); mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); svga->banked_mask = 0xffff; @@ -552,6 +560,14 @@ void mach64_updatemapping(mach64_t *mach64) } } +static void mach64_update_irqs(mach64_t *mach64) +{ + if ((mach64->crtc_int_cntl & 0xaa0024) & ((mach64->crtc_int_cntl << 1) & 0xaa0024)) + pci_set_irq(mach64->card, PCI_INTA); + else + pci_clear_irq(mach64->card, PCI_INTA); +} + static inline void wake_fifo_thread(mach64_t *mach64) { thread_set_event(mach64->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ @@ -1671,6 +1687,7 @@ static void mach64_vblank_start(svga_t *svga) int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; mach64->crtc_int_cntl |= 4; + mach64_update_irqs(mach64); svga->overlay.x = (mach64->overlay_y_x_start >> 16) & 0x7ff; svga->overlay.y = mach64->overlay_y_x_start & 0x7ff; @@ -1822,11 +1839,27 @@ uint8_t mach64_ext_readb(uint32_t addr, void *p) else ret = ati68860_ramdac_in(addr & 3, &mach64->ramdac, &mach64->svga); break; - case 0xc4: case 0xc5: case 0xc6: case 0xc7: - if (mach64->type == MACH64_VT2) - mach64->dac_cntl |= (4 << 24); + case 0xc4: case 0xc5: case 0xc6: READ8(addr, mach64->dac_cntl); break; + case 0xc7: + READ8(addr, mach64->dac_cntl); + if (mach64->type == MACH64_VT2) + { + uint8_t gpio_state = 6; + + if ((ret & (1 << 4)) && !(ret & (1 << 1))) + gpio_state &= ~(1 << 1); + if (!(ret & (1 << 4)) && !ddc_read_data()) + gpio_state &= ~(1 << 1); + if ((ret & (1 << 5)) && !(ret & (1 << 2))) + gpio_state &= ~(1 << 2); + if (!(ret & (1 << 5)) && !ddc_read_clock()) + gpio_state &= ~(1 << 2); + + ret = (ret & ~6) | gpio_state; + } + break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: READ8(addr, mach64->gen_test_cntl); @@ -2230,6 +2263,7 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) mach64->crtc_int_cntl = (mach64->crtc_int_cntl & 0x75) | (val & ~0x75); if (val & 4) mach64->crtc_int_cntl &= ~4; + mach64_update_irqs(mach64); break; case 0x1c: case 0x1d: case 0x1e: case 0x1f: @@ -2337,6 +2371,12 @@ void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) 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); + { + int data = (val & (1 << 4)) ? ((val & (1 << 1)) ? 1 : 0) : 1; + int clk = (val & (1 << 5)) ? ((val & (1 << 2)) ? 1 : 0) : 1; + + ddc_i2c_change(clk, data); + } break; case 0xd0: case 0xd1: case 0xd2: case 0xd3: @@ -2812,6 +2852,22 @@ void mach64_write(uint32_t addr, uint8_t val, void *p) // pclog("%08X\n", addr); svga_write_linear(addr, val, svga); } +void mach64_writew(uint32_t addr, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; + svga_writew_linear(addr, val, svga); +} +void mach64_writel(uint32_t addr, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; + svga_writel_linear(addr, val, svga); +} uint8_t mach64_read(uint32_t addr, void *p) { @@ -2824,6 +2880,22 @@ uint8_t mach64_read(uint32_t addr, void *p) // pclog("%08X %02X\n", addr, ret); return ret; } +uint16_t mach64_readw(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + return svga_readw_linear(addr, svga); +} +uint32_t mach64_readl(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + return svga_readl_linear(addr, svga); +} void mach64_hwcursor_draw(svga_t *svga, int displine) { @@ -3146,17 +3218,20 @@ static void mach64_io_set(mach64_t *mach64) io_sethandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); - for (c = 0; c < 8; c++) + if (!mach64->use_block_decoded_io) { - 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); + 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); - if (mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) + if (mach64->use_block_decoded_io && mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) io_sethandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); } @@ -3194,7 +3269,10 @@ uint8_t mach64_pci_read(int func, int addr, void *p) case 0x12: return mach64->linear_base >> 16; case 0x13: return mach64->linear_base >> 24; - case 0x14: return 0x01; /*Block decoded IO address*/ + case 0x14: + if (mach64->type == MACH64_VT2) + return 0x01; /*Block decoded IO address*/ + return 0; case 0x15: return mach64->block_decoded_io >> 8; case 0x16: return mach64->block_decoded_io >> 16; case 0x17: return mach64->block_decoded_io >> 24; @@ -3203,6 +3281,11 @@ uint8_t mach64_pci_read(int func, int addr, void *p) case 0x31: return 0x00; case 0x32: return mach64->pci_regs[0x32]; case 0x33: return mach64->pci_regs[0x33]; + + case 0x3c: return mach64->int_line; + case 0x3d: return PCI_INTA; + + case 0x40: return mach64->use_block_decoded_io; } return 0; } @@ -3280,6 +3363,21 @@ void mach64_pci_write(int func, int addr, uint8_t val, void *p) mem_mapping_disable(&mach64->bios_rom.mapping); } return; + + case 0x3c: + mach64->int_line = val; + break; + + case 0x40: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->use_block_decoded_io = val & 0x04; + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; } } @@ -3308,7 +3406,7 @@ static void *mach64_common_init() mach64_io_set(mach64); - pci_add(mach64_pci_read, mach64_pci_write, mach64); + mach64->card = pci_add(mach64_pci_read, mach64_pci_write, mach64); mach64->pci_regs[PCI_REG_COMMAND] = 3; mach64->pci_regs[0x30] = 0x00; @@ -3322,6 +3420,8 @@ static void *mach64_common_init() mach64->wake_fifo_thread = thread_create_event(); mach64->fifo_not_full_event = thread_create_event(); mach64->fifo_thread = thread_create(fifo_thread, mach64); + + ddc_init(); return mach64; } @@ -3342,7 +3442,7 @@ static void *mach64gx_init() ati_eeprom_load(&mach64->eeprom, "mach64.nvr", 1); - rom_init(&mach64->bios_rom, "roms/mach64gx/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&mach64->bios_rom, "mach64gx/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return mach64; } @@ -3356,10 +3456,11 @@ static void *mach64vt2_init() mach64->config_chip_id = 0x40005654; mach64->dac_cntl = 1 << 16; /*Internal 24-bit DAC*/ mach64->config_stat0 = 4; - + mach64->use_block_decoded_io = PCI ? 4 : 0; + ati_eeprom_load(&mach64->eeprom, "mach64vt.nvr", 1); - rom_init(&mach64->bios_rom, "roms/atimach64vt2pci.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&mach64->bios_rom, "atimach64vt2pci.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga->vblank_start = mach64_vblank_start; @@ -3368,11 +3469,11 @@ static void *mach64vt2_init() int mach64gx_available() { - return rom_present("roms/mach64gx/bios.bin"); + return rom_present("mach64gx/bios.bin"); } int mach64vt2_available() { - return rom_present("roms/atimach64vt2pci.bin"); + return rom_present("atimach64vt2pci.bin"); } void mach64_close(void *p) diff --git a/src/vid_cga.c b/src/vid_cga.c index 65585b6..a74f497 100644 --- a/src/vid_cga.c +++ b/src/vid_cga.c @@ -10,9 +10,6 @@ #include "vid_cga.h" #include "dosbox/vid_cga_comp.h" -#define CGA_RGB 0 -#define CGA_COMPOSITE 1 - #define COMPOSITE_OLD 0 #define COMPOSITE_NEW 1 @@ -31,10 +28,10 @@ void cga_out(uint16_t addr, uint8_t val, void *p) // pclog("CGA_OUT %04X %02X\n", addr, val); switch (addr) { - case 0x3D4: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: cga->crtcreg = val & 31; return; - case 0x3D5: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: old = cga->crtc[cga->crtcreg]; cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; if (old != val) @@ -83,8 +80,9 @@ void cga_write(uint32_t addr, uint8_t val, void *p) cga->vram[addr & 0x3fff] = val; if (cga->snow_enabled) { - cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = val; - cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + int offset = ((timer_get_remaining_u64(&cga->timer) / CGACONST) * 2) & 0xfc; + cga->charbuffer[offset] = cga->vram[addr & 0x3fff]; + cga->charbuffer[offset | 1] = cga->vram[addr & 0x3fff]; } egawrites++; cycles -= 4; @@ -96,8 +94,9 @@ uint8_t cga_read(uint32_t addr, void *p) cycles -= 4; if (cga->snow_enabled) { - 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]; + int offset = ((timer_get_remaining_u64(&cga->timer) / CGACONST) * 2) & 0xfc; + cga->charbuffer[offset] = cga->vram[addr & 0x3fff]; + cga->charbuffer[offset | 1] = cga->vram[addr & 0x3fff]; } egareads++; // pclog("CGA_READ %04X\n", addr); @@ -124,8 +123,8 @@ void cga_recalctimings(cga_t *cga) _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)); + cga->dispontime = (uint64_t)_dispontime; + cga->dispofftime = (uint64_t)_dispofftime; } void cga_poll(void *p) @@ -137,13 +136,13 @@ void cga_poll(void *p) int oldvc; uint8_t chr, attr; uint16_t dat; - int cols[4]; + uint32_t cols[4]; int col; int oldsc; if (!cga->linepos) { - cga->vidtime += cga->dispofftime; + timer_advance_u64(&cga->timer, cga->dispofftime); cga->cgastat |= 1; cga->linepos = 1; oldsc = cga->sc; @@ -158,49 +157,49 @@ void cga_poll(void *p) // printf("Firstline %i\n",firstline); } cga->lastline = cga->displine; + + cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15); 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; - } + ((uint32_t *)buffer32->line[cga->displine])[c] = cols[0]; + if (cga->cgamode & 1) + ((uint32_t *)buffer32->line[cga->displine])[c + (cga->crtc[1] << 3) + 8] = cols[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; - } + ((uint32_t *)buffer32->line[cga->displine])[c + (cga->crtc[1] << 4) + 8] = cols[0]; } if (cga->cgamode & 1) { for (x = 0; x < cga->crtc[1]; x++) { - chr = cga->charbuffer[x << 1]; - attr = cga->charbuffer[(x << 1) + 1]; + if (cga->cgamode & 8) + { + chr = cga->charbuffer[x << 1]; + attr = cga->charbuffer[(x << 1) + 1]; + } + else + chr = attr = 0; drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); if (cga->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; + cols[1] = attr & 15; + cols[0] = (attr >> 4) & 7; if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) cols[1] = cols[0]; } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; + cols[1] = attr & 15; + cols[0] = attr >> 4; } 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; + ((uint32_t *)buffer32->line[cga->displine])[(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; } 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]; + ((uint32_t *)buffer32->line[cga->displine])[(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } cga->ma++; } @@ -209,37 +208,45 @@ void cga_poll(void *p) { for (x = 0; x < cga->crtc[1]; x++) { - chr = cga->vram[((cga->ma << 1) & 0x3fff)]; - attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + if (cga->cgamode & 8) + { + chr = cga->vram[((cga->ma << 1) & 0x3fff)]; + attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + } + else + chr = attr = 0; 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]; + cols[1] = attr & 15; + cols[0] = (attr >> 4) & 7; + if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) + cols[1] = cols[0]; } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; + cols[1] = attr & 15; + cols[0] = attr >> 4; } 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; + ((uint32_t *)buffer32->line[cga->displine])[(x << 4)+(c << 1) + 8] = + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; } 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]; + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][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; + cols[0] = cga->cgacol & 15; + col = (cga->cgacol & 16) ? 8 : 0; if (cga->cgamode & 4) { cols[1] = col | 3; @@ -260,26 +267,33 @@ void cga_poll(void *p) } 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]; + if (cga->cgamode & 8) + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + else + dat = 0; 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]; + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } } else { - cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; + cols[0] = 0; + cols[1] = cga->cgacol & 15; 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]; + if (cga->cgamode & 8) + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + else + dat = 0; cga->ma++; for (c = 0; c < 16; c++) { - buffer->line[cga->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -287,9 +301,9 @@ void cga_poll(void *p) } 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]); + cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15); + if (cga->cgamode & 1) hline(buffer32, 0, cga->displine, (cga->crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, cga->displine, (cga->crtc[1] << 4) + 16, cols[0]); } if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; @@ -298,10 +312,15 @@ void cga_poll(void *p) if (cga->composite) { for (c = 0; c < x; c++) - buffer32->line[cga->displine][c] = buffer->line[cga->displine][c] & 0xf; + buffer32->line[cga->displine][c] = ((uint32_t *)buffer32->line[cga->displine])[c] & 0xf; Composite_Process(cga->cgamode, 0, x >> 2, buffer32->line[cga->displine]); } + else + { + for (c = 0; c < x; c++) + ((uint32_t *)buffer32->line[cga->displine])[c] = cgapal[((uint32_t *)buffer32->line[cga->displine])[c] & 0xf]; + } cga->sc = oldsc; if (cga->vc == cga->crtc[7] && !cga->sc) @@ -312,7 +331,7 @@ void cga_poll(void *p) } else { - cga->vidtime += cga->dispontime; + timer_advance_u64(&cga->timer, cga->dispontime); cga->linepos = 0; if (cga->vsynctime) { @@ -380,10 +399,7 @@ void cga_poll(void *p) updatewindowsize(xsize, (ysize << 1) + 16); } - if (cga->composite) - 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); + video_blit_memtoscreen(0, cga->firstline - 4, 0, (cga->lastline - cga->firstline) + 8, xsize, (cga->lastline - cga->firstline) + 8); frames++; video_res_x = xsize - 16; @@ -436,27 +452,32 @@ void cga_poll(void *p) void cga_init(cga_t *cga) { + timer_add(&cga->timer, cga_poll, cga, 1); cga->composite = 0; } void *cga_standalone_init() { - int display_type; + int display_type, contrast; cga_t *cga = malloc(sizeof(cga_t)); memset(cga, 0, sizeof(cga_t)); display_type = device_get_config_int("display_type"); - cga->composite = (display_type != CGA_RGB); + cga->composite = (display_type == DISPLAY_COMPOSITE); cga->revision = device_get_config_int("composite_type"); cga->snow_enabled = device_get_config_int("snow_enabled"); + contrast = device_get_config_int("contrast"); cga->vram = malloc(0x4000); cga_comp_init(cga->revision); - 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); + + timer_add(&cga->timer, cga_poll, cga, 1); + mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, cga); io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); - + + cgapal_rebuild(display_type, contrast); + return cga; } @@ -475,7 +496,7 @@ void cga_speed_changed(void *p) cga_recalctimings(cga); } -static device_config_t cga_config[] = +device_config_t cga_config[] = { { .name = "display_type", @@ -485,17 +506,33 @@ static device_config_t cga_config[] = { { .description = "RGB", - .value = CGA_RGB + .value = DISPLAY_RGB + }, + { + .description = "RGB (no brown)", + .value = DISPLAY_RGB_NO_BROWN + }, + { + .description = "Green Monochrome", + .value = DISPLAY_GREEN + }, + { + .description = "Amber Monochrome", + .value = DISPLAY_AMBER + }, + { + .description = "White Monochrome", + .value = DISPLAY_WHITE }, { .description = "Composite", - .value = CGA_COMPOSITE + .value = DISPLAY_COMPOSITE }, { .description = "" } }, - .default_int = CGA_RGB + .default_int = DISPLAY_RGB }, { .name = "composite_type", @@ -523,6 +560,12 @@ static device_config_t cga_config[] = .type = CONFIG_BINARY, .default_int = 1 }, + { + .name = "contrast", + .description = "Alternate monochrome contrast", + .type = CONFIG_BINARY, + .default_int = 0 + }, { .type = -1 } diff --git a/src/vid_cga.h b/src/vid_cga.h index db4355b..b8b73c9 100644 --- a/src/vid_cga.h +++ b/src/vid_cga.h @@ -9,6 +9,7 @@ typedef struct cga_t uint8_t cgamode, cgacol; + int fontbase; int linepos, displine; int sc, vc; int cgadispon; @@ -17,8 +18,8 @@ typedef struct cga_t uint16_t ma, maback; int oddeven; - int dispontime, dispofftime; - int vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; diff --git a/src/vid_cl5429.c b/src/vid_cl5429.c index 13ff6df..51584cd 100644 --- a/src/vid_cl5429.c +++ b/src/vid_cl5429.c @@ -1,19 +1,50 @@ /*Cirrus Logic CL-GD5429 emulation*/ +//SR7.0 = "true packed-pixel memory addressing" #include #include "ibm.h" +#include "cpu.h" #include "device.h" #include "io.h" +#include "mca.h" #include "mem.h" +#include "pci.h" #include "rom.h" #include "video.h" #include "vid_cl5429.h" #include "vid_svga.h" #include "vid_svga_render.h" +#include "vid_vga.h" #include "vid_unk_ramdac.h" +enum +{ + CL_TYPE_AVGA2 = 0, + CL_TYPE_GD5426, + CL_TYPE_GD5428, + CL_TYPE_GD5429, + CL_TYPE_GD5430, + CL_TYPE_GD5434 +}; + +#define BLIT_DEPTH_8 0 +#define BLIT_DEPTH_16 1 +#define BLIT_DEPTH_32 3 + +#define CL_GD5428_SYSTEM_BUS_MCA 5 +#define CL_GD5428_SYSTEM_BUS_VESA 6 +#define CL_GD5428_SYSTEM_BUS_ISA 7 + +#define CL_GD5429_SYSTEM_BUS_VESA 5 +#define CL_GD5429_SYSTEM_BUS_ISA 7 + +#define CL_GD543X_SYSTEM_BUS_PCI 4 +#define CL_GD543X_SYSTEM_BUS_VESA 6 +#define CL_GD543X_SYSTEM_BUS_ISA 7 + typedef struct gd5429_t { mem_mapping_t mmio_mapping; + mem_mapping_t linear_mapping; svga_t svga; @@ -21,10 +52,15 @@ typedef struct gd5429_t uint32_t bank[2]; uint32_t mask; + + uint32_t vram_mask; + int type; + struct { - uint16_t bg_col, fg_col; + uint32_t bg_col, fg_col; + uint16_t trans_col, trans_mask; uint16_t width, height; uint16_t dst_pitch, src_pitch; uint32_t dst_addr, src_addr; @@ -32,16 +68,45 @@ typedef struct gd5429_t uint32_t dst_addr_backup, src_addr_backup; uint16_t width_backup, height_internal; - int x_count; + int x_count, y_count; + int depth; + + int mem_word_sel; + uint16_t mem_word_save; } blt; + uint8_t hidden_dac_reg; + int dac_3c6_count; + + uint8_t pci_regs[256]; + uint8_t int_line; + int card; + + uint8_t pos_regs[8]; + svga_t *mb_vga; + + uint32_t lfb_base; + + int mmio_vram_overlap; + + uint8_t sr10_read, sr11_read; + + uint8_t latch_ext[4]; + + int vidsys_ena; } gd5429_t; -void gd5429_write(uint32_t addr, uint8_t val, void *p); -uint8_t gd5429_read(uint32_t addr, void *p); +#define GRB_X8_ADDRESSING (1 << 1) +#define GRB_WRITEMODE_EXT (1 << 2) +#define GRB_8B_LATCHES (1 << 3) +#define GRB_ENHANCED_16BIT (1 << 4) -void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p); -uint8_t gd5429_mmio_read(uint32_t addr, void *p); +static void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p); +static void gd5429_mmio_writew(uint32_t addr, uint16_t val, void *p); +static void gd5429_mmio_writel(uint32_t addr, uint32_t val, void *p); +static uint8_t gd5429_mmio_read(uint32_t addr, void *p); +static uint16_t gd5429_mmio_readw(uint32_t addr, void *p); +static uint32_t gd5429_mmio_readl(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); @@ -49,19 +114,31 @@ 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); +uint8_t gd5429_read_linear(uint32_t addr, void *p); + +static void ibm_gd5428_mapping_update(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)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; // pclog("gd5429 out %04X %02X\n", addr, val); switch (addr) { + case 0x3c3: + if (MCA) + { + gd5429->vidsys_ena = val & 1; + ibm_gd5428_mapping_update(gd5429); + } + break; + case 0x3c4: svga->seqaddr = val; break; @@ -74,31 +151,67 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p) 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); + gd5429->sr10_read = svga->seqaddr & 0xe0; +// 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); + gd5429->sr11_read = svga->seqaddr & 0xe0; +// 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); + svga->hwcursor.ysize = (val & 4) ? 64 : 32; + svga->hwcursor.yoff = 0; + if (svga->hwcursor.ysize == 64) + svga->hwcursor.addr = (0x3fc000 + ((svga->seqregs[0x13] & 0x3c) * 256)) & svga->vram_mask; + else + svga->hwcursor.addr = (0x3fc000 + ((svga->seqregs[0x13] & 0x3f) * 256)) & svga->vram_mask; +// 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); + if (svga->hwcursor.ysize == 64) + svga->hwcursor.addr = (0x3fc000 + ((val & 0x3c) * 256)) & svga->vram_mask; + else + svga->hwcursor.addr = (0x3fc000 + ((val & 0x3f) * 256)) & svga->vram_mask; +// pclog("svga->hwcursor.addr = %x\n", svga->hwcursor.addr); break; + case 0x07: + svga->set_reset_disabled = svga->seqregs[7] & 1; + svga->packed_chain4 = svga->seqregs[7] & 1; + svga_recalctimings(svga); case 0x17: - gd5429_recalc_mapping(gd5429); + if (gd5429->type >= CL_TYPE_GD5429) + gd5429_recalc_mapping(gd5429); break; } return; } break; + case 0x3c6: +// pclog("CL write 3c6 %02x %i\n", val, gd5429->dac_3c6_count); + if (gd5429->dac_3c6_count == 4) + { + gd5429->dac_3c6_count = 0; + gd5429->hidden_dac_reg = val; + svga_recalctimings(svga); + return; + } + gd5429->dac_3c6_count = 0; + break; + case 0x3c7: case 0x3c8: case 0x3c9: + gd5429->dac_3c6_count = 0; + break; + case 0x3cf: +// pclog("Write GDC %02x %02x\n", svga->gdcaddr, val); + if (svga->gdcaddr == 0) + gd5429_mmio_write(0xb8000, val, gd5429); + if (svga->gdcaddr == 1) + gd5429_mmio_write(0xb8004, val, gd5429); if (svga->gdcaddr == 5) { svga->gdcreg[5] = val; @@ -107,6 +220,7 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p) else svga->writemode = svga->gdcreg[5] & 3; svga->readmode = val & 8; + svga->chain2_read = val & 0x10; // pclog("writemode = %i\n", svga->writemode); return; } @@ -117,12 +231,28 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p) svga->gdcreg[6] = val; gd5429_recalc_mapping(gd5429); } + + /*Hack - the Windows 3.x drivers for the GD5426/8 require VRAM wraparound + for pattern & cursor writes to work correctly, but the BIOSes require + no wrapping to detect memory size - albeit with odd/even mode enabled. + This may be a quirk of address mapping. So change wrapping mode based on + odd/even mode for now*/ + if (gd5429->type == CL_TYPE_GD5426 || gd5429->type == CL_TYPE_GD5428) + { + if (val & 2) /*Odd/Even*/ + svga->decode_mask = 0x1fffff; + else + svga->decode_mask = svga->vram_mask; + } + svga->gdcreg[6] = val; return; } if (svga->gdcaddr > 8) { svga->gdcreg[svga->gdcaddr & 0x3f] = val; + if (gd5429->type < CL_TYPE_GD5426 && (svga->gdcaddr > 0xb)) + return; switch (svga->gdcaddr) { case 0x09: case 0x0a: case 0x0b: @@ -132,7 +262,103 @@ void gd5429_out(uint16_t addr, uint8_t val, void *p) else svga->writemode = svga->gdcreg[5] & 3; break; - } + + case 0x10: + gd5429_mmio_write(0xb8001, val, gd5429); + break; + case 0x11: + gd5429_mmio_write(0xb8005, val, gd5429); + break; + case 0x12: + gd5429_mmio_write(0xb8002, val, gd5429); + break; + case 0x13: + gd5429_mmio_write(0xb8006, val, gd5429); + break; + case 0x14: + gd5429_mmio_write(0xb8003, val, gd5429); + break; + case 0x15: + gd5429_mmio_write(0xb8007, val, gd5429); + break; + + case 0x20: + gd5429_mmio_write(0xb8008, val, gd5429); + break; + case 0x21: + gd5429_mmio_write(0xb8009, val, gd5429); + break; + case 0x22: + gd5429_mmio_write(0xb800a, val, gd5429); + break; + case 0x23: + gd5429_mmio_write(0xb800b, val, gd5429); + break; + case 0x24: + gd5429_mmio_write(0xb800c, val, gd5429); + break; + case 0x25: + gd5429_mmio_write(0xb800d, val, gd5429); + break; + case 0x26: + gd5429_mmio_write(0xb800e, val, gd5429); + break; + case 0x27: + gd5429_mmio_write(0xb800f, val, gd5429); + break; + + case 0x28: + gd5429_mmio_write(0xb8010, val, gd5429); + break; + case 0x29: + gd5429_mmio_write(0xb8011, val, gd5429); + break; + case 0x2a: + gd5429_mmio_write(0xb8012, val, gd5429); + break; + + case 0x2c: + gd5429_mmio_write(0xb8014, val, gd5429); + break; + case 0x2d: + gd5429_mmio_write(0xb8015, val, gd5429); + break; + case 0x2e: + gd5429_mmio_write(0xb8016, val, gd5429); + break; + + case 0x2f: + gd5429_mmio_write(0xb8017, val, gd5429); + break; + case 0x30: + gd5429_mmio_write(0xb8018, val, gd5429); + break; + + case 0x32: + gd5429_mmio_write(0xb801a, val, gd5429); + break; + + case 0x31: + gd5429_mmio_write(0xb8040, val, gd5429); + break; + + case 0x34: + if (gd5429->type <= CL_TYPE_GD5428) + gd5429->blt.trans_col = (gd5429->blt.trans_col & 0xff00) | val; + break; + case 0x35: + if (gd5429->type <= CL_TYPE_GD5428) + gd5429->blt.trans_col = (gd5429->blt.trans_col & 0x00ff) | (val << 8); + break; + case 0x36: + if (gd5429->type <= CL_TYPE_GD5428) + gd5429->blt.trans_mask = (gd5429->blt.trans_mask & 0xff00) | val; + break; + case 0x37: + if (gd5429->type <= CL_TYPE_GD5428) + gd5429->blt.trans_mask = (gd5429->blt.trans_mask & 0x00ff) | (val << 8); + break; + } return; } break; @@ -166,24 +392,83 @@ 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) == 0x3d0) && !(svga->miscout & 1)) + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) addr ^= 0x60; // if (addr != 0x3da) pclog("IN gd5429 %04X\n", addr); switch (addr) { + case 0x3c3: + if (MCA) + return gd5429->vidsys_ena; + break; + + case 0x3c4: + if ((svga->seqaddr & 0x1f) == 0x10) + return (svga->seqaddr & 0x1f) | gd5429->sr10_read; + if ((svga->seqaddr & 0x1f) == 0x11) + return (svga->seqaddr & 0x1f) | gd5429->sr11_read; + return svga->seqaddr & 0x1f; + case 0x3c5: if (svga->seqaddr > 5) { + uint8_t temp; + switch (svga->seqaddr) { case 6: return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; + + case 0x17: + if (gd5429->type < CL_TYPE_GD5426) + break; + temp = svga->seqregs[0x17]; + temp &= ~(7 << 3); + if (gd5429->type == CL_TYPE_GD5426 || gd5429->type == CL_TYPE_GD5428) + { + if (MCA) + temp |= (CL_GD5428_SYSTEM_BUS_MCA << 3); + else if (has_vlb) + temp |= (CL_GD5428_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD5428_SYSTEM_BUS_ISA << 3); + } + else if (gd5429->type == CL_TYPE_GD5429) + { + if (has_vlb) + temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); + } + else + { + if (PCI) + temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); + else if (has_vlb) + temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); + } + return temp; } return svga->seqregs[svga->seqaddr & 0x3f]; } break; + + case 0x3c6: +// pclog("CL read 3c6 %i\n", gd5429->dac_3c6_count); + if (gd5429->dac_3c6_count == 4) + { + gd5429->dac_3c6_count = 0; + return gd5429->hidden_dac_reg; + } + gd5429->dac_3c6_count++; + break; + case 0x3c7: case 0x3c8: case 0x3c9: + gd5429->dac_3c6_count = 0; + break; case 0x3cf: if (svga->gdcaddr > 8) @@ -198,7 +483,26 @@ uint8_t gd5429_in(uint16_t addr, void *p) switch (svga->crtcreg) { case 0x27: /*ID*/ - return 0x9c; /*GD5429*/ + switch (gd5429->type) + { + case CL_TYPE_AVGA2: + return 0x18; /*AVGA2*/ + case CL_TYPE_GD5426: + return 0x90; /*GD5426*/ + case CL_TYPE_GD5428: + return 0x98; /*GD5428*/ + case CL_TYPE_GD5429: + return 0x9c; /*GD5429*/ + case CL_TYPE_GD5430: + return 0xa0; /*GD5430*/ + case CL_TYPE_GD5434: + return 0xa8; /*GD5434*/ + } + break; + case 0x28: /*Class ID*/ + if (gd5429->type == CL_TYPE_GD5430) + return 0xff; /*Standard CL-GD5430*/ + break; } return svga->crtc[svga->crtcreg]; } @@ -210,14 +514,14 @@ 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; + gd5429->bank[0] = (svga->gdcreg[0x09] & 0xff) << 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; + gd5429->bank[1] = (svga->gdcreg[0x0a] & 0xff) << 14; else gd5429->bank[1] = svga->gdcreg[0x0a] << 12; } @@ -229,44 +533,156 @@ 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) + if ((PCI && gd5429->type >= CL_TYPE_GD5430 && !(gd5429->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) || + (MCA && (!(gd5429->pos_regs[2] & 0x01) || !gd5429->vidsys_ena))) { - case 0x0: /*128k at A0000*/ - mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&gd5429->linear_mapping); 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; + return; } + + gd5429->mmio_vram_overlap = 0; + +// pclog("Write mapping %02X %i\n", svga->gdcreg[6], svga->seqregs[0x17] & 0x04); + if (!(svga->seqregs[7] & 0xf0)) + { + mem_mapping_disable(&gd5429->linear_mapping); + switch (svga->gdcreg[6] & 0x0C) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + 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; + gd5429->mmio_vram_overlap = 1; + break; + } + if (gd5429->type >= CL_TYPE_GD5429 && svga->seqregs[0x17] & 0x04) + mem_mapping_set_addr(&gd5429->mmio_mapping, 0xb8000, 0x00100); + else + mem_mapping_disable(&gd5429->mmio_mapping); + } + else + { + uint32_t base, size; + + if (gd5429->type <= CL_TYPE_GD5429 || (!PCI && !has_vlb)) + { + base = (svga->seqregs[7] & 0xf0) << 16; + if (svga->gdcreg[0xb] & 0x20) + size = 1 * 1024 * 1024; + else + size = 2 * 1024 * 1024; + } + else if (PCI) + { + base = gd5429->lfb_base; + size = 4 * 1024 * 1024; + } + else /*VLB*/ + { + base = 128*1024*1024; + size = 4 * 1024 * 1024; + } + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&gd5429->linear_mapping, base, size); + if (gd5429->type >= CL_TYPE_GD5429 && svga->seqregs[0x17] & 0x04) + mem_mapping_set_addr(&gd5429->mmio_mapping, 0xb8000, 0x00100); + else + mem_mapping_disable(&gd5429->mmio_mapping); + } } void gd5429_recalctimings(svga_t *svga) { -// gd5429_t *gd5429 = (gd5429_t *)svga->p; + gd5429_t *gd5429 = (gd5429_t *)svga->p; + int clock = (svga->miscout >> 2) & 3; + int n, d, p; + double vclk; + + if (svga->crtc[0x1b] & 0x10) + svga->rowoffset |= 0x100; + + if (!svga->rowoffset) + svga->rowoffset = 0x100; + + svga->interlace = svga->crtc[0x1a] & 1; 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]); +// pclog("MA now %05X %02X\n", svga->ma_latch, svga->crtc[0x1b]); + + svga->bpp = 8; + if (gd5429->hidden_dac_reg & 0x80) + { + if (gd5429->hidden_dac_reg & 0x40) + { + switch (gd5429->hidden_dac_reg & 0xf) + { + case 0x0: + svga->render = svga_render_15bpp_highres; + svga->bpp = 15; + break; + case 0x1: + svga->render = svga_render_16bpp_highres; + svga->bpp = 16; + break; + case 0x5: + if (gd5429->type >= CL_TYPE_GD5434 && (svga->seqregs[7] & 8)) + { + svga->render = svga_render_32bpp_highres; + svga->bpp = 32; + svga->rowoffset *= 2; + } + else + { + svga->render = svga_render_24bpp_highres; + svga->bpp = 24; + } + break; + } + } + else + { + svga->render = svga_render_15bpp_highres; + svga->bpp = 15; + } + } + + n = svga->seqregs[0xb + clock] & 0x7f; + d = (svga->seqregs[0x1b + clock] >> 1) & 0x1f; + p = svga->seqregs[0x1b + clock] & 1; + + /*Prevent divide by zero during clock setup*/ + if (d && n) + vclk = (14318184.0 * ((float)n / (float)d)) / (float)(1 + p); + else + vclk = 14318184.0; + switch (svga->seqregs[7] & ((gd5429->type >= CL_TYPE_GD5434) ? 0xe : 0x6)) + { + case 2: + vclk /= 2.0; + break; + case 4: + vclk /= 3.0; + break; + } + svga->clock = (cpuclock * (float)(1ull << 32)) / vclk; + + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd5429->vram_mask : 0x3ffff; } void gd5429_hwcursor_draw(svga_t *svga, int displine) @@ -275,55 +691,144 @@ void gd5429_hwcursor_draw(svga_t *svga, int displine) 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, svga->vram[svga->hwcursor_latch.addr], svga->vram[svga->hwcursor_latch.addr + 0x80]); - for (x = 0; x < 32; x += 8) + int line_offset = (svga->seqregs[0x12] & 0x04) ? 16 : 4; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += line_offset; + + if (svga->seqregs[0x12] & 0x04) { - dat[0] = svga->vram[svga->hwcursor_latch.addr]; - dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; - for (xx = 0; xx < 8; xx++) + for (x = 0; x < 64; x += 8) { - if (offset >= svga->hwcursor_latch.x) + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + dat[1] = svga->vram[svga->hwcursor_latch.addr + 8]; + for (xx = 0; xx < 8; xx++) { - if (dat[1] & 0x80) - ((uint32_t *)buffer32->line[displine])[offset + 32] = 0; - if (dat[0] & 0x80) - ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; + 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; } - - offset++; - dat[0] <<= 1; - dat[1] <<= 1; + svga->hwcursor_latch.addr++; } - svga->hwcursor_latch.addr++; + svga->hwcursor_latch.addr += 8; } + else + { + 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++; + } + } + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += line_offset; } void gd5429_write_linear(uint32_t addr, uint8_t val, void *p); -void gd5429_write(uint32_t addr, uint8_t val, void *p) +static 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) +static void gd5429_writew(uint32_t addr, uint16_t val, 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; + + if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + svga_writew_linear(addr, val, svga); + else + { + gd5429_write_linear(addr, val, p); + gd5429_write_linear(addr+1, val >> 8, p); + } +} +static void gd5429_writel(uint32_t addr, uint32_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1]; + + if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + svga_writel_linear(addr, val, svga); + else + { + gd5429_write_linear(addr, val, p); + gd5429_write_linear(addr+1, val >> 8, p); + gd5429_write_linear(addr+2, val >> 16, p); + gd5429_write_linear(addr+3, val >> 24, p); + } +} + +static uint8_t gd5429_read(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1]; + return gd5429_read_linear(addr, gd5429); +} +static uint16_t gd5429_readw(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1]; + + if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + return svga_readw_linear(addr, &gd5429->svga); + return gd5429_read_linear(addr, gd5429) | (gd5429_read_linear(addr+1, gd5429) << 8); +} +static uint32_t gd5429_readl(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1]; + + if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + return svga_readl_linear(addr, &gd5429->svga); + return gd5429_read_linear(addr, gd5429) | (gd5429_read_linear(addr+1, gd5429) << 8) | + (gd5429_read_linear(addr+2, gd5429) << 16) | (gd5429_read_linear(addr+3, gd5429) << 24); } void gd5429_write_linear(uint32_t addr, uint8_t val, void *p) @@ -331,81 +836,220 @@ 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; + int writemask2 = svga->seqregs[2]; - cycles -= video_timing_b; - cycles_lost += video_timing_b; + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; egawrites++; // if (svga_output) pclog("Write LFB %08X %02X ", addr, val); if (!(svga->gdcreg[6] & 1)) svga->fullchange = 2; - if (svga->chain4 && (svga->writemode < 4)) + if (svga->gdcreg[0xb] & GRB_ENHANCED_16BIT) + addr <<= 4; + else if (svga->gdcreg[0xb] & GRB_X8_ADDRESSING) + addr <<= 3; + else if (((svga->chain4 && svga->packed_chain4) || svga->fb_only) && (svga->writemode < 4)) { writemask2 = 1 << (addr & 3); addr &= ~3; } + else if (svga->chain4) + { + writemask2 = 1 << (addr & 3); + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); + } + else if (svga->chain2_write) + { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } else { addr <<= 2; } - addr &= 0x7fffff; - if (addr >= svga->vram_limit) + addr &= svga->decode_mask; + if (addr >= svga->vram_max) return; + addr &= svga->vram_mask; // 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]; + if (svga->gdcreg[0xb] & GRB_ENHANCED_16BIT) + { +// pclog("Writemode 4 : %X ", addr); + svga->changedvram[addr >> 12] = changeframecount; +// pclog("%X %X %02x\n", addr, val, svga->gdcreg[0xb]); + if (val & svga->seqregs[2] & 0x80) + { + svga->vram[addr + 0] = svga->gdcreg[1]; + svga->vram[addr + 1] = svga->gdcreg[0x11]; + } + if (val & svga->seqregs[2] & 0x40) + { + svga->vram[addr + 2] = svga->gdcreg[1]; + svga->vram[addr + 3] = svga->gdcreg[0x11]; + } + if (val & svga->seqregs[2] & 0x20) + { + svga->vram[addr + 4] = svga->gdcreg[1]; + svga->vram[addr + 5] = svga->gdcreg[0x11]; + } + if (val & svga->seqregs[2] & 0x10) + { + svga->vram[addr + 6] = svga->gdcreg[1]; + svga->vram[addr + 7] = svga->gdcreg[0x11]; + } + if (val & svga->seqregs[2] & 0x08) + { + svga->vram[addr + 8] = svga->gdcreg[1]; + svga->vram[addr + 9] = svga->gdcreg[0x11]; + } + if (val & svga->seqregs[2] & 0x04) + { + svga->vram[addr + 10] = svga->gdcreg[1]; + svga->vram[addr + 11] = svga->gdcreg[0x11]; + } + if (val & svga->seqregs[2] & 0x02) + { + svga->vram[addr + 12] = svga->gdcreg[1]; + svga->vram[addr + 13] = svga->gdcreg[0x11]; + } + if (val & svga->seqregs[2] & 0x01) + { + svga->vram[addr + 14] = svga->gdcreg[1]; + svga->vram[addr + 15] = svga->gdcreg[0x11]; + } + } + else + { +// pclog("Writemode 4 : %X ", addr); + svga->changedvram[addr >> 12] = changeframecount; +// pclog("%X %X %02x\n", addr, val, svga->gdcreg[0xb]); + if (val & svga->seqregs[2] & 0x80) + svga->vram[addr + 0] = svga->gdcreg[1]; + if (val & svga->seqregs[2] & 0x40) + svga->vram[addr + 1] = svga->gdcreg[1]; + if (val & svga->seqregs[2] & 0x20) + svga->vram[addr + 2] = svga->gdcreg[1]; + if (val & svga->seqregs[2] & 0x10) + svga->vram[addr + 3] = svga->gdcreg[1]; + if (val & svga->seqregs[2] & 0x08) + svga->vram[addr + 4] = svga->gdcreg[1]; + if (val & svga->seqregs[2] & 0x04) + svga->vram[addr + 5] = svga->gdcreg[1]; + if (val & svga->seqregs[2] & 0x02) + svga->vram[addr + 6] = svga->gdcreg[1]; + if (val & svga->seqregs[2] & 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]; + if (svga->gdcreg[0xb] & GRB_ENHANCED_16BIT) + { +// pclog("Writemode 5 : %X ", addr); + svga->changedvram[addr >> 12] = changeframecount; +// pclog("%X %X %02x\n", addr, val, svga->gdcreg[0xb]); + if (svga->seqregs[2] & 0x80) + { + svga->vram[addr + 0] = (val & 0x80) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 1] = (val & 0x80) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + if (svga->seqregs[2] & 0x40) + { + svga->vram[addr + 2] = (val & 0x40) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 3] = (val & 0x40) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + if (svga->seqregs[2] & 0x20) + { + svga->vram[addr + 4] = (val & 0x20) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 5] = (val & 0x20) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + if (svga->seqregs[2] & 0x10) + { + svga->vram[addr + 6] = (val & 0x10) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 7] = (val & 0x10) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + if (svga->seqregs[2] & 0x08) + { + svga->vram[addr + 8] = (val & 0x08) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 9] = (val & 0x08) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + if (svga->seqregs[2] & 0x04) + { + svga->vram[addr + 10] = (val & 0x04) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 11] = (val & 0x04) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + if (svga->seqregs[2] & 0x02) + { + svga->vram[addr + 12] = (val & 0x02) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 13] = (val & 0x02) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + if (svga->seqregs[2] & 0x01) + { + svga->vram[addr + 14] = (val & 0x01) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 15] = (val & 0x01) ? svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + } + else + { +// pclog("Writemode 5 : %X ", addr); + svga->changedvram[addr >> 12] = changeframecount; +// pclog("%X %X %02x\n", addr, val, svga->gdcreg[0xb]); + if (svga->seqregs[2] & 0x80) + svga->vram[addr + 0] = (val & 0x80) ? svga->gdcreg[1] : svga->gdcreg[0]; + if (svga->seqregs[2] & 0x40) + svga->vram[addr + 1] = (val & 0x40) ? svga->gdcreg[1] : svga->gdcreg[0]; + if (svga->seqregs[2] & 0x20) + svga->vram[addr + 2] = (val & 0x20) ? svga->gdcreg[1] : svga->gdcreg[0]; + if (svga->seqregs[2] & 0x10) + svga->vram[addr + 3] = (val & 0x10) ? svga->gdcreg[1] : svga->gdcreg[0]; + if (svga->seqregs[2] & 0x08) + svga->vram[addr + 4] = (val & 0x08) ? svga->gdcreg[1] : svga->gdcreg[0]; + if (svga->seqregs[2] & 0x04) + svga->vram[addr + 5] = (val & 0x04) ? svga->gdcreg[1] : svga->gdcreg[0]; + if (svga->seqregs[2] & 0x02) + svga->vram[addr + 6] = (val & 0x02) ? svga->gdcreg[1] : svga->gdcreg[0]; + if (svga->seqregs[2] & 0x01) + 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; + if (svga->gdcreg[0xb] & GRB_WRITEMODE_EXT) + { + if (writemask2 & 0x80) svga->vram[addr] = svga->la; + if (writemask2 & 0x40) svga->vram[addr | 0x1] = svga->lb; + if (writemask2 & 0x20) svga->vram[addr | 0x2] = svga->lc; + if (writemask2 & 0x10) svga->vram[addr | 0x3] = svga->ld; + if (svga->gdcreg[0xb] & GRB_8B_LATCHES) + { + if (writemask2 & 0x08) svga->vram[addr | 0x4] = gd5429->latch_ext[0]; + if (writemask2 & 0x04) svga->vram[addr | 0x5] = gd5429->latch_ext[1]; + if (writemask2 & 0x02) svga->vram[addr | 0x6] = gd5429->latch_ext[2]; + if (writemask2 & 0x01) svga->vram[addr | 0x7] = gd5429->latch_ext[3]; + } + } + else + { + 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 (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { if (writemask2 & 1) svga->vram[addr] = val; if (writemask2 & 2) svga->vram[addr | 0x1] = val; @@ -538,49 +1182,276 @@ void gd5429_write_linear(uint32_t addr, uint8_t val, void *p) } } -void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) +uint8_t gd5429_read_linear(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + uint8_t temp, temp2, temp3, temp4; + int readplane = svga->readplane; + uint32_t latch_addr; + + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; + + egareads++; + + if (svga->gdcreg[0xb] & GRB_ENHANCED_16BIT) + latch_addr = (addr << 4) & svga->decode_mask; + else if (svga->gdcreg[0xb] & GRB_X8_ADDRESSING) + latch_addr = (addr << 3) & svga->decode_mask; + else + latch_addr = (addr << 2) & svga->decode_mask; + + if (svga->gdcreg[0xb] & GRB_ENHANCED_16BIT) + addr <<= 4; + else if (svga->gdcreg[0xb] & GRB_X8_ADDRESSING) + addr <<= 3; + else if ((svga->chain4 && svga->packed_chain4) || svga->fb_only) + { + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + return svga->vram[addr & svga->vram_mask]; + } + else if (svga->chain4) + { + readplane = addr & 3; + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); + } + else if (svga->chain2_read) + { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + addr <<= 2; + } + else + addr<<=2; + + addr &= svga->decode_mask; + + if (latch_addr >= svga->vram_max) + { + svga->la = svga->lb = svga->lc = svga->ld = 0xff; + if (svga->gdcreg[0xb] & GRB_8B_LATCHES) + gd5429->latch_ext[0] = gd5429->latch_ext[1] = gd5429->latch_ext[2] = gd5429->latch_ext[3] = 0xff; + } + else + { + latch_addr &= svga->vram_mask; + 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]; + if (svga->gdcreg[0xb] & GRB_8B_LATCHES) + { + gd5429->latch_ext[0] = svga->vram[latch_addr | 0x4]; + gd5429->latch_ext[1] = svga->vram[latch_addr | 0x5]; + gd5429->latch_ext[2] = svga->vram[latch_addr | 0x6]; + gd5429->latch_ext[3] = svga->vram[latch_addr | 0x7]; + } + } + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + + if (svga->readmode) + { + temp = svga->la; + temp ^= (svga->colourcompare & 1) ? 0xff : 0; + temp &= (svga->colournocare & 1) ? 0xff : 0; + temp2 = svga->lb; + temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; + temp2 &= (svga->colournocare & 2) ? 0xff : 0; + temp3 = svga->lc; + temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; + temp3 &= (svga->colournocare & 4) ? 0xff : 0; + temp4 = svga->ld; + temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + temp4 &= (svga->colournocare & 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]; +} + +static void gd5429_writeb_linear(uint32_t addr, uint8_t val, void *p) { gd5429_t *gd5429 = (gd5429_t *)p; svga_t *svga = &gd5429->svga; - pclog("gd5429_start_blit %i\n", count); + if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + svga_write_linear(addr, val, svga); + else + gd5429_write_linear(addr, val & 0xff, gd5429); +} +static void gd5429_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + svga_writew_linear(addr, val, svga); + else + { + gd5429_write_linear(addr, val & 0xff, gd5429); + gd5429_write_linear(addr+1, val >> 8, gd5429); + } +} +static void gd5429_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + if ((svga->writemode < 4) && !(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + svga_writel_linear(addr, val, svga); + else + { + gd5429_write_linear(addr, val & 0xff, gd5429); + gd5429_write_linear(addr+1, val >> 8, gd5429); + gd5429_write_linear(addr+2, val >> 16, gd5429); + gd5429_write_linear(addr+3, val >> 24, gd5429); + } +} + +static uint8_t gd5429_readb_linear(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + return svga_read_linear(addr, &gd5429->svga); + return gd5429_read_linear(addr, gd5429); +} +static uint16_t gd5429_readw_linear(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + return svga_readw_linear(addr, &gd5429->svga); + return gd5429_read_linear(addr, gd5429) | (gd5429_read_linear(addr+1, gd5429) << 8); +} +static uint32_t gd5429_readl_linear(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + if (!(svga->gdcreg[0xb] & (GRB_X8_ADDRESSING | GRB_8B_LATCHES))) + return svga_readl_linear(addr, &gd5429->svga); + return gd5429_read_linear(addr, gd5429) | (gd5429_read_linear(addr+1, gd5429) << 8) | + (gd5429_read_linear(addr+2, gd5429) << 16) | (gd5429_read_linear(addr+3, gd5429) << 24); +} + + +void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + int blt_mask = gd5429->blt.mask & 7; + int x_max = 0; + + switch (gd5429->blt.depth) + { + case BLIT_DEPTH_8: + x_max = 8; + break; + case BLIT_DEPTH_16: + x_max = 16; + blt_mask *= 2; + break; + case BLIT_DEPTH_32: + x_max = 32; + blt_mask *= 4; + break; + } + +// 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); + gd5429->blt.x_count = 0; + if ((gd5429->blt.mode & 0xc0) == 0xc0) + gd5429->blt.y_count = gd5429->blt.src_addr & 7; + else + gd5429->blt.y_count = 0; +// pclog("gd5429_start_blit : size %i, %i %i\n", gd5429->blt.width, gd5429->blt.height, gd5429->blt.x_count); 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); + if (!(svga->seqregs[7] & 0xf0)) + { + 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); + } + else + { + mem_mapping_set_handler(&gd5429->linear_mapping, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l); + mem_mapping_set_p(&gd5429->linear_mapping, gd5429); + } + gd5429_recalc_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); + if (!(svga->seqregs[7] & 0xf0)) + mem_mapping_set_handler(&svga->mapping, gd5429_read, gd5429_readw, gd5429_readl, gd5429_write, gd5429_writew, gd5429_writel); + else + mem_mapping_set_handler(&gd5429->linear_mapping, gd5429_readb_linear, gd5429_readw_linear, gd5429_readl_linear, gd5429_writeb_linear, gd5429_writew_linear, gd5429_writel_linear); gd5429_recalc_mapping(gd5429); } } + else if (gd5429->blt.height_internal == 0xffff) + return; while (count) { uint8_t src = 0, dst; int mask = 0; + int shift; + + if (gd5429->blt.depth == BLIT_DEPTH_32) + shift = (gd5429->blt.x_count & 3) * 8; + else if (gd5429->blt.depth == BLIT_DEPTH_8) + shift = 0; + else + shift = (gd5429->blt.x_count & 1) * 8; 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--; + + switch (gd5429->blt.depth) + { + case BLIT_DEPTH_8: + src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col; + cpu_dat <<= 1; + count--; + break; + case BLIT_DEPTH_16: + src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift); + if (gd5429->blt.x_count & 1) + { + cpu_dat <<= 1; + count--; + } + break; + case BLIT_DEPTH_32: + src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift); + if ((gd5429->blt.x_count & 3) == 3) + { + cpu_dat <<= 1; + count--; + } + break; + } } else { @@ -595,35 +1466,66 @@ void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) switch (gd5429->blt.mode & 0xc0) { case 0x00: - src = svga->vram[gd5429->blt.src_addr & svga->vrammask]; + src = svga->vram[gd5429->blt.src_addr & svga->vram_mask]; 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)]; + switch (gd5429->blt.depth) + { + case BLIT_DEPTH_8: + src = svga->vram[(gd5429->blt.src_addr & (svga->vram_mask & ~7)) + (gd5429->blt.y_count << 3) + (gd5429->blt.x_count & 7)]; + break; + case BLIT_DEPTH_16: + src = svga->vram[(gd5429->blt.src_addr & (svga->vram_mask & ~3)) + (gd5429->blt.y_count << 4) + (gd5429->blt.x_count & 15)]; + break; + case BLIT_DEPTH_32: + src = svga->vram[(gd5429->blt.src_addr & (svga->vram_mask & ~3)) + (gd5429->blt.y_count << 5) + (gd5429->blt.x_count & 31)]; + break; + } 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) + switch (gd5429->blt.depth) { - gd5429->blt.x_count = 0; - gd5429->blt.src_addr++; + case BLIT_DEPTH_8: + mask = svga->vram[gd5429->blt.src_addr & svga->vram_mask] & (0x80 >> gd5429->blt.x_count); + src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col; + break; + case BLIT_DEPTH_16: + mask = svga->vram[gd5429->blt.src_addr & svga->vram_mask] & (0x80 >> (gd5429->blt.x_count >> 1)); + src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift); + break; + case BLIT_DEPTH_32: + mask = svga->vram[gd5429->blt.src_addr & svga->vram_mask] & (0x80 >> (gd5429->blt.x_count >> 2)); + src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift); + break; } 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; + case 0xc0: + switch (gd5429->blt.depth) + { + case BLIT_DEPTH_8: + mask = svga->vram[(gd5429->blt.src_addr & svga->vram_mask & ~7) | gd5429->blt.y_count] & (0x80 >> gd5429->blt.x_count); + src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col; + break; + case BLIT_DEPTH_16: + mask = svga->vram[(gd5429->blt.src_addr & svga->vram_mask & ~7) | gd5429->blt.y_count] & (0x80 >> (gd5429->blt.x_count >> 1)); + src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift); + break; + case BLIT_DEPTH_32: + mask = svga->vram[(gd5429->blt.src_addr & svga->vram_mask & ~7) | gd5429->blt.y_count] & (0x80 >> (gd5429->blt.x_count >> 2)); + src = mask ? (gd5429->blt.fg_col >> shift) : (gd5429->blt.bg_col >> shift); + break; + } break; } count--; } - dst = svga->vram[gd5429->blt.dst_addr & svga->vrammask]; - svga->changedvram[(gd5429->blt.dst_addr & svga->vrammask) >> 12] = changeframecount; + dst = svga->vram[gd5429->blt.dst_addr & svga->vram_mask]; + svga->changedvram[(gd5429->blt.dst_addr & svga->vram_mask) >> 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); +// 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->vram_mask, svga->vram[gd5429->blt.src_addr & svga->vram_mask], 0x80 >> (gd5429->blt.dst_addr & 7), src, dst); switch (gd5429->blt.rop) { case 0x00: dst = 0; break; @@ -643,13 +1545,30 @@ void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) case 0xd6: dst = ~src | dst; break; case 0xda: dst = ~(src & dst); break; } - pclog("%02X %02X\n", dst, mask); + //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; + if (gd5429->type <= CL_TYPE_GD5428) + { + if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask && + (!(gd5429->blt.mode & 0x08) || (dst & gd5429->blt.trans_mask) != gd5429->blt.trans_col)) + svga->vram[gd5429->blt.dst_addr & svga->vram_mask] = dst; + } + else + { + if ((gd5429->blt.width_backup - gd5429->blt.width) >= blt_mask && + !((gd5429->blt.mode & 0x08) && !mask)) + svga->vram[gd5429->blt.dst_addr & svga->vram_mask] = dst; + } gd5429->blt.dst_addr += ((gd5429->blt.mode & 0x01) ? -1 : 1); + + gd5429->blt.x_count++; + if (gd5429->blt.x_count == x_max) + { + gd5429->blt.x_count = 0; + if ((gd5429->blt.mode & 0xc0) == 0x80) + gd5429->blt.src_addr++; + } gd5429->blt.width--; @@ -664,28 +1583,29 @@ void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) 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.x_count = 0; + if (gd5429->blt.mode & 0x01) + gd5429->blt.y_count = (gd5429->blt.y_count - 1) & 7; + else + gd5429->blt.y_count = (gd5429->blt.y_count + 1) & 7; 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); + if (!(svga->seqregs[7] & 0xf0)) + mem_mapping_set_handler(&svga->mapping, gd5429_read, gd5429_readw, gd5429_readl, gd5429_write, gd5429_writew, gd5429_writel); + else + mem_mapping_set_handler(&gd5429->linear_mapping, gd5429_readb_linear, gd5429_readw_linear, gd5429_readl_linear, gd5429_writeb_linear, gd5429_writew_linear, gd5429_writel_linear); +// 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; @@ -697,114 +1617,222 @@ void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) } } -void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p) +static 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) + if ((addr & ~0xff) == 0xb8000) { - 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; + // pclog("MMIO write %08X %02X\n", addr, val); + switch (addr & 0xff) + { + case 0x00: + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xffffff00) | val; + else + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xff00) | val; + break; + case 0x01: + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xffff00ff) | (val << 8); + else + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0x00ff) | (val << 8); + break; + case 0x02: + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xff00ffff) | (val << 16); + break; + case 0x03: + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0x00ffffff) | (val << 24); + 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 0x04: + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xffffff00) | val; + else + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xff00) | val; + break; + case 0x05: + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xffff00ff) | (val << 8); + else + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0x00ff) | (val << 8); + break; + case 0x06: + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xff00ffff) | (val << 16); + break; + case 0x07: + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0x00ffffff) | (val << 24); + 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 0x08: + gd5429->blt.width = (gd5429->blt.width & 0xff00) | val; + break; + case 0x09: + gd5429->blt.width = (gd5429->blt.width & 0x00ff) | (val << 8); + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.width &= 0x1fff; + else + gd5429->blt.width &= 0x07ff; + break; + case 0x0a: + gd5429->blt.height = (gd5429->blt.height & 0xff00) | val; + break; + case 0x0b: + gd5429->blt.height = (gd5429->blt.height & 0x00ff) | (val << 8); + gd5429->blt.height &= 0x03ff; + 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 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); + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.dst_addr &= 0x3fffff; + else + gd5429->blt.dst_addr &= 0x1fffff; + 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 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); + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.src_addr &= 0x3fffff; + else + gd5429->blt.src_addr &= 0x1fffff; + break; - case 0x17: - gd5429->blt.mask = val; - break; - case 0x18: - gd5429->blt.mode = val; - break; + case 0x17: + gd5429->blt.mask = val; + break; + case 0x18: + gd5429->blt.mode = val; + if (gd5429->type >= CL_TYPE_GD5434) + gd5429->blt.depth = (val >> 4) & 3; + else + gd5429->blt.depth = (val >> 4) & 1; + break; - case 0x1a: - gd5429->blt.rop = val; - break; + case 0x1a: + gd5429->blt.rop = val; + break; - case 0x40: - if (val & 0x02) - gd5429_start_blit(0, -1, gd5429); - break; + case 0x40: + if (val & 0x02) + gd5429_start_blit(0, -1, gd5429); + break; + } } + else if (gd5429->mmio_vram_overlap) + gd5429_write(addr, val, gd5429); +} +static void gd5429_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + if ((addr & ~0xff) == 0xb8000) + { + gd5429_mmio_write(addr, val & 0xff, gd5429); + gd5429_mmio_write(addr + 1, val >> 8, gd5429); + } + else if (gd5429->mmio_vram_overlap) + gd5429_writew(addr, val, gd5429); +} +static void gd5429_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + if ((addr & ~0xff) == 0xb8000) + { + gd5429_mmio_writew(addr, val & 0xffff, gd5429); + gd5429_mmio_writew(addr + 2, val >> 16, gd5429); + } + else if (gd5429->mmio_vram_overlap) + gd5429_writel(addr, val, gd5429); } -uint8_t gd5429_mmio_read(uint32_t addr, void *p) +static 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) + gd5429_t *gd5429 = (gd5429_t *)p; + + if ((addr & ~0xff) == 0xb8000) { - case 0x40: /*BLT status*/ - return 0; +// pclog("MMIO read %08X\n", addr); + switch (addr & 0xff) + { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ } - return 0xff; /*All other registers read-only*/ + if (gd5429->mmio_vram_overlap) + return gd5429_read(addr, gd5429); + return 0xff; +} +static uint16_t gd5429_mmio_readw(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + if ((addr & ~0xff) == 0xb8000) + return gd5429_mmio_read(addr, gd5429) | (gd5429_mmio_read(addr+1, gd5429) << 8); + if (gd5429->mmio_vram_overlap) + return gd5429_readw(addr, gd5429); + return 0xffff; +} +static uint32_t gd5429_mmio_readl(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + if ((addr & ~0xff) == 0xb8000) + return gd5429_mmio_readw(addr, gd5429) | (gd5429_mmio_readw(addr+2, gd5429) << 16); + if (gd5429->mmio_vram_overlap) + return gd5429_readl(addr, gd5429); + return 0xffffffff; } 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); + gd5429_t *gd5429 = (gd5429_t *)p; + +// pclog("gd5429_blt_write_w %08X %08X\n", addr, val); + if (!gd5429->blt.mem_word_sel) + gd5429->blt.mem_word_save = val; + else + gd5429_start_blit(gd5429->blt.mem_word_save | (val << 16), 32, p); + gd5429->blt.mem_word_sel = !gd5429->blt.mem_word_sel; + } 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)); + + gd5429->blt.mem_word_sel = 0; +// 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); @@ -816,38 +1844,321 @@ void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *p) gd5429_start_blit(val, 32, p); } -void *gd5429_init() +uint8_t ibm_gd5428_mca_read(int port, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + +// pclog("gd5429_pro_mcv_read: port=%04x %02x %04x:%04x\n", port, gd5429->pos_regs[port & 7], CS, cpu_state.pc); + + return gd5429->pos_regs[port & 7]; +} + +static void ibm_gd5428_mapping_update(gd5429_t *gd5429) +{ + gd5429_recalc_mapping(gd5429); + + io_removehandler(0x03a0, 0x0023, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + io_removehandler(0x03c4, 0x001c, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + if ((gd5429->pos_regs[2] & 0x01) && gd5429->vidsys_ena) + { +// pclog(" GD5429 enable registers\n"); + io_sethandler(0x03c0, 0x0003, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + io_sethandler(0x03c4, 0x001c, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + if (!(gd5429->svga.miscout & 1)) + io_sethandler(0x03a0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + gd5429->svga.override = 0; + if (mb_vga) + svga_set_override(mb_vga, 1); + } + else + { +// pclog(" GD5429 disable registers\n"); + gd5429->svga.override = 1; + if (mb_vga) + svga_set_override(mb_vga, 0); + } +} + +void ibm_gd5428_mca_write(int port, uint8_t val, void *p) +{ +// svga_set_override(voodoo->svga, val & 1); + gd5429_t *gd5429 = (gd5429_t *)p; + +// pclog("gd5429_pro_mcv_write: port=%04x val=%02x\n", port, val); + + if (port < 0x102) + return; + gd5429->pos_regs[port & 7] = val; + + if ((port & 7) == 2) + { + mem_mapping_disable(&gd5429->bios_rom.mapping); + io_removehandler(0x03c3, 0x0001, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + if (gd5429->pos_regs[2] & 0x01) + { +// pclog("Enable BIOS mapping\n"); + mem_mapping_enable(&gd5429->bios_rom.mapping); + io_sethandler(0x03c3, 0x0001, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + } +// else +// pclog("Disable BIOS mapping\n"); + } + + ibm_gd5428_mapping_update(gd5429); +} + +static void ibm_gd5428_mca_reset(void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + +// pclog("ibm_gd5428_mca_reset\n"); + gd5429->vidsys_ena = 0; + ibm_gd5428_mca_write(0x102, 0, gd5429); +} + +static uint8_t cl_pci_read(int func, int addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + +// pclog("CL PCI read %08X\n", addr); + switch (addr) + { + case 0x00: return 0x13; /*Cirrus Logic*/ + case 0x01: return 0x10; + + case 0x02: + switch (gd5429->type) + { + case CL_TYPE_GD5430: + return 0xa0; + case CL_TYPE_GD5434: + return 0xa8; + } + return 0xff; + case 0x03: return 0x00; + + case PCI_REG_COMMAND: + return gd5429->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 0 << 1; /*Fast 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 0x08; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return gd5429->lfb_base >> 24; + + case 0x30: return gd5429->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return gd5429->pci_regs[0x32]; + case 0x33: return gd5429->pci_regs[0x33]; + + case 0x3c: return gd5429->int_line; + case 0x3d: return PCI_INTA; + } + return 0; +} + +static void cl_pci_write(int func, int addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + +// pclog("cl_pci_write: addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case PCI_REG_COMMAND: + gd5429->pci_regs[PCI_REG_COMMAND] = val & 0x23; + io_removehandler(0x03c0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + if (val & PCI_COMMAND_IO) + io_sethandler(0x03c0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + gd5429_recalc_mapping(gd5429); + break; + + case 0x13: + gd5429->lfb_base = val << 24; + gd5429_recalc_mapping(gd5429); + break; + + case 0x30: case 0x32: case 0x33: + gd5429->pci_regs[addr] = val; + if (gd5429->pci_regs[0x30] & 0x01) + { + uint32_t addr = (gd5429->pci_regs[0x32] << 16) | (gd5429->pci_regs[0x33] << 24); + mem_mapping_set_addr(&gd5429->bios_rom.mapping, addr, 0x8000); + } + else + mem_mapping_disable(&gd5429->bios_rom.mapping); + return; + + case 0x3c: + gd5429->int_line = val; + return; + } +} + +static void *cl_init(int type, char *fn, int pci_card, uint32_t force_vram_size) { gd5429_t *gd5429 = malloc(sizeof(gd5429_t)); svga_t *svga = &gd5429->svga; + int vram_size; 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*/ + if (force_vram_size) + vram_size = force_vram_size; + else + vram_size = device_get_config_int("memory"); + if (vram_size >= 256) + gd5429->vram_mask = (vram_size << 10) - 1; + else + gd5429->vram_mask = (vram_size << 20) - 1; + + gd5429->type = type; + + if (fn) + rom_init(&gd5429->bios_rom, fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&gd5429->svga, gd5429, (vram_size >= 256) ? (vram_size << 10) : (vram_size << 20), 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_handler(&gd5429->svga.mapping, gd5429_read, gd5429_readw, gd5429_readl, gd5429_write, gd5429_writew, gd5429_writel); 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); + mem_mapping_add(&gd5429->mmio_mapping, 0, 0, gd5429_mmio_read, gd5429_mmio_readw, gd5429_mmio_readl, gd5429_mmio_write, gd5429_mmio_writew, gd5429_mmio_writel, NULL, 0, gd5429); + mem_mapping_add(&gd5429->linear_mapping, 0, 0, gd5429_readb_linear, gd5429_readw_linear, gd5429_readl_linear, gd5429_writeb_linear, gd5429_writew_linear, gd5429_writel_linear, NULL, 0, gd5429); io_sethandler(0x03c0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + if (type == CL_TYPE_AVGA2) + { + io_sethandler(0x0102, 0x0001, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + io_sethandler(0x46e8, 0x0002, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + svga->decode_mask = svga->vram_mask; + } svga->hwcursor.yoff = 32; svga->hwcursor.xoff = 0; gd5429->bank[1] = 0x8000; + + /*Default VCLK values*/ + svga->seqregs[0xb] = 0x66; + svga->seqregs[0xc] = 0x5b; + svga->seqregs[0xd] = 0x45; + svga->seqregs[0xe] = 0x7e; + svga->seqregs[0x1b] = 0x3b; + svga->seqregs[0x1c] = 0x2f; + svga->seqregs[0x1d] = 0x30; + svga->seqregs[0x1e] = 0x33; + + if (PCI && type >= CL_TYPE_GD5430) + { + if (pci_card != -1) + { + pci_add_specific(pci_card, cl_pci_read, cl_pci_write, gd5429); + gd5429->card = pci_card; + } + else + gd5429->card = pci_add(cl_pci_read, cl_pci_write, gd5429); + + gd5429->pci_regs[0x04] = 7; + + gd5429->pci_regs[0x30] = 0x00; + gd5429->pci_regs[0x32] = 0x0c; + gd5429->pci_regs[0x33] = 0x00; + } return gd5429; } + +static void *avga2_init() +{ + return cl_init(CL_TYPE_AVGA2, "avga2vram.vbi", -1, 0); +} +static void *avga2_cbm_sl386sx_init() +{ + return cl_init(CL_TYPE_AVGA2, "cbm_sl386sx25/c000.rom", -1, 0); +} +static void *gd5426_ps1_init() +{ + return cl_init(CL_TYPE_GD5426, NULL, -1, 1); +} +static void *gd5428_init() +{ + return cl_init(CL_TYPE_GD5428, "Machspeed_VGA_GUI_2100_VLB.vbi", -1, 0); +} +static void *ibm_gd5428_init() +{ + gd5429_t *gd5429; + svga_t *mb_vga = svga_get_pri(); + + gd5429 = cl_init(CL_TYPE_GD5428, "SVGA141.ROM", -1, 1); /*Only supports 1MB*/ + gd5429->mb_vga = mb_vga; + + mca_add(ibm_gd5428_mca_read, ibm_gd5428_mca_write, ibm_gd5428_mca_reset, gd5429); + gd5429->pos_regs[0] = 0x7b; + gd5429->pos_regs[1] = 0x91; + gd5429->pos_regs[2] = 0; + + gd5429_recalc_mapping(gd5429); + io_removehandler(0x03a0, 0x0040, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + gd5429->svga.override = 1; + mem_mapping_disable(&gd5429->bios_rom.mapping); + io_sethandler(0x46e8, 0x0001, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + + return gd5429; +} +static void *gd5429_init() +{ + return cl_init(CL_TYPE_GD5429, "5429.vbi", -1, 0); +} +static void *gd5430_init() +{ + return cl_init(CL_TYPE_GD5430, "gd5430/pci.bin", -1, 0); +} +static void *gd5430_pb570_init() +{ + return cl_init(CL_TYPE_GD5430, "pb570/gd5430.bin", 8, 0); +} +static void *gd5434_init() +{ + return cl_init(CL_TYPE_GD5434, "gd5434.bin", -1, 0); +} +static void *gd5434_pb520r_init() +{ + return cl_init(CL_TYPE_GD5434, "pb520r/gd5434.bin", 3, 0); +} + +static int avga2_available() +{ + return rom_present("avga2vram.vbi"); +} +static int gd5428_available() +{ + return rom_present("Machspeed_VGA_GUI_2100_VLB.vbi"); +} +static int ibm_gd5428_available() +{ + return rom_present(/*"FILE.ROM"*/"SVGA141.ROM"); +} static int gd5429_available() { - return rom_present("roms/5429.vbi"); + return rom_present("5429.vbi"); +} +static int gd5430_available() +{ + return rom_present("gd5430/pci.bin"); +} +static int gd5434_available() +{ + return rom_present("gd5434.bin"); } void gd5429_close(void *p) @@ -880,14 +2191,212 @@ void gd5429_add_status_info(char *s, int max_len, void *p) svga_add_status_info(s, max_len, &gd5429->svga); } +static device_config_t avga2_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 gd5429_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 + } +}; +static device_config_t gd5434_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +device_t avga2_device = +{ + "AVGA2 / Cirrus Logic GD5402", + 0, + avga2_init, + gd5429_close, + avga2_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + avga2_config +}; + +device_t avga2_cbm_sl386sx_device = +{ + "AVGA2 (Commodore SL386SX-25)", + 0, + avga2_cbm_sl386sx_init, + gd5429_close, + gd5430_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + avga2_config +}; + +device_t gd5426_ps1_device = +{ + "Cirrus Logic GD5426 (IBM PS/1)", + 0, + gd5426_ps1_init, + gd5429_close, + NULL, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + NULL +}; + +device_t gd5428_device = +{ + "Cirrus Logic GD5428", + 0, + gd5428_init, + gd5429_close, + gd5428_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + gd5429_config +}; + +device_t ibm_gd5428_device = +{ + "IBM 1MB SVGA Adapter/A (Cirrus Logic GD5428)", + DEVICE_MCA, + ibm_gd5428_init, + gd5429_close, + ibm_gd5428_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + NULL +}; + device_t gd5429_device = { "Cirrus Logic GD5429", - DEVICE_NOT_WORKING, + 0, gd5429_init, gd5429_close, gd5429_available, gd5429_speed_changed, gd5429_force_redraw, - gd5429_add_status_info + gd5429_add_status_info, + gd5429_config +}; + +device_t gd5430_device = +{ + "Cirrus Logic GD5430", + 0, + gd5430_init, + gd5429_close, + gd5430_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + gd5429_config +}; + +device_t gd5430_pb570_device = +{ + "Cirrus Logic GD5430 (PB570)", + 0, + gd5430_pb570_init, + gd5429_close, + gd5430_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + gd5429_config +}; + +device_t gd5434_device = +{ + "Cirrus Logic GD5434", + 0, + gd5434_init, + gd5429_close, + gd5434_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + gd5434_config +}; + +device_t gd5434_pb520r_device = +{ + "Cirrus Logic GD5434 (PB520r)", + 0, + gd5434_pb520r_init, + gd5429_close, + gd5434_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info, + gd5434_config }; diff --git a/src/vid_cl5429.h b/src/vid_cl5429.h index b4a159c..edeab65 100644 --- a/src/vid_cl5429.h +++ b/src/vid_cl5429.h @@ -1 +1,11 @@ +extern device_t avga2_device; +extern device_t avga2_cbm_sl386sx_device; +extern device_t gd5426_ps1_device; +extern device_t gd5428_device; +extern device_t ibm_gd5428_device; extern device_t gd5429_device; +extern device_t gd5429_reply_m25_device; +extern device_t gd5430_device; +extern device_t gd5430_pb570_device; +extern device_t gd5434_device; +extern device_t gd5434_pb520r_device; diff --git a/src/vid_colorplus.c b/src/vid_colorplus.c index 31110bd..298cee2 100644 --- a/src/vid_colorplus.c +++ b/src/vid_colorplus.c @@ -101,10 +101,10 @@ void colorplus_poll(void *p) int cols[4]; int col; int oldsc; - static const int cols16[16] = { 0x10,0x12,0x14,0x16, - 0x18,0x1A,0x1C,0x1E, - 0x11,0x13,0x15,0x17, - 0x19,0x1B,0x1D,0x1F }; + static const int cols16[16] = { 0x0,0x2,0x4,0x6, + 0x8,0xA,0xC,0xE, + 0x1,0x3,0x5,0x7, + 0x9,0xB,0xD,0xF }; uint8_t *plane0 = colorplus->cga.vram; uint8_t *plane1 = colorplus->cga.vram + 0x4000; @@ -119,7 +119,7 @@ void colorplus_poll(void *p) if (!colorplus->cga.linepos) { - colorplus->cga.vidtime += colorplus->cga.dispofftime; + timer_advance_u64(&colorplus->cga.timer, colorplus->cga.dispofftime); colorplus->cga.cgastat |= 1; colorplus->cga.linepos = 1; oldsc = colorplus->cga.sc; @@ -137,8 +137,8 @@ void colorplus_poll(void *p) /* Left / right border */ for (c = 0; c < 8; c++) { - buffer->line[colorplus->cga.displine][c] = - buffer->line[colorplus->cga.displine][c + (colorplus->cga.crtc[1] << 4) + 8] = (colorplus->cga.cgacol & 15) + 16; + ((uint32_t *)buffer32->line[colorplus->cga.displine])[c] = + ((uint32_t *)buffer32->line[colorplus->cga.displine])[c + (colorplus->cga.crtc[1] << 4) + 8] = cgapal[colorplus->cga.cgacol & 15]; } if (colorplus->control & COLORPLUS_320x200_MODE) { @@ -151,9 +151,9 @@ void colorplus_poll(void *p) colorplus->cga.ma++; for (c = 0; c < 8; c++) { - buffer->line[colorplus->cga.displine][(x << 4) + (c << 1) + 8] = - buffer->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = - cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]; + ((uint32_t *)buffer32->line[colorplus->cga.displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[colorplus->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = + cgapal[cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]]; dat0 <<= 2; dat1 <<= 2; } @@ -161,25 +161,25 @@ void colorplus_poll(void *p) } else if (colorplus->control & COLORPLUS_640x200_MODE) { - cols[0] = (colorplus->cga.cgacol & 15) | 16; - col = (colorplus->cga.cgacol & 16) ? 24 : 16; + cols[0] = cgapal[colorplus->cga.cgacol & 15]; + col = (colorplus->cga.cgacol & 16) ? 8 : 0; if (colorplus->cga.cgamode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; + cols[1] = cgapal[col | 3]; + cols[2] = cgapal[col | 4]; + cols[3] = cgapal[col | 7]; } else if (colorplus->cga.cgacol & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; + cols[1] = cgapal[col | 3]; + cols[2] = cgapal[col | 5]; + cols[3] = cgapal[col | 7]; } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; + cols[1] = cgapal[col | 2]; + cols[2] = cgapal[col | 4]; + cols[3] = cgapal[col | 6]; } for (x = 0; x < colorplus->cga.crtc[1]; x++) { @@ -190,7 +190,7 @@ void colorplus_poll(void *p) colorplus->cga.ma++; for (c = 0; c < 16; c++) { - buffer->line[colorplus->cga.displine][(x << 4) + c + 8] = + ((uint32_t *)buffer32->line[colorplus->cga.displine])[(x << 4) + c + 8] = cols[(dat0 >> 15) | ((dat1 >> 15) << 1)]; dat0 <<= 1; dat1 <<= 1; @@ -200,8 +200,8 @@ void colorplus_poll(void *p) } else /* Top / bottom border */ { - cols[0] = (colorplus->cga.cgacol & 15) + 16; - hline(buffer, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); + cols[0] = cgapal[colorplus->cga.cgacol & 15]; + hline(buffer32, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); } x = (colorplus->cga.crtc[1] << 4) + 16; @@ -215,7 +215,7 @@ void colorplus_poll(void *p) } else { - colorplus->cga.vidtime += colorplus->cga.dispontime; + timer_advance_u64(&colorplus->cga.timer, colorplus->cga.dispontime); colorplus->cga.linepos = 0; if (colorplus->cga.vsynctime) { @@ -283,7 +283,7 @@ void colorplus_poll(void *p) updatewindowsize(xsize, (ysize << 1) + 16); } - video_blit_memtoscreen_8(0, colorplus->cga.firstline - 4, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); + video_blit_memtoscreen(0, colorplus->cga.firstline - 4, 0, (colorplus->cga.lastline - colorplus->cga.firstline) + 8, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); frames++; video_res_x = xsize - 16; @@ -336,15 +336,21 @@ void colorplus_poll(void *p) void *colorplus_init() { + int display_type, contrast; colorplus_t *colorplus = malloc(sizeof(colorplus_t)); memset(colorplus, 0, sizeof(colorplus_t)); colorplus->cga.vram = malloc(0x8000); colorplus->cga.composite = colorplus->cga.snow_enabled = 0; + + display_type = device_get_config_int("display_type"); + contrast = device_get_config_int("contrast"); - timer_add(colorplus_poll, &colorplus->cga.vidtime, TIMER_ALWAYS_ENABLED, colorplus); + timer_add(&colorplus->cga.timer, colorplus_poll, colorplus, 1); mem_mapping_add(&colorplus->cga.mapping, 0xb8000, 0x08000, colorplus_read, NULL, NULL, colorplus_write, NULL, NULL, NULL, 0, colorplus); io_sethandler(0x03d0, 0x0010, colorplus_in, NULL, NULL, colorplus_out, NULL, NULL, colorplus); + + cgapal_rebuild(display_type, contrast); return colorplus; } @@ -364,6 +370,51 @@ void colorplus_speed_changed(void *p) cga_recalctimings(&colorplus->cga); } +device_config_t colorplus_config[] = +{ + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "RGB", + .value = DISPLAY_RGB + }, + { + .description = "RGB (no brown)", + .value = DISPLAY_RGB_NO_BROWN + }, + { + .description = "Green Monochrome", + .value = DISPLAY_GREEN + }, + { + .description = "Amber Monochrome", + .value = DISPLAY_AMBER + }, + { + .description = "White Monochrome", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + }, + .default_int = DISPLAY_RGB + }, + { + .name = "contrast", + .description = "Alternate monochrome contrast", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .type = -1 + } +}; + device_t colorplus_device = { "Colorplus", @@ -374,5 +425,5 @@ device_t colorplus_device = colorplus_speed_changed, NULL, NULL, - NULL + colorplus_config }; diff --git a/src/vid_compaq_cga.c b/src/vid_compaq_cga.c new file mode 100644 index 0000000..f92bd84 --- /dev/null +++ b/src/vid_compaq_cga.c @@ -0,0 +1,393 @@ +/*Compaq CGA emulation*/ +#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_compaq_cga.h" + +typedef struct compaq_cga_t +{ + cga_t cga; + +} compaq_cga_t; + +static uint8_t mdaattr[256][2][2]; + +void compaq_cga_recalctimings(compaq_cga_t *self) +{ + double _dispontime, _dispofftime, disptime; + disptime = self->cga.crtc[0] + 1; + _dispontime = self->cga.crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + self->cga.dispontime = (uint64_t)_dispontime; + self->cga.dispofftime = (uint64_t)_dispofftime; +} + +void compaq_cga_poll(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + uint16_t ca = (self->cga.crtc[15] | (self->cga.crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint32_t cols[4]; + int oldsc; + int underline; + int blink; + + /* If in graphics mode or character height is not 13, behave as CGA */ + if ((self->cga.cgamode & 0x12) || (self->cga.crtc[9] != 13)) + { + cga_poll(&self->cga); + return; + } + +/* We are in Compaq 350-line CGA territory */ + if (!self->cga.linepos) + { + timer_advance_u64(&self->cga.timer, self->cga.dispofftime); + self->cga.cgastat |= 1; + self->cga.linepos = 1; + oldsc = self->cga.sc; + if ((self->cga.crtc[8] & 3) == 3) + self->cga.sc = ((self->cga.sc << 1) + self->cga.oddeven) & 7; + if (self->cga.cgadispon) + { + if (self->cga.displine < self->cga.firstline) + { + self->cga.firstline = self->cga.displine; + video_wait_for_buffer(); +// printf("Firstline %i\n",firstline); + } + self->cga.lastline = self->cga.displine; + + cols[0] = (self->cga.cgacol & 15); + + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[self->cga.displine])[c] = cols[0]; + if (self->cga.cgamode & 1) + ((uint32_t *)buffer32->line[self->cga.displine])[c + (self->cga.crtc[1] << 3) + 8] = cols[0]; + else + ((uint32_t *)buffer32->line[self->cga.displine])[c + (self->cga.crtc[1] << 4) + 8] = cols[0]; + } + if (self->cga.cgamode & 1) + { + for (x = 0; x < self->cga.crtc[1]; x++) + { + chr = self->cga.charbuffer[x << 1]; + attr = self->cga.charbuffer[(x << 1) + 1]; + drawcursor = ((self->cga.ma == ca) && self->cga.con && self->cga.cursoron); + underline = 0; + blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + if (self->cga.cgamode & 0x80) + { + cols[0] = mdaattr[attr][blink][0]; + cols[1] = mdaattr[attr][blink][1]; + if (self->cga.sc == 12 && (attr & 7) == 1) underline = 1; + } + else if (self->cga.cgamode & 0x20) + { + cols[1] = attr & 15; + cols[0] = (attr >> 4) & 7; + if (blink) + cols[1] = cols[0]; + } + else + { + cols[1] = attr & 15; + cols[0] = attr >> 4; + } + if (underline) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = mdaattr[attr][blink][1]; + } + else if (drawcursor) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + } + self->cga.ma++; + } + } + else + { + for (x = 0; x < self->cga.crtc[1]; x++) + { + chr = self->cga.vram[((self->cga.ma << 1) & 0x3fff)]; + attr = self->cga.vram[(((self->cga.ma << 1) + 1) & 0x3fff)]; + drawcursor = ((self->cga.ma == ca) && self->cga.con && self->cga.cursoron); + underline = 0; + blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + if (self->cga.cgamode & 0x80) + { + cols[0] = mdaattr[attr][blink][0]; + cols[1] = mdaattr[attr][blink][1]; + if (self->cga.sc == 12 && (attr & 7) == 1) underline = 1; + } + else if (self->cga.cgamode & 0x20) + { + cols[1] = attr & 15; + cols[0] = (attr >> 4) & 7; + if (blink) + cols[1] = cols[0]; + } + else + { + cols[1] = attr & 15; + cols[0] = attr >> 4; + } + self->cga.ma++; + if (underline) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 9] = mdaattr[attr][blink][1]; + } + else if (drawcursor) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + } + else + { + cols[0] = (self->cga.cgacol & 15); + if (self->cga.cgamode & 1) hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 4) + 16, cols[0]); + } + + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3) + 16; + else x = (self->cga.crtc[1] << 4) + 16; + + for (c = 0; c < x; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[c] = cgapal[((uint32_t *)buffer32->line[self->cga.displine])[c] & 0xf]; + + self->cga.sc = oldsc; + if (self->cga.vc == self->cga.crtc[7] && !self->cga.sc) + self->cga.cgastat |= 8; + self->cga.displine++; + if (self->cga.displine >= 500) + self->cga.displine = 0; + } + else + { + timer_advance_u64(&self->cga.timer, self->cga.dispontime); + self->cga.linepos = 0; + if (self->cga.vsynctime) + { + self->cga.vsynctime--; + if (!self->cga.vsynctime) + self->cga.cgastat &= ~8; + } + if (self->cga.sc == (self->cga.crtc[11] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[11] & 31) >> 1))) + { + self->cga.con = 0; + self->cga.coff = 1; + } + if ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == (self->cga.crtc[9] >> 1)) + self->cga.maback = self->cga.ma; + if (self->cga.vadj) + { + self->cga.sc++; + self->cga.sc &= 31; + self->cga.ma = self->cga.maback; + self->cga.vadj--; + if (!self->cga.vadj) + { + self->cga.cgadispon = 1; + self->cga.ma = self->cga.maback = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x3fff; + self->cga.sc = 0; + } + } + else if (self->cga.sc == self->cga.crtc[9]) + { + self->cga.maback = self->cga.ma; + self->cga.sc = 0; + oldvc = self->cga.vc; + self->cga.vc++; + self->cga.vc &= 127; + + if (self->cga.vc == self->cga.crtc[6]) + self->cga.cgadispon = 0; + + if (oldvc == self->cga.crtc[4]) + { + self->cga.vc = 0; + self->cga.vadj = self->cga.crtc[5]; + if (!self->cga.vadj) self->cga.cgadispon = 1; + if (!self->cga.vadj) self->cga.ma = self->cga.maback = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x3fff; + if ((self->cga.crtc[10] & 0x60) == 0x20) self->cga.cursoron = 0; + else self->cga.cursoron = self->cga.cgablink & 8; + } + + if (self->cga.vc == self->cga.crtc[7]) + { + self->cga.cgadispon = 0; + self->cga.displine = 0; + self->cga.vsynctime = 16; + if (self->cga.crtc[7]) + { + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3) + 16; + else x = (self->cga.crtc[1] << 4) + 16; + self->cga.lastline++; + if (x != xsize || (self->cga.lastline - self->cga.firstline) != ysize) + { + xsize = x; + ysize = self->cga.lastline - self->cga.firstline; + + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize + 16); + } + + video_blit_memtoscreen(0, self->cga.firstline - 4, 0, (self->cga.lastline - self->cga.firstline) + 8, xsize, (self->cga.lastline - self->cga.firstline) + 8); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (self->cga.cgamode & 1) + { + video_res_x /= 8; + video_res_y /= self->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(self->cga.cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= self->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(self->cga.cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + self->cga.firstline = 1000; + self->cga.lastline = 0; + self->cga.cgablink++; + self->cga.oddeven ^= 1; + } + } + else + { + self->cga.sc++; + self->cga.sc &= 31; + self->cga.ma = self->cga.maback; + } + if (self->cga.cgadispon) + self->cga.cgastat &= ~1; + if ((self->cga.sc == (self->cga.crtc[10] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[10] & 31) >> 1)))) + self->cga.con = 1; + if (self->cga.cgadispon && (self->cga.cgamode & 1)) + { + for (x = 0; x < (self->cga.crtc[1] << 1); x++) + self->cga.charbuffer[x] = self->cga.vram[(((self->cga.ma << 1) + x) & 0x3fff)]; + } + } + +} + +void *compaq_cga_init() +{ + int display_type; + int contrast; + int c; + compaq_cga_t *self = malloc(sizeof(compaq_cga_t)); + memset(self, 0, sizeof(compaq_cga_t)); + + self->cga.vram = malloc(0x4000); + + timer_add(&self->cga.timer, compaq_cga_poll, self, 1); + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, self); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, self); + + display_type = device_get_config_int("display_type"); + contrast = device_get_config_int("contrast"); + cgapal_rebuild(display_type, contrast); + + for (c = 0; c < 256; c++) + { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 0; + if (c & 8) mdaattr[c][0][1] = 0xf; + else mdaattr[c][0][1] = 0x7; + } + mdaattr[0x70][0][1] = 0; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 0xf; + mdaattr[0xF0][0][1] = 0; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 0xf; + mdaattr[0x78][0][1] = 0x7; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 0xf; + mdaattr[0xF8][0][1] = 0x7; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 0xf; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 0; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 0; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 0; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 0; + + return self; +} + +void compaq_cga_close(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + + free(self->cga.vram); + free(self); +} + +void compaq_cga_speed_changed(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + + if (self->cga.crtc[9] == 13) /* Character height */ + { + compaq_cga_recalctimings(self); + } + else + { + cga_recalctimings(&self->cga); + } +} + +extern device_config_t cga_config[]; + +device_t compaq_cga_device = +{ + "Compaq CGA", + 0, + compaq_cga_init, + compaq_cga_close, + NULL, + compaq_cga_speed_changed, + NULL, + NULL, + cga_config +}; diff --git a/src/vid_compaq_cga.h b/src/vid_compaq_cga.h new file mode 100644 index 0000000..adbab4c --- /dev/null +++ b/src/vid_compaq_cga.h @@ -0,0 +1 @@ +extern device_t compaq_cga_device; diff --git a/src/vid_ddc.c b/src/vid_ddc.c new file mode 100644 index 0000000..9ccc7ca --- /dev/null +++ b/src/vid_ddc.c @@ -0,0 +1,310 @@ +#include "ibm.h" +#include "vid_ddc.h" +#include "x86.h" + +static uint8_t edid_data[128] = +{ + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, /*Fixed header pattern*/ + 0x65, 0x40, /*Manufacturer "PCE" - apparently unassigned by UEFI*/ + 0x00, 0x00, /*Product code*/ + 0x12, 0x34, 0x56, 0x78, /*Serial number*/ + 0x01, 9, /*Manufacturer week and year*/ + 0x01, 0x03, /*EDID version (1.3)*/ + + 0x08, /*Analogue input, separate sync*/ + 34, 0, /*Landscape, 4:3*/ + 0, /*Gamma*/ + 0x08, /*RGB colour*/ + 0x81, 0xf1, 0xa3, 0x57, 0x53, 0x9f, 0x27, 0x0a, 0x50, /*Chromaticity*/ + + 0xff, 0xff, 0xff, /*Established timing bitmap*/ + 0x00, 0x00, /*Standard timing information*/ + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + 0x00, 0x00, + + /*Detailed mode descriptions*/ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, /*No extensions*/ + 0x00 +}; + +/*This should probably be split off into a separate I2C module*/ +enum +{ + TRANSMITTER_MONITOR = 1, + TRANSMITTER_HOST = -1 +}; + +enum +{ + I2C_IDLE = 0, + I2C_RECEIVE, + I2C_RECEIVE_WAIT, + I2C_TRANSMIT_START, + I2C_TRANSMIT, + I2C_ACKNOWLEDGE, + I2C_TRANSACKNOWLEDGE, + I2C_TRANSMIT_WAIT +}; + +enum +{ + PROM_IDLE = 0, + PROM_RECEIVEADDR, + PROM_RECEIVEDATA, + PROM_SENDDATA, + PROM_INVALID +}; + +static struct +{ + int clock, data; + int state; + int last_data; + int pos; + int transmit; + uint8_t byte; +} i2c; + +static struct +{ + int state; + int addr; + int rw; +} prom; + +static void prom_stop(void) +{ +// pclog("prom_stop()\n"); + prom.state = PROM_IDLE; + i2c.transmit = TRANSMITTER_HOST; +} + +static void prom_next_byte(void) +{ +// pclog("prom_next_byte(%d)\n", prom.addr); + i2c.byte = edid_data[(prom.addr++) & 0x7F]; +} + +static void prom_write(uint8_t byte) +{ +// pclog("prom_write: byte=%02x\n", byte); + switch (prom.state) + { + case PROM_IDLE: + if ((byte & 0xfe) != 0xa0) + { +// pclog("I2C address not PROM\n"); + prom.state = PROM_INVALID; + break; + } + prom.rw = byte & 1; + if (prom.rw) + { + prom.state = PROM_SENDDATA; + i2c.transmit = TRANSMITTER_MONITOR; + i2c.byte = edid_data[(prom.addr++) & 0x7F]; +// pclog("PROM - %02X from %02X\n",i2c.byte, prom.addr-1); +// pclog("Transmitter now PROM\n"); + } + else + { + prom.state = PROM_RECEIVEADDR; + i2c.transmit = TRANSMITTER_HOST; + } +// pclog("PROM R/W=%i\n",promrw); + return; + + case PROM_RECEIVEADDR: +// pclog("PROM addr=%02X\n",byte); + prom.addr = byte; + if (prom.rw) + prom.state = PROM_SENDDATA; + else + prom.state = PROM_RECEIVEDATA; + break; + + case PROM_RECEIVEDATA: +// pclog("PROM write %02X %02X\n",promaddr,byte); + break; + + case PROM_SENDDATA: + break; + } +} + +void ddc_i2c_change(int new_clock, int new_data) +{ +// pclog("I2C update clock %i->%i data %i->%i state %i\n",i2c.clock,new_clock,i2c.last_data,new_data,i2c.state); + switch (i2c.state) + { + case I2C_IDLE: + if (i2c.clock && new_clock) + { + if (i2c.last_data && !new_data) /*Start bit*/ + { +// pclog("Start bit received\n"); + i2c.state = I2C_RECEIVE; + i2c.pos = 0; + } + } + break; + + case I2C_RECEIVE_WAIT: + if (!i2c.clock && new_clock) + i2c.state = I2C_RECEIVE; + case I2C_RECEIVE: + if (!i2c.clock && new_clock) + { + i2c.byte <<= 1; + if (new_data) + i2c.byte |= 1; + else + i2c.byte &= 0xFE; + i2c.pos++; + if (i2c.pos == 8) + { + prom_write(i2c.byte); + i2c.state = I2C_ACKNOWLEDGE; + } + } + else if (i2c.clock && new_clock && new_data && !i2c.last_data) /*Stop bit*/ + { +// pclog("Stop bit received\n"); + i2c.state = I2C_IDLE; + prom_stop(); + } + else if (i2c.clock && new_clock && !new_data && i2c.last_data) /*Start bit*/ + { +// pclog("Start bit received\n"); + i2c.pos = 0; + prom.state = PROM_IDLE; + } + break; + + case I2C_ACKNOWLEDGE: + if (!i2c.clock && new_clock) + { +// pclog("Acknowledging transfer\n"); + new_data = 0; + i2c.pos = 0; + if (i2c.transmit == TRANSMITTER_HOST) + i2c.state = I2C_RECEIVE_WAIT; + else + i2c.state = I2C_TRANSMIT; + } + break; + + case I2C_TRANSACKNOWLEDGE: + if (!i2c.clock && new_clock) + { + if (new_data) /*It's not acknowledged - must be end of transfer*/ + { +// pclog("End of transfer\n"); + i2c.state = I2C_IDLE; + prom_stop(); + } + else /*Next byte to transfer*/ + { + i2c.state = I2C_TRANSMIT_START; + prom_next_byte(); + i2c.pos = 0; +// pclog("Next byte - %02X\n",i2c.byte); + } + } + break; + + case I2C_TRANSMIT_WAIT: + if (i2c.clock && new_clock) + { + if (i2c.last_data && !new_data) /*Start bit*/ + { + prom_next_byte(); + i2c.pos = 0; +// pclog("Next byte - %02X\n",i2c.byte); + } + if (!i2c.last_data && new_data) /*Stop bit*/ + { +// pclog("Stop bit received\n"); + i2c.state = I2C_IDLE; + prom_stop(); + } + } + break; + + case I2C_TRANSMIT_START: + if (!i2c.clock && new_clock) + i2c.state = I2C_TRANSMIT; + if (i2c.clock && new_clock && !i2c.last_data && new_data) /*Stop bit*/ + { +// pclog("Stop bit received\n"); + i2c.state = I2C_IDLE; + prom_stop(); + } + case I2C_TRANSMIT: + if (!i2c.clock && new_clock) + { + i2c.clock = new_clock; +// if (!i2c.pos) +// pclog("Transmit byte %02x\n", i2c.byte); + i2c.data = new_data = i2c.byte & 0x80; +// pclog("Transmit bit %i %i\n", i2c.byte, i2c.pos); + i2c.byte <<= 1; + i2c.pos++; + return; + } + if (i2c.clock && !new_clock && i2c.pos == 8) + { + i2c.state = I2C_TRANSACKNOWLEDGE; +// pclog("Acknowledge mode\n"); + } + break; + + } + if (!i2c.clock && new_clock) + i2c.data = new_data; + i2c.last_data = new_data; + i2c.clock = new_clock; +} + +int ddc_read_clock(void) +{ + return i2c.clock; +} +int ddc_read_data(void) +{ + if (i2c.state == I2C_TRANSMIT || i2c.state == I2C_ACKNOWLEDGE) + return i2c.data; + if (i2c.state == I2C_RECEIVE_WAIT) + return 0; /*ACK*/ + return 1; +} + +void ddc_init(void) +{ + int c; + uint8_t checksum = 0; + + for (c = 0; c < 127; c++) + checksum += edid_data[c]; + edid_data[127] = 256 - checksum; + + i2c.clock = 1; + i2c.data = 1; +} diff --git a/src/vid_ddc.h b/src/vid_ddc.h new file mode 100644 index 0000000..7b8f8bd --- /dev/null +++ b/src/vid_ddc.h @@ -0,0 +1,4 @@ +void ddc_init(void); +void ddc_i2c_change(int new_clock, int new_data); +int ddc_read_clock(void); +int ddc_read_data(void); diff --git a/src/vid_ega.c b/src/vid_ega.c index bb98784..1c134be 100644 --- a/src/vid_ega.c +++ b/src/vid_ega.c @@ -150,8 +150,8 @@ 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 != 0x3da && addr != 0x3ba) + pclog("ega_in %04X\n", addr); if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) addr ^= 0x60; @@ -241,29 +241,266 @@ void ega_recalctimings(ega_t *ega) _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)); + ega->dispontime = (uint64_t)_dispontime; + ega->dispofftime = (uint64_t)_dispofftime; + pclog("dispontime %i (%f) dispofftime %i (%f)\n", ega->dispontime, (float)ega->dispontime, + ega->dispofftime, (float)ega->dispofftime); // 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]); } +static void ega_draw_text(ega_t *ega) +{ + int x, xx; + + for (x = 0; x < ega->hdisp; x++) + { + int drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + uint8_t chr = ega->vram[(ega->ma << 1) & ega->vrammask]; + uint8_t attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + uint8_t dat; + uint32_t fg, bg; + uint32_t charaddr; + + 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])[((x << 4) + 32 + (xx << 1)) & 2047] = + ((uint32_t *)buffer32->line[ega->displine])[((x << 4) + 33 + (xx << 1)) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + (xx << 1)) & 2047] = + ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 33 + (xx << 1)) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 16) & 2047] = + ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 17) & 2047] = bg; + else + ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 16) & 2047] = + ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 17) & 2047] = (dat & 1) ? fg : bg; + } + } + else + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine])[((x << 3) + 32 + xx) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + xx) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + 8) & 2047] = bg; + else + ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + 8) & 2047] = (dat & 1) ? fg : bg; + } + } + ega->ma += 4; + ega->ma &= ega->vrammask; + } +} + +static void ega_draw_2bpp(ega_t *ega) +{ + int x; + int offset = ((8 - ega->scrollcache) << 1) + 16; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[2]; + uint32_t addr = ega->ma; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + if (ega->seqregs[1] & 4) + ega->ma += 2; + else + ega->ma += 4; + + ega->ma &= ega->vrammask; + + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 14 + offset]= ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[edat[1] & 3]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 9 + offset] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 7 + offset] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 5 + offset] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 3 + offset] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; + } +} + +static void ega_draw_4bpp_lowres(ega_t *ega) +{ + int x; + int offset = ((8 - ega->scrollcache) << 1) + 16; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[4]; + uint8_t dat; + uint32_t addr = ega->ma; + int oddeven = 0; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + if (ega->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + if (ega->seqregs[1] & 4) + { + edat[0] = ega->vram[addr | oddeven]; + edat[2] = ega->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + ega->ma += 2; + } + else + { + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + edat[2] = ega->vram[addr | 0x2]; + edat[3] = ega->vram[addr | 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])[(x << 4) + 14 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = 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])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 9 + offset] = 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])[(x << 4) + 6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 7 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 5 + offset] = 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])[(x << 4) + 2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 3 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } +} + +static void ega_draw_4bpp_highres(ega_t *ega) +{ + int x; + int offset = (8 - ega->scrollcache) + 24; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[4]; + uint8_t dat; + uint32_t addr = ega->ma; + int oddeven = 0; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + if (ega->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + if (ega->seqregs[1] & 4) + { + edat[0] = ega->vram[addr | oddeven]; + edat[2] = ega->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + ega->ma += 2; + } + else + { + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + edat[2] = ega->vram[addr | 0x2]; + edat[3] = ega->vram[addr | 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])[(x << 3) + 7 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 6 + offset] = 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])[(x << 3) + 5 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 4 + offset] = 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])[(x << 3) + 3 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 2 + offset] = 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])[(x << 3) + 1 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + offset] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } +} + 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; if (!ega->linepos) { - ega->vidtime += ega->dispofftime; + timer_advance_u64(&ega->timer, ega->dispofftime); ega->stat |= 1; ega->linepos = 1; @@ -300,76 +537,7 @@ void ega_poll(void *p) else if (!(ega->gdcreg[6] & 1)) { if (fullchange) - { - for (x = 0; x < ega->hdisp; x++) - { - drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); - chr = ega->vram[(ega->ma << 1) & ega->vrammask]; - attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; - - 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])[((x << 4) + 32 + (xx << 1)) & 2047] = - ((uint32_t *)buffer32->line[ega->displine])[((x << 4) + 33 + (xx << 1)) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + (xx << 1)) & 2047] = - ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 33 + (xx << 1)) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) - ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 16) & 2047] = - ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 17) & 2047] = bg; - else - ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 16) & 2047] = - ((uint32_t *)buffer32->line[ega->displine])[((x * 18) + 32 + 17) & 2047] = (dat & 1) ? fg : bg; - } - } - else - { - if (ega->seqregs[1] & 1) - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[ega->displine])[((x << 3) + 32 + xx) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; - } - else - { - for (xx = 0; xx < 8; xx++) - ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + xx) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; - if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) - ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + 8) & 2047] = bg; - else - ((uint32_t *)buffer32->line[ega->displine])[((x * 9) + 32 + 8) & 2047] = (dat & 1) ? fg : bg; - } - } - ega->ma += 4; - ega->ma &= ega->vrammask; - } - } + ega_draw_text(ega); } else { @@ -377,104 +545,12 @@ void ega_poll(void *p) { 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])[(x << 4) + 14 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = 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])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 9 + offset] = 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])[(x << 4) + 6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 7 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 5 + offset] = 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])[(x << 4) + 2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 3 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - } - } + ega_draw_4bpp_lowres(ega); 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])[(x << 3) + 7 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 6 + offset] = 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])[(x << 3) + 5 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 4 + offset] = 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])[(x << 3) + 3 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + 2 + offset] = 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])[(x << 3) + 1 + offset] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 3) + offset] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; - } - } + ega_draw_4bpp_highres(ega); 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])[(x << 4) + 14 + offset]= ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[edat[1] & 3]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 9 + offset] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 7 + offset] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 5 + offset] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 3 + offset] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; - ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; - } + ega_draw_2bpp(ega); break; } } @@ -491,7 +567,7 @@ void ega_poll(void *p) } else { - ega->vidtime += ega->dispontime; + timer_advance_u64(&ega->timer, ega->dispontime); // if (output) printf("Display on %f\n",vidtime); if (ega->dispon) ega->stat &= ~1; @@ -503,6 +579,8 @@ void ega_poll(void *p) if (ega->sc == (ega->crtc[9] & 31)) { ega->sc = 0; + if (ega->sc == (ega->crtc[11] & 31)) + ega->con = 0; ega->maback += (ega->rowoffset << 3); ega->maback &= ega->vrammask; @@ -540,7 +618,6 @@ void ega_poll(void *p) } if (ega->vc == ega->vsyncstart) { - int wx = 0, wy = 0; ega->dispon = 0; // printf("Vsync on at line %i %i\n",displine,vc); ega->stat |= 8; @@ -555,7 +632,7 @@ void ega_poll(void *p) ysize = ega->lastline - ega->firstline; if (xsize < 64) xsize = 656; if (ysize < 32) ysize = 200; - if (ega->vres) + if (ega->vres || ysize <= 200) updatewindowsize(xsize, ysize << 1); else updatewindowsize(xsize, ysize); @@ -563,10 +640,9 @@ void ega_poll(void *p) video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline, xsize, ega->lastline - ega->firstline); - frames++; - - ega->video_res_x = wx; - ega->video_res_y = wy + 1; + ega->frames++; + ega->video_res_x = xsize; + ega->video_res_y = ysize+1; if (!(ega->gdcreg[6] & 1)) /*Text mode*/ { ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9; @@ -602,7 +678,7 @@ void ega_poll(void *p) if (ega->vc == ega->vtotal) { ega->vc = 0; - ega->sc = 0; + ega->sc = ega->crtc[8] & 0x1f; ega->dispon = 1; ega->displine = 0; ega->scrollcache = ega->attrregs[0x13] & 7; @@ -620,8 +696,8 @@ void ega_write(uint32_t addr, uint8_t val, void *p) int writemask2 = ega->writemask; egawrites++; - cycles -= video_timing_b; - cycles_lost += video_timing_b; + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; if (addr >= 0xB0000) addr &= 0x7fff; else addr &= 0xffff; @@ -632,10 +708,16 @@ void ega_write(uint32_t addr, uint8_t val, void *p) if (addr & 1) writemask2 <<= 1; addr &= ~1; + if (addr & 0x4000) + addr |= 1; + addr &= ~0x4000; } addr <<= 2; + if (addr >= ega->vram_limit) + return; + if (!(ega->gdcreg[6] & 1)) fullchange = 2; @@ -753,8 +835,8 @@ uint8_t ega_read(uint32_t addr, void *p) int readplane = ega->readplane; egareads++; - cycles -= video_timing_b; - cycles_lost += video_timing_b; + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; // pclog("Readega %06X ",addr); if (addr >= 0xb0000) addr &= 0x7fff; else addr &= 0xffff; @@ -763,34 +845,39 @@ uint8_t ega_read(uint32_t addr, void *p) { readplane = (readplane & 2) | (addr & 1); addr &= ~1; + if (addr & 0x4000) + addr |= 1; + addr &= ~0x4000; } addr <<= 2; - + if (addr >= ega->vram_limit) + return 0xff; + 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->la; temp ^= (ega->colourcompare & 1) ? 0xff : 0; - temp2 = (ega->colournocare & 2) ? 0xff : 0; - temp2 &= ega->lb; + temp &= (ega->colournocare & 1) ? 0xff : 0; + temp2 = ega->lb; temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; - temp3 = (ega->colournocare & 4) ? 0xff : 0; - temp3 &= ega->lc; + temp2 &= (ega->colournocare & 2) ? 0xff : 0; + temp3 = ega->lc; temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; - temp4 = (ega->colournocare & 8) ? 0xff : 0; - temp4 &= ega->ld; + temp3 &= (ega->colournocare & 4) ? 0xff : 0; + temp4 = ega->ld; temp4 ^= (ega->colourcompare & 8) ? 0xff : 0; + temp4 &= (ega->colournocare & 8) ? 0xff : 0; return ~(temp | temp2 | temp3 | temp4); } return ega->vram[addr | readplane]; } -void ega_init(ega_t *ega) +void ega_init(ega_t *ega, int monitor_type, int is_mono) { int c, d, e; @@ -819,24 +906,94 @@ void ega_init(ega_t *ega) } } - for (c = 0; c < 256; c++) + if (is_mono) { - 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); + for (c = 0; c < 256; c++) + { + switch (monitor_type >> 4) + { + case DISPLAY_GREEN: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0x04, 0x8a, 0x20); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0x08, 0xc7, 0x2c); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0x34, 0xff, 0x5d); + break; + } + break; + case DISPLAY_AMBER: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0xb2, 0x4d, 0x00); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0xef, 0x79, 0x00); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0xff, 0xe3, 0x34); + break; + } + break; + case DISPLAY_WHITE: default: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0x7a, 0x81, 0x83); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0xaf, 0xb3, 0xb0); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0xff, 0xfd, 0xed); + break; + } + break; + } + } + } + else + { + 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; + + egaswitches = monitor_type & 0xf; + ega->vram_limit = 256 * 1024; + ega->vrammask = ega->vram_limit-1; + + timer_add(&ega->timer, ega_poll, ega, 1); } void *ega_standalone_init() { ega_t *ega = malloc(sizeof(ega_t)); memset(ega, 0, sizeof(ega_t)); + int monitor_type; - rom_init(&ega->bios_rom, "roms/ibm_6277356_ega_card_u44_27128.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&ega->bios_rom, "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) { @@ -851,17 +1008,21 @@ void *ega_standalone_init() } } - ega_init(ega); + monitor_type = device_get_config_int("monitor_type"); + ega_init(ega, monitor_type, (monitor_type & 0xf) == 10); - 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); + ega->vram_limit = device_get_config_int("memory") * 1024; + ega->vrammask = ega->vram_limit-1; + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); io_sethandler(0x03a0, 0x0040, 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"); + return rom_present("ibm_6277356_ega_card_u44_27128.bin"); } void ega_close(void *p) @@ -879,6 +1040,90 @@ void ega_speed_changed(void *p) ega_recalctimings(ega); } +void ega_add_status_info(char *s, int max_len, void *p) +{ + ega_t *ega = (ega_t *)p; + char temps[128]; + + if (!ega->video_bpp) strcpy(temps, "EGA in text mode\n"); + else sprintf(temps, "EGA colour depth : %i bpp\n", ega->video_bpp); + strncat(s, temps, max_len); + + sprintf(temps, "EGA resolution : %i x %i\n", ega->video_res_x, ega->video_res_y); + strncat(s, temps, max_len); + + sprintf(temps, "EGA refresh rate : %i Hz\n\n", ega->frames); + ega->frames = 0; + strncat(s, temps, max_len); +} + +static device_config_t ega_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "64 kB", + .value = 64 + }, + { + .description = "128 kB", + .value = 128 + }, + { + .description = "256 kB", + .value = 256 + }, + { + .description = "" + } + }, + .default_int = 256 + }, + { + .name = "monitor_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "EGA Colour, 40x25", + .value = 6 + }, + { + .description = "EGA Colour, 80x25", + .value = 7 + }, + { + .description = "EGA Colour, ECD", + .value = 9 + }, + { + .description = "EGA Monochrome (white)", + .value = 10 | (DISPLAY_WHITE << 4) + }, + { + .description = "EGA Monochrome (green)", + .value = 10 | (DISPLAY_GREEN << 4) + }, + { + .description = "EGA Monochrome (amber)", + .value = 10 | (DISPLAY_AMBER << 4) + }, + { + .description = "" + } + }, + .default_int = 9 + }, + { + .type = -1 + } +}; + device_t ega_device = { "EGA", @@ -888,5 +1133,6 @@ device_t ega_device = ega_standalone_available, ega_speed_changed, NULL, - NULL + ega_add_status_info, + ega_config }; diff --git a/src/vid_ega.h b/src/vid_ega.h index 1c43184..c955509 100644 --- a/src/vid_ega.h +++ b/src/vid_ega.h @@ -39,8 +39,8 @@ typedef struct ega_t int vres; - int dispontime, dispofftime; - int vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; uint8_t scrblank; @@ -60,8 +60,10 @@ typedef struct ega_t uint8_t *vram; int vrammask; + uint32_t vram_limit; int video_res_x, video_res_y, video_bpp; + int frames; } ega_t; void *ega_standalone_init(); @@ -71,6 +73,6 @@ 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); -void ega_init(ega_t *ega); +void ega_init(ega_t *ega, int monitor_type, int is_mono); extern device_t ega_device; diff --git a/src/vid_et4000.c b/src/vid_et4000.c index 483ce94..7f366b3 100644 --- a/src/vid_et4000.c +++ b/src/vid_et4000.c @@ -7,6 +7,7 @@ #include "rom.h" #include "video.h" #include "vid_svga.h" +#include "vid_svga_render.h" #include "vid_unk_ramdac.h" #include "vid_et4000.h" @@ -19,6 +20,16 @@ typedef struct et4000_t rom_t bios_rom; uint8_t banking; + uint8_t port_22cb_val; + uint8_t port_32cb_val; + int get_korean_font_enabled; + int get_korean_font_index; + uint16_t get_korean_font_base; + + uint8_t kasan_cfg_index; + uint8_t kasan_cfg_regs[16]; + uint16_t kasan_access_addr; + uint8_t kasan_font_data[4]; } et4000_t; static uint8_t crtc_mask[0x40] = @@ -33,6 +44,9 @@ static uint8_t crtc_mask[0x40] = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +void et4000_kasan_out(uint16_t addr, uint8_t val, void *p); +uint8_t et4000_kasan_in(uint16_t addr, void *p); + void et4000_out(uint16_t addr, uint8_t val, void *p) { et4000_t *et4000 = (et4000_t *)p; @@ -57,6 +71,21 @@ void et4000_out(uint16_t addr, uint8_t val, void *p) et4000->banking = val; // pclog("Banking write %08X %08X %02X\n", svga->write_bank, svga->read_bank, val); return; + + case 0x3cf: + if ((svga->gdcaddr & 15) == 6) + { + old = svga->gdcreg[6]; + svga_out(addr, val, svga); + if ((old & 0xc) != 0 && (val & 0xc) == 0) + { + /*override mask - ET4000 supports linear 128k at A0000*/ + svga->banked_mask = 0x1ffff; + } + return; + } + break; + case 0x3D4: svga->crtcreg = val & 0x3f; return; @@ -81,6 +110,172 @@ void et4000_out(uint16_t addr, uint8_t val, void *p) svga_out(addr, val, svga); } +void et4000k_out(uint16_t addr, uint8_t val, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + +// pclog("ET4000k out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x22CB: + et4000->port_22cb_val = (et4000->port_22cb_val & 0xF0) | (val & 0x0F); + et4000->get_korean_font_enabled = val & 7; + if (et4000->get_korean_font_enabled == 3) + et4000->get_korean_font_index = 0; + break; + case 0x22CF: + switch (et4000->get_korean_font_enabled) + { + case 1: + et4000->get_korean_font_base = ((val & 0x7F) << 7) | (et4000->get_korean_font_base & 0x7F); + break; + case 2: + et4000->get_korean_font_base = (et4000->get_korean_font_base & 0x3F80) | (val & 0x7F) | (((val ^ 0x80) & 0x80) << 8); + break; + case 3: + if ((et4000->port_32cb_val & 0x30) == 0x20 && (et4000->get_korean_font_base & 0x7F) > 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F) + { + switch (et4000->get_korean_font_base & 0x3F80) + { + case 0x2480: + if (et4000->get_korean_font_index < 16) + fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index] = val; + else if (et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40) + fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index - 8] = val; + break; + case 0x3F00: + if (et4000->get_korean_font_index < 16) + fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index] = val; + else if (et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40) + fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index - 8] = val; + break; + } + et4000->get_korean_font_index++; + } + break; + } + break; + case 0x32CB: + et4000->port_32cb_val = val; + svga_recalctimings(&et4000->svga); + break; + default: + et4000_out(addr, val, p); + break; + } +} + +void et4000_kasan_out(uint16_t addr, uint8_t val, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + +// pclog("ET4000k out %04X %02X\n", addr, val); + + + if(addr == 0x258) + { + //pclog("Write port %04X to %02X at %04X:%04X\n", addr, val, CS, cpu_state.oldpc); + et4000->kasan_cfg_index = val; + } + else if(addr == 0x259) + { + //pclog("Write port %04X to %02X at %04X:%04X\n", addr, val, CS, cpu_state.oldpc); + if(et4000->kasan_cfg_index >= 0xF0) + { + switch(et4000->kasan_cfg_index - 0xF0) + { + case 0: + if(et4000->kasan_cfg_regs[4] & 8) + val = (val & 0xFC) | (et4000->kasan_cfg_regs[0] & 3); + et4000->kasan_cfg_regs[0] = val; + svga_recalctimings(&et4000->svga); + break; + case 1: + case 2: + et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; + io_removehandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); + et4000->kasan_access_addr = (et4000->kasan_cfg_regs[2] << 8) | et4000->kasan_cfg_regs[1]; + io_sethandler(et4000->kasan_access_addr, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); + //pclog("Set font access address to %04X\n", et4000->kasan_access_addr); + break; + case 4: + if(et4000->kasan_cfg_regs[0] & 0x20) + val |= 0x80; + et4000->svga.ksc5601_swap_mode = (val & 4) >> 2; + et4000->kasan_cfg_regs[4] = val; + svga_recalctimings(&et4000->svga); + break; + case 5: + et4000->kasan_cfg_regs[5] = val; + et4000->svga.ksc5601_english_font_type = 0x100 | val; + break; + case 6: + case 7: + et4000->svga.ksc5601_udc_area_msb[et4000->kasan_cfg_index - 0xF6] = val; + default: + et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0] = val; + svga_recalctimings(&et4000->svga); + break; + } + } + } + else if(addr >= et4000->kasan_access_addr && addr < et4000->kasan_access_addr + 8) + { + switch (addr - ((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1]))) + { + case 0: + if(et4000->kasan_cfg_regs[0] & 2) + { + et4000->get_korean_font_index = ((val & 1) << 4) | ((val & 0x1E) >> 1); + et4000->get_korean_font_base = (et4000->get_korean_font_base & ~7) | (val >> 5); + } + break; + case 1: + if(et4000->kasan_cfg_regs[0] & 2) + { + et4000->get_korean_font_base = (et4000->get_korean_font_base & ~0x7F8) | (val << 3); + } + break; + case 2: + if(et4000->kasan_cfg_regs[0] & 2) + { + et4000->get_korean_font_base = (et4000->get_korean_font_base & ~0x7F800) | ((val & 7) << 11); + } + break; + case 3: + case 4: + case 5: + if(et4000->kasan_cfg_regs[0] & 1) + { + et4000->kasan_font_data[addr - (((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1])) + 3)] = val; + } + break; + case 6: + if((et4000->kasan_cfg_regs[0] & 1) && (et4000->kasan_font_data[3] & !val & 0x80) && (et4000->get_korean_font_base & 0x7F) >= 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F) + { + if(((et4000->get_korean_font_base >> 7) & 0x7F) == (et4000->svga.ksc5601_udc_area_msb[0] & 0x7F) && (et4000->svga.ksc5601_udc_area_msb[0] & 0x80)) + { + fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index] = et4000->kasan_font_data[2]; + } + else if(((et4000->get_korean_font_base >> 7) & 0x7F) == (et4000->svga.ksc5601_udc_area_msb[1] & 0x7F) && (et4000->svga.ksc5601_udc_area_msb[1] & 0x80)) + { + fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index] = et4000->kasan_font_data[2]; + } + } + et4000->kasan_font_data[3] = val; + break; + default: + break; + } + //pclog("Write port %04X at %04X:%04X\n", addr, CS, cpu_state.oldpc); + } + else + { + et4000_out(addr, val, p); + } +} + uint8_t et4000_in(uint16_t addr, void *p) { et4000_t *et4000 = (et4000_t *)p; @@ -110,6 +305,113 @@ uint8_t et4000_in(uint16_t addr, void *p) return svga_in(addr, svga); } +uint8_t et4000k_in(uint16_t addr, void *p) +{ + uint8_t val = 0xFF; + et4000_t *et4000 = (et4000_t *)p; + +// if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr); + + switch (addr) + { + case 0x22CB: + return et4000->port_22cb_val; + case 0x22CF: + val = 0; + switch (et4000->get_korean_font_enabled) + { + case 3: + if ((et4000->port_32cb_val & 0x30) == 0x30) + { + val = fontdatksc5601[et4000->get_korean_font_base][et4000->get_korean_font_index++]; + et4000->get_korean_font_index &= 0x1F; + } + else if ((et4000->port_32cb_val & 0x30) == 0x20 && (et4000->get_korean_font_base & 0x7F) > 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F) + { + switch (et4000->get_korean_font_base & 0x3F80) + { + case 0x2480: + if (et4000->get_korean_font_index < 16) + val = fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index]; + else if (et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40) + val = fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index - 8]; + break; + case 0x3F00: + if (et4000->get_korean_font_index < 16) + val = fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index]; + else if (et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40) + val = fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index - 8]; + break; + } + et4000->get_korean_font_index++; + et4000->get_korean_font_index %= 72; + } + break; + case 4: + val = 0x0F; + break; + } + return val; + case 0x32CB: + return et4000->port_32cb_val; + } + + return et4000_in(addr, p); +} + +uint8_t et4000_kasan_in(uint16_t addr, void *p) +{ + uint8_t val = 0xFF; + et4000_t *et4000 = (et4000_t *)p; + + if(addr == 0x258) + { + //pclog("Read port %04X at %04X:%04X\n", addr, CS, cpu_state.oldpc); + val = et4000->kasan_cfg_index; + } + else if(addr == 0x259) + { + //pclog("Read port %04X at %04X:%04X\n", addr, CS, cpu_state.oldpc); + if (et4000->kasan_cfg_index >= 0xF0) + { + val = et4000->kasan_cfg_regs[et4000->kasan_cfg_index - 0xF0]; + if(et4000->kasan_cfg_index == 0xF4 && et4000->kasan_cfg_regs[0] & 0x20) + val |= 0x80; + } + } + else if(addr >= et4000->kasan_access_addr && addr < et4000->kasan_access_addr + 8) + { + switch (addr - ((et4000->kasan_cfg_regs[2] << 8) | (et4000->kasan_cfg_regs[1]))) + { + case 2: + val = 0; + break; + case 5: + if(((et4000->get_korean_font_base >> 7) & 0x7F) == (et4000->svga.ksc5601_udc_area_msb[0] & 0x7F) && (et4000->svga.ksc5601_udc_area_msb[0] & 0x80)) + { + val = fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index]; + } + else if(((et4000->get_korean_font_base >> 7) & 0x7F) == (et4000->svga.ksc5601_udc_area_msb[1] & 0x7F) && (et4000->svga.ksc5601_udc_area_msb[1] & 0x80)) + { + val = fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20][et4000->get_korean_font_index]; + } + else + { + val = fontdatksc5601[et4000->get_korean_font_base][et4000->get_korean_font_index]; + } + break; + default: + break; + } + //pclog(stderr, "Read port %04X at %04X:%04X\n", addr, CS, cpu_state.oldpc); + } + else + { + val = et4000_in(addr, p); + } + return val; +} + void et4000_recalctimings(svga_t *svga) { svga->ma_latch |= (svga->crtc[0x33]&3)<<16; @@ -127,9 +429,9 @@ void et4000_recalctimings(svga_t *svga) 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; + case 3: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 5: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + default: svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; } switch (svga->bpp) @@ -143,12 +445,48 @@ void et4000_recalctimings(svga_t *svga) } } +void et4000k_recalctimings(svga_t *svga) +{ + et4000_t *et4000 = (et4000_t *)svga->p; + + et4000_recalctimings(svga); + + if (svga->render == svga_render_text_80 && ((svga->crtc[0x37] & 0x0A) == 0x0A)) + { + if(et4000->port_32cb_val & 0x80) + { + svga->ma_latch -= 2; + svga->ca_adj = -2; + } + if((et4000->port_32cb_val & 0xB4) == ((svga->crtc[0x37] & 3) == 2 ? 0xB4 : 0xB0)) + { + svga->render = svga_render_text_80_ksc5601; + } + } +} + +void et4000_kasan_recalctimings(svga_t *svga) +{ + et4000_t *et4000 = (et4000_t *)svga->p; + + et4000_recalctimings(svga); + + if (svga->render == svga_render_text_80 && (et4000->kasan_cfg_regs[0] & 8)) + { + svga->ma_latch -= 3; + svga->ca_adj = (et4000->kasan_cfg_regs[0] >> 6) - 3; + svga->ksc5601_sbyte_mask = (et4000->kasan_cfg_regs[0] & 4) << 5; + if((et4000->kasan_cfg_regs[0] & 0x23) == 0x20 && (et4000->kasan_cfg_regs[4] & 0x80) && ((svga->crtc[0x37] & 0x0B) == 0x0A)) + svga->render = svga_render_text_80_ksc5601; + } +} + 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); + rom_init(&et4000->bios_rom, "et4000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); @@ -157,13 +495,104 @@ void *et4000_init() et4000_in, et4000_out, NULL, NULL); + + et4000->svga.packed_chain4 = 1; return et4000; } +void *et4000k_init() +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + rom_init(&et4000->bios_rom, "tgkorvga.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont("tg_ksc5601.rom", 6); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + io_sethandler(0x22cb, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000); + io_sethandler(0x22cf, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000); + io_sethandler(0x32cb, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000); + et4000->port_22cb_val = 0x60; + et4000->port_32cb_val = 0; + + svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ + et4000k_recalctimings, + et4000k_in, et4000k_out, + NULL, + NULL); + + et4000->svga.ksc5601_sbyte_mask = 0x80; + et4000->svga.ksc5601_udc_area_msb[0] = 0xC9; + et4000->svga.ksc5601_udc_area_msb[1] = 0xFE; + et4000->svga.ksc5601_swap_mode = 0; + et4000->svga.ksc5601_english_font_type = 0; + + et4000->svga.packed_chain4 = 1; + + return et4000; +} + +void *et4000_kasan_init() +{ + int i; + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + rom_init(&et4000->bios_rom, "et4000_kasan16.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont("kasan_ksc5601.rom", 6); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + io_sethandler(0x0258, 0x0002, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); + + svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ + et4000_kasan_recalctimings, + et4000_in, et4000_out, + NULL, + NULL); + + et4000->svga.ksc5601_sbyte_mask = 0; + et4000->kasan_cfg_index = 0; + for(i=0; i<16; i++) + et4000->kasan_cfg_regs[i] = 0; + for(i=0; i<4; i++) + et4000->kasan_font_data[i] = 0; + et4000->kasan_cfg_regs[1] = 0x50; + et4000->kasan_cfg_regs[2] = 2; + et4000->kasan_cfg_regs[3] = 6; + et4000->kasan_cfg_regs[4] = 0x78; + et4000->kasan_cfg_regs[5] = 0xFF; + et4000->kasan_cfg_regs[6] = 0xC9; + et4000->kasan_cfg_regs[7] = 0xFE; + et4000->kasan_access_addr = 0x250; + io_sethandler(0x250, 0x0008, et4000_kasan_in, NULL, NULL, et4000_kasan_out, NULL, NULL, et4000); + + et4000->svga.ksc5601_sbyte_mask = 0; + et4000->svga.ksc5601_udc_area_msb[0] = 0xC9; + et4000->svga.ksc5601_udc_area_msb[1] = 0xFE; + et4000->svga.ksc5601_swap_mode = 0; + et4000->svga.ksc5601_english_font_type = 0x1FF; + + et4000->svga.packed_chain4 = 1; + + return et4000; +} + static int et4000_available() { - return rom_present("roms/et4000.bin"); + return rom_present("et4000.bin"); +} + +static int et4000k_available() +{ + return rom_present("tgkorvga.bin") && rom_present("tg_ksc5601.rom");; +} + +static int et4000_kasan_available() +{ + return rom_present("et4000_kasan16.bin") && rom_present("kasan_ksc5601.rom");; } void et4000_close(void *p) @@ -207,3 +636,27 @@ device_t et4000_device = et4000_force_redraw, et4000_add_status_info }; + +device_t et4000k_device = +{ + "Trigem Korean VGA(Tseng Labs ET4000AX)", + 0, + et4000k_init, + et4000_close, + et4000k_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_add_status_info +}; + +device_t et4000_kasan_device = +{ + "Kasan Hangulmadang-16(Tseng Labs ET4000AX)", + 0, + et4000_kasan_init, + et4000_close, + et4000_kasan_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_add_status_info +}; diff --git a/src/vid_et4000.h b/src/vid_et4000.h index cc7e161..9d18590 100644 --- a/src/vid_et4000.h +++ b/src/vid_et4000.h @@ -1 +1,3 @@ extern device_t et4000_device; +extern device_t et4000k_device; +extern device_t et4000_kasan_device; diff --git a/src/vid_et4000w32.c b/src/vid_et4000w32.c index f0b936a..b84cdbd 100644 --- a/src/vid_et4000w32.c +++ b/src/vid_et4000w32.c @@ -293,7 +293,7 @@ void et4000w32p_recalctimings(svga_t *svga) switch ((svga->miscout >> 2) & 3) { case 0: case 1: break; - case 2: case 3: svga->clock = cpuclock / icd2061_getfreq(&et4000->icd2061, 2); break; + case 2: case 3: svga->clock = (cpuclock * (double)(1ull << 32)) / icd2061_getfreq(&et4000->icd2061, 2); break; } switch (svga->bpp) @@ -337,7 +337,7 @@ void et4000w32p_recalcmapping(et4000w32p_t *et4000) 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; + svga->banked_mask = 0x1ffff; break; case 0x1: /*64k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); @@ -554,7 +554,7 @@ void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p) } else { - if ((addr&0x1fff) + et4000->mmu.base[bank] < svga->vram_limit) + if ((addr&0x1fff) + et4000->mmu.base[bank] < svga->vram_max) { svga->vram[(addr & 0x1fff) + et4000->mmu.base[bank]] = val; svga->changedvram[((addr & 0x1fff) + et4000->mmu.base[bank]) >> 12] = changeframecount; @@ -614,7 +614,7 @@ uint8_t et4000w32p_mmu_read(uint32_t addr, void *p) /*???*/ return temp; } - if ((addr&0x1fff) + et4000->mmu.base[bank] >= svga->vram_limit) + if ((addr&0x1fff) + et4000->mmu.base[bank] >= svga->vram_max) return 0xff; return svga->vram[(addr&0x1fff) + et4000->mmu.base[bank]]; @@ -1085,7 +1085,6 @@ static void et4000w32p_io_set(et4000w32p_t *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); @@ -1110,8 +1109,8 @@ uint8_t et4000w32p_pci_read(int func, int addr, void *p) 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 0x12: return 0x00; + case 0x13: return et4000->pci_regs[0x13]; case 0x30: return et4000->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ case 0x31: return 0x00; @@ -1137,7 +1136,8 @@ void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x13: - et4000->linearbase = val << 24; + et4000->linearbase = val << 24; + et4000->pci_regs[0x13] = val; et4000w32p_recalcmapping(et4000); break; @@ -1176,7 +1176,7 @@ void *et4000w32p_init() et4000w32p_hwcursor_draw, NULL); - rom_init(&et4000->bios_rom, "roms/et4000w32.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&et4000->bios_rom, "et4000w32.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); /*Some BIOSes (eg Diamond Stealth 32 VLB) have a PCI data structure, but with the wrong PCI device ID. The BIOSes on the Intel boards detect this @@ -1207,12 +1207,14 @@ void *et4000w32p_init() et4000->fifo_not_full_event = thread_create_event(); et4000->fifo_thread = thread_create(fifo_thread, et4000); + et4000->svga.packed_chain4 = 1; + return et4000; } int et4000w32p_available() { - return rom_present("roms/et4000w32.bin"); + return rom_present("et4000w32.bin"); } void et4000w32p_close(void *p) diff --git a/src/vid_genius.c b/src/vid_genius.c index c6d6202..f8c3688 100644 --- a/src/vid_genius.c +++ b/src/vid_genius.c @@ -13,7 +13,6 @@ #define GENIUS_YSIZE 1008 void updatewindowsize(int x, int y); -void loadfont(char *s, int format); extern uint8_t fontdat8x12[256][16]; @@ -98,8 +97,8 @@ typedef struct genius_t int enabled; /* Display enabled, 0 or 1 */ int detach; /* Detach cursor, 0 or 1 */ - int dispontime, dispofftime; - int vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int linepos, displine; int vc; @@ -109,6 +108,8 @@ typedef struct genius_t uint8_t *vram; } genius_t; +static uint32_t genius_pal[4]; + /* Mapping of attributes to colours, in MDA emulation mode */ static int mdacols[256][2][2]; @@ -244,8 +245,8 @@ void genius_recalctimings(genius_t *genius) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - genius->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - genius->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + genius->dispontime = (uint64_t)_dispontime; + genius->dispofftime = (uint64_t)_dispofftime; } @@ -265,7 +266,7 @@ void genius_textline(genius_t *genius, uint8_t background) uint16_t ma = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; uint16_t ca = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; unsigned char *framebuf = genius->vram + 0x10000; - uint8_t col; + uint32_t col; /* Character height is 12-15 */ charh = 15 - (genius->genius_charh & 3); @@ -317,13 +318,13 @@ void genius_textline(genius_t *genius, uint8_t background) if (genius->genius_control & 0x20) { - col ^= 15; + col ^= 0xffffff; } for (c = 0; c < cw; c++) { if (col != background) - buffer->line[genius->displine][(x * cw) + c] = col; + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; } } else /* Draw 8 pixels of character */ @@ -337,33 +338,35 @@ void genius_textline(genius_t *genius, uint8_t background) if (genius->genius_control & 0x20) { - col ^= 15; + col ^= 0xffffff; } if (col != background) { - buffer->line[genius->displine][(x * cw) + c] = col; + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; } } /* The ninth pixel column... */ if ((chr & ~0x1f) == 0xc0) { /* Echo column 8 for the graphics chars */ - col = buffer->line[genius->displine][(x * cw) + 7]; - if (col != background) buffer->line[genius->displine][(x * cw) + 8] = col; + col = ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 7]; + if (col != background) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; } else /* Otherwise fill with background */ { col = mdacols[attr][blink][0]; if (genius->genius_control & 0x20) { - col ^= 15; + col ^= 0xffffff; } - if (col != background) buffer->line[genius->displine][(x * cw) + 8] = col; + if (col != background) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; } if (drawcursor) { for (c = 0; c < cw; c++) - buffer->line[genius->displine][(x * cw) + c] ^= mdacols[attr][0][1]; + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] ^= mdacols[attr][0][1]; } ++ma; } @@ -378,10 +381,10 @@ void genius_cgaline(genius_t *genius) { int x, c; uint32_t dat; - uint8_t ink; + uint32_t ink; uint32_t addr; - ink = (genius->genius_control & 0x20) ? 16 : 16+15; + ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; /* We draw the CGA at row 600 */ if (genius->displine < 600) { @@ -402,7 +405,7 @@ void genius_cgaline(genius_t *genius) { if (dat & 0x80) { - buffer->line[genius->displine][x*8 + c] = ink; + ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; } dat = dat << 1; } @@ -417,10 +420,10 @@ void genius_hiresline(genius_t *genius) { int x, c; uint32_t dat; - uint8_t ink; + uint32_t ink; uint32_t addr; - ink = (genius->genius_control & 0x20) ? 16 : 16+15; + ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; /* The first 512 lines live at A0000 */ if (genius->displine < 512) { @@ -440,7 +443,7 @@ void genius_hiresline(genius_t *genius) { if (dat & 0x80) { - buffer->line[genius->displine][x*8 + c] = ink; + ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; } dat = dat << 1; } @@ -454,11 +457,11 @@ void genius_poll(void *p) { genius_t *genius = (genius_t *)p; int x; - uint8_t background; + uint32_t background; if (!genius->linepos) { - genius->vidtime += genius->dispofftime; + timer_advance_u64(&genius->timer, genius->dispofftime); genius->cga_stat |= 1; genius->mda_stat |= 1; genius->linepos = 1; @@ -466,11 +469,11 @@ void genius_poll(void *p) { if (genius->genius_control & 0x20) { - background = 16 + 15; + background = genius_pal[3]; } else { - background = 16; + background = genius_pal[0]; } if (genius->displine == 0) { @@ -479,7 +482,7 @@ void genius_poll(void *p) /* Start off with a blank line */ for (x = 0; x < GENIUS_XSIZE; x++) { - buffer->line[genius->displine][x] = background; + ((uint32_t *)buffer32->line[genius->displine])[x] = background; } /* If graphics display enabled, draw graphics on top * of the blanked line */ @@ -522,7 +525,7 @@ void genius_poll(void *p) genius->cga_stat &= ~1; genius->mda_stat &= ~1; } - genius->vidtime += genius->dispontime; + timer_advance_u64(&genius->timer, genius->dispontime); genius->linepos = 0; if (genius->displine == 1008) @@ -536,7 +539,7 @@ void genius_poll(void *p) if (ysize < 32) ysize = 200; updatewindowsize(xsize, ysize); } - video_blit_memtoscreen_8(0, 0, xsize, ysize); + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); frames++; /* Fixed 728x1008 resolution */ @@ -557,7 +560,7 @@ void *genius_init() /* 160k video RAM */ genius->vram = malloc(0x28000); - timer_add(genius_poll, &genius->vidtime, TIMER_ALWAYS_ENABLED, genius); + timer_add(&genius->timer, genius_poll, genius, 1); /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in * high-resolution modes) */ @@ -566,27 +569,32 @@ void *genius_init() io_sethandler(0x03b0, 0x000C, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); io_sethandler(0x03d0, 0x0010, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + genius_pal[0] = makecol(0x00, 0x00, 0x00); + genius_pal[1] = makecol(0x55, 0x55, 0x55); + genius_pal[2] = makecol(0xaa, 0xaa, 0xaa); + genius_pal[3] = makecol(0xff, 0xff, 0xff); + /* MDA attributes */ /* I don't know if the Genius's MDA emulation actually does * emulate bright / non-bright. For the time being pretend it does. */ 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[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = genius_pal[0]; + if (c & 8) mdacols[c][0][1] = genius_pal[3]; + else mdacols[c][0][1] = genius_pal[2]; } - 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; + mdacols[0x70][0][1] = genius_pal[0]; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = genius_pal[3]; + mdacols[0xF0][0][1] = genius_pal[0]; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = genius_pal[3]; + mdacols[0x78][0][1] = genius_pal[2]; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = genius_pal[3]; + mdacols[0xF8][0][1] = genius_pal[2]; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = genius_pal[3]; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = genius_pal[0]; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = genius_pal[0]; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = genius_pal[0]; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = genius_pal[0]; /* Start off in 80x25 text mode */ genius->cga_stat = 0xF4; @@ -606,7 +614,7 @@ void genius_close(void *p) static int genius_available() { - return rom_present("roms/8x12.bin"); + return rom_present("8x12.bin"); } void genius_speed_changed(void *p) diff --git a/src/vid_hercules.c b/src/vid_hercules.c index d010baa..0363cce 100644 --- a/src/vid_hercules.c +++ b/src/vid_hercules.c @@ -17,8 +17,8 @@ typedef struct hercules_t uint8_t ctrl, ctrl2, stat; - int dispontime, dispofftime; - int vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; @@ -32,7 +32,7 @@ typedef struct hercules_t uint8_t *vram; } hercules_t; -static int mdacols[256][2][2]; +static uint32_t mdacols[256][2][2]; void hercules_recalctimings(hercules_t *hercules); void hercules_write(uint32_t addr, uint8_t val, void *p); @@ -110,8 +110,8 @@ void hercules_recalctimings(hercules_t *hercules) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - hercules->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - hercules->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + hercules->dispontime = (uint64_t)_dispontime; + hercules->dispofftime = (uint64_t)_dispofftime; } void hercules_poll(void *p) @@ -128,7 +128,7 @@ void hercules_poll(void *p) if (!hercules->linepos) { //pclog("Poll %i %i\n",vc,sc); - hercules->vidtime += hercules->dispofftime; + timer_advance_u64(&hercules->timer, hercules->dispofftime); hercules->stat |= 1; hercules->linepos = 1; oldsc = hercules->sc; @@ -153,7 +153,7 @@ void hercules_poll(void *p) 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; + ((uint32_t *)buffer32->line[hercules->displine])[(x << 4) + c] = (dat & (32768 >> c)) ? cgapal[0x7] : 0; } } else @@ -167,20 +167,22 @@ void hercules_poll(void *p) if (hercules->sc == 12 && ((attr & 7) == 1)) { for (c = 0; c < 9; c++) - buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][1]; + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->line[hercules->displine])[(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][hercules->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) + ((uint32_t *)buffer32->line[hercules->displine])[(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][hercules->sc] & 1]; + else + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->line[hercules->displine])[(x * 9) + c] ^= mdacols[attr][0][1]; } } } @@ -197,7 +199,7 @@ void hercules_poll(void *p) } else { - hercules->vidtime += hercules->dispontime; + timer_advance_u64(&hercules->timer, hercules->dispontime); if (hercules->dispon) hercules->stat &= ~1; hercules->linepos = 0; @@ -268,7 +270,7 @@ void hercules_poll(void *p) updatewindowsize(xsize, ysize); } - video_blit_memtoscreen_8(0, hercules->firstline, xsize, ysize); + video_blit_memtoscreen(0, hercules->firstline, 0, ysize, xsize, ysize); frames++; if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) @@ -305,34 +307,38 @@ void hercules_poll(void *p) void *hercules_init() { + int display_type; 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); + timer_add(&hercules->timer, hercules_poll, hercules, 1); + mem_mapping_add(&hercules->mapping, 0xb0000, 0x08000, hercules_read, NULL, NULL, hercules_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, hercules); io_sethandler(0x03b0, 0x0010, hercules_in, NULL, NULL, hercules_out, NULL, NULL, hercules); + display_type = device_get_config_int("display_type"); + cgapal_rebuild(display_type, 0); + 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[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = cgapal[0]; + if (c & 8) mdacols[c][0][1] = cgapal[0xf]; + else mdacols[c][0][1] = cgapal[0x7]; } - 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; + mdacols[0x70][0][1] = cgapal[0]; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = cgapal[0xf]; + mdacols[0xF0][0][1] = cgapal[0]; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = cgapal[0xf]; + mdacols[0x78][0][1] = cgapal[0x7]; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = cgapal[0xf]; + mdacols[0xF8][0][1] = cgapal[0x7]; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = cgapal[0xf]; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = cgapal[0]; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = cgapal[0]; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = cgapal[0]; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = cgapal[0]; return hercules; } @@ -352,6 +358,37 @@ void hercules_speed_changed(void *p) hercules_recalctimings(hercules); } +static device_config_t hercules_config[] = +{ + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Green", + .value = DISPLAY_GREEN + }, + { + .description = "Amber", + .value = DISPLAY_AMBER + }, + { + .description = "White", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + }, + .default_int = DISPLAY_WHITE + }, + { + .type = -1 + } +}; + device_t hercules_device = { "Hercules", @@ -361,5 +398,6 @@ device_t hercules_device = NULL, hercules_speed_changed, NULL, - NULL + NULL, + hercules_config }; diff --git a/src/vid_ht216.c b/src/vid_ht216.c new file mode 100644 index 0000000..aa717e4 --- /dev/null +++ b/src/vid_ht216.c @@ -0,0 +1,1141 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_ht216.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_unk_ramdac.h" + +typedef struct ht216_t +{ + svga_t svga; + + mem_mapping_t linear_mapping; + + rom_t bios_rom; + + uint32_t vram_mask; + + int ext_reg_enable; + int clk_sel; + + uint8_t read_bank_reg[2], write_bank_reg[2]; + uint32_t read_bank[2], write_bank[2]; + uint8_t misc; + + uint8_t bg_latch[8]; + + uint8_t ht_regs[256]; +} ht216_t; + +#define HT_MISC_PAGE_SEL (1 << 5) + +/*Shifts CPU VRAM read address by 3 bits, for use with fat pixel colour expansion*/ +#define HT_REG_C8_MOVSB (1 << 0) +#define HT_REG_C8_E256 (1 << 4) +#define HT_REG_C8_XLAM (1 << 6) + +#define HT_REG_CD_FP8PCEXP (1 << 1) +#define HT_REG_CD_BMSKSL (3 << 2) +#define HT_REG_CD_RMWMDE (1 << 5) +/*Use GDC data rotate as offset when reading VRAM data into latches*/ +#define HT_REG_CD_ASTODE (1 << 6) +#define HT_REG_CD_EXALU (1 << 7) + +#define HT_REG_E0_SBAE (1 << 7) + +#define HT_REG_F9_XPSEL (1 << 0) + +/*Enables A[14:15] of VRAM address in chain-4 modes*/ +#define HT_REG_FC_ECOLRE (1 << 2) + +#define HT_REG_FE_FBRC (1 << 1) +#define HT_REG_FE_FBMC (3 << 2) +#define HT_REG_FE_FBRSL (3 << 4) + +void ht216_remap(ht216_t *ht216); + +void ht216_out(uint16_t addr, uint8_t val, void *p); +uint8_t ht216_in(uint16_t addr, void *p); + +void ht216_out(uint16_t addr, uint8_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + uint8_t old; + +// pclog("ht216 %i out %04X %02X %04X:%04X\n", svga->miscout & 1, addr, val, CS, cpu_state.pc); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + ht216->clk_sel = (ht216->clk_sel & ~3) | ((val & 0x0c) >> 2); + ht216->misc = val; + ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0x20) | ((val & HT_MISC_PAGE_SEL) ? 0x20 : 0); + ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0x20) | ((val & HT_MISC_PAGE_SEL) ? 0x20 : 0); + ht216_remap(ht216); + svga_recalctimings(&ht216->svga); + break; + + case 0x3c5: + if (svga->seqaddr == 4) + { + svga->chain4 = val & 8; + ht216_remap(ht216); + } + else if (svga->seqaddr == 6) + { + if (val == 0xea) + ht216->ext_reg_enable = 1; + else if (val == 0xae) + ht216->ext_reg_enable = 0; + } + else if (svga->seqaddr >= 0x80 && ht216->ext_reg_enable) + { + ht216->ht_regs[svga->seqaddr & 0xff] = val; +// pclog("HT[%02x]=%02x %04x(%08x):%08x\n", svga->seqaddr, val, CS,cs,cpu_state.pc); + switch (svga->seqaddr & 0xff) + { + case 0x83: + svga->attraddr = val & 0x1f; + svga->attrff = (val & 0x80) ? 1 : 0; + break; + + case 0x94: + svga->hwcursor.addr = ((val << 6) | (3 << 14) | ((ht216->ht_regs[0xff] & 0x60) << 11)) << 2; + //pclog("cursor_addr = %05x\n", svga->hwcursor.addr); + break; + case 0x9c: case 0x9d: + svga->hwcursor.x = ht216->ht_regs[0x9d] | ((ht216->ht_regs[0x9c] & 7) << 8); + break; + case 0x9e: case 0x9f: + svga->hwcursor.y = ht216->ht_regs[0x9f] | ((ht216->ht_regs[0x9e] & 3) << 8); + break; + case 0xa0: + svga->la = val; + break; + case 0xa1: + svga->lb = val; + break; + case 0xa2: + svga->lc = val; + break; + case 0xa3: + svga->ld = val; + break; + case 0xa4: + ht216->clk_sel = (val >> 2) & 0xf; + svga->miscout = (svga->miscout & ~0xc) | ((ht216->clk_sel & 3) << 2); + break; + case 0xa5: + svga->hwcursor.ena = val & 0x80; + break; + case 0xe8: + ht216->read_bank_reg[0] = val; + ht216->write_bank_reg[0] = val; + break; + case 0xe9: + ht216->read_bank_reg[1] = val; + ht216->write_bank_reg[1] = val; + break; + case 0xf6: + svga->vram_display_mask = (val & 0x40) ? ht216->vram_mask : 0x3ffff; + ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0xc0) | ((val & 0xc) << 4); + ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0xc0) | ((val & 0x3) << 6); + break; + case 0xf9: + ht216->read_bank_reg[0] = (ht216->read_bank_reg[0] & ~0x10) | ((val & 1) ? 0x10 : 0); + ht216->write_bank_reg[0] = (ht216->write_bank_reg[0] & ~0x10) | ((val & 1) ? 0x10 : 0); + break; + case 0xfc: + svga->packed_chain4 = val & 0x20; + break; + case 0xff: + svga->hwcursor.addr = ((ht216->ht_regs[0x94] << 6) | (3 << 14) | ((val & 0x60) << 11)) << 2; + //pclog("cursor_addr = %05x\n", svga->hwcursor.addr); + break; + } + switch (svga->seqaddr & 0xff) + { + case 0xa4: case 0xf6: case 0xfc: + svga->fullchange = changeframecount; + svga_recalctimings(&ht216->svga); + break; + } + switch (svga->seqaddr & 0xff) + { + case 0xc8: case 0xc9: case 0xcf: + case 0xe0: case 0xe8: case 0xe9: + case 0xf6: case 0xf9: + ht216_remap(ht216); + break; + } + return; + } + break; + + case 0x3cf: + if (svga->gdcaddr == 6) + { + if (val & 8) + svga->banked_mask = 0x7fff; + else + svga->banked_mask = 0xffff; + } + 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); + +// if (svga->crtcreg == 0xc) +// pclog("CRTC[C]=%02x %08x\n", val, svga->vram_display_mask); + 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(&ht216->svga); + } + } + break; + + case 0x46e8: + io_removehandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + mem_mapping_disable(&ht216->svga.mapping); + mem_mapping_disable(&ht216->linear_mapping); + if (val & 8) + { + io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + mem_mapping_enable(&ht216->svga.mapping); + ht216_remap(ht216); + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t ht216_in(uint16_t addr, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + +// if (addr != 0x3ba && addr != 0x3da) pclog("ht216 %i in %04X\n", svga->miscout & 1, addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: +// pclog("3C2 read\n"); + break; +// return 0x10; + + case 0x3c5: + if (svga->seqaddr == 6) + return ht216->ext_reg_enable; + if (svga->seqaddr >= 0x80) + { + if (ht216->ext_reg_enable) + { +// pclog("Read HT[%02x]=%02x\n", svga->seqaddr & 0xff, ht216->ht_regs[svga->seqaddr & 0xff]); + switch (svga->seqaddr & 0xff) + { + case 0x83: + if (svga->attrff) + return svga->attraddr | 0x80; + return svga->attraddr; + + case 0x8e: return 0x61; /*HT216-32*/ + case 0x8f: return 0x78; + + case 0xa0: + return svga->la; + case 0xa1: + return svga->lb; + case 0xa2: + return svga->lc; + case 0xa3: + return svga->ld; + } + return ht216->ht_regs[svga->seqaddr & 0xff]; + } + else + return 0xff; + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg == 0x1f) + return svga->crtc[0xc] ^ 0xea; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void ht216_remap(ht216_t *ht216) +{ + svga_t *svga = &ht216->svga; + + mem_mapping_disable(&ht216->linear_mapping); + if (ht216->ht_regs[0xc8] & HT_REG_C8_XLAM) + { + uint32_t linear_base = ((ht216->ht_regs[0xc9] & 0xf) << 20) | (ht216->ht_regs[0xcf] << 24); + + pclog("Linear base %08x\n", linear_base); + mem_mapping_set_addr(&ht216->linear_mapping, linear_base, 0x100000); + + /*Linear mapping enabled*/ + } + else + { + uint8_t read_bank_reg[2] = {ht216->read_bank_reg[0], ht216->read_bank_reg[1]}; + uint8_t write_bank_reg[2] = {ht216->write_bank_reg[0], ht216->write_bank_reg[1]}; + + if (!svga->chain4 || !(ht216->ht_regs[0xfc] & HT_REG_FC_ECOLRE)) + { + read_bank_reg[0] &= ~0x30; + read_bank_reg[1] &= ~0x30; + write_bank_reg[0] &= ~0x30; + write_bank_reg[1] &= ~0x30; + } + + ht216->read_bank[0] = read_bank_reg[0] << 12; + ht216->write_bank[0] = write_bank_reg[0] << 12; + if (ht216->ht_regs[0xe0] & HT_REG_E0_SBAE) + { + /*Split bank*/ + ht216->read_bank[1] = read_bank_reg[1] << 12; + ht216->write_bank[1] = write_bank_reg[1] << 12; + } + else + { + ht216->read_bank[1] = ht216->read_bank[0] + (svga->chain4 ? 0x8000 : 0x20000); + ht216->write_bank[1] = ht216->write_bank[0] + (svga->chain4 ? 0x8000 : 0x20000); + } + + if (!svga->chain4) + { + ht216->read_bank[0] >>= 2; + ht216->read_bank[1] >>= 2; + ht216->write_bank[0] >>= 2; + ht216->write_bank[1] >>= 2; + } + } +// pclog("Remap - chain4=%i [e0]=%02x [e8]=%02x [e9]=%02x [f6]=%02x [fc]=%02x [f9]=%02x misc=%02x gdc[6]=%02x read[0]=%05X write[0]=%05X read[1]=%05X write[1]=%05X\n", svga->chain4, ht216->ht_regs[0xe0], ht216->ht_regs[0xe8], ht216->ht_regs[0xe9], ht216->ht_regs[0xf6], ht216->ht_regs[0xfc], ht216->ht_regs[0xf9], ht216->misc, svga->gdcreg[6], ht216->read_bank[0], ht216->write_bank[0], ht216->read_bank[1], ht216->write_bank[1]); +} + +void ht216_recalctimings(svga_t *svga) +{ + ht216_t *ht216 = (ht216_t *)svga->p; + +// pclog("clk_sel = %i\n", ht216->clk_sel); + switch (ht216->clk_sel) + { + case 5: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + case 6: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 10: svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0; break; + } + svga->lowres = !(ht216->ht_regs[0xc8] & HT_REG_C8_E256); + svga->ma_latch |= ((ht216->ht_regs[0xf6] & 0x30) << 12); + svga->interlace = ht216->ht_regs[0xe0] & 1; + + if (svga->bpp == 8 && !svga->lowres) + svga->render = svga_render_8bpp_highres; +} + +static void ht216_hwcursor_draw(svga_t *svga, int displine) +{ +// ht216_t *ht216 = (ht216_t *)svga->p; + int x; + uint32_t dat[2]; + int offset = svga->hwcursor_latch.x + 32; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 4; + + 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+128] << 24) | + (svga->vram[svga->hwcursor_latch.addr+128+1] << 16) | + (svga->vram[svga->hwcursor_latch.addr+128+2] << 8) | + svga->vram[svga->hwcursor_latch.addr+128+3]; + + for (x = 0; x < 32; x++) + { + if (!(dat[0] & 0x80000000)) + ((uint32_t *)buffer32->line[displine])[offset + x] = 0; + if (dat[1] & 0x80000000) + ((uint32_t *)buffer32->line[displine])[offset + x] ^= 0xffffff; + + dat[0] <<= 1; + dat[1] <<= 1; + } + + svga->hwcursor_latch.addr += 4; + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 4; +} + +static inline uint8_t extalu(int op, uint8_t input_a, uint8_t input_b) +{ + uint8_t val; + + switch (op) + { + case 0x0: val = 0; break; + case 0x1: val = ~(input_a | input_b); break; + case 0x2: val = input_a & ~input_b; break; + case 0x3: val = ~input_b; break; + case 0x4: val = ~input_a & input_b; break; + case 0x5: val = ~input_a; break; + case 0x6: val = input_a ^ input_b; break; + case 0x7: val = ~(input_a & input_b); break; + case 0x8: val = input_a & input_b; break; + case 0x9: val = ~(input_a ^ input_b); break; + case 0xa: val = input_a; break; + case 0xb: val = input_a | ~input_b; break; + case 0xc: val = input_b; break; + case 0xd: val = ~input_a | input_b; break; + case 0xe: val = input_a | input_b; break; + case 0xf: default: val = 0xff; break; + } + + return val; +} + +/*Remap address for chain-4/doubleword style layout*/ +static inline uint32_t dword_remap(svga_t *svga, uint32_t in_addr) +{ + if (svga->packed_chain4) + return in_addr; + return ((in_addr & 0xfffc) << 2) | ((in_addr & 0x30000) >> 14) | (in_addr & ~0x3ffff); +} + +static void ht216_dm_write(ht216_t *ht216, uint32_t addr, uint8_t cpu_dat, uint8_t cpu_dat_unexpanded) +{ + svga_t *svga = &ht216->svga; + uint8_t vala, valb, valc, vald, wm = svga->writemask; + int writemask2 = svga->writemask; + uint8_t fg_data[4] = {0,0,0,0}; + + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + if (svga->chain4) + { + writemask2 = 1 << (addr & 3); + addr = dword_remap(svga, addr) & ~3; + } + else if (svga->chain2_write) + { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } + else + { + addr<<=2; + } + if (addr >= svga->vram_max) + return; + + svga->changedvram[addr >> 12]=changeframecount; + + switch (ht216->ht_regs[0xfe] & HT_REG_FE_FBMC) + { + case 0x00: + fg_data[0] = fg_data[1] = fg_data[2] = fg_data[3] = cpu_dat; + break; + case 0x04: + if (ht216->ht_regs[0xfe] & HT_REG_FE_FBRC) + { + if (addr & 4) + { + fg_data[0] = (cpu_dat_unexpanded & (1 << (((addr + 4) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[1] = (cpu_dat_unexpanded & (1 << (((addr + 5) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[2] = (cpu_dat_unexpanded & (1 << (((addr + 6) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[3] = (cpu_dat_unexpanded & (1 << (((addr + 7) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + } + else + { + fg_data[0] = (cpu_dat_unexpanded & (1 << (((addr + 0) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[1] = (cpu_dat_unexpanded & (1 << (((addr + 1) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[2] = (cpu_dat_unexpanded & (1 << (((addr + 2) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[3] = (cpu_dat_unexpanded & (1 << (((addr + 3) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + } + } + else + { + if (addr & 4) + { + fg_data[0] = (ht216->ht_regs[0xf5] & (1 << (((addr + 4) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[1] = (ht216->ht_regs[0xf5] & (1 << (((addr + 5) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[2] = (ht216->ht_regs[0xf5] & (1 << (((addr + 6) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[3] = (ht216->ht_regs[0xf5] & (1 << (((addr + 7) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + } + else + { + fg_data[0] = (ht216->ht_regs[0xf5] & (1 << (((addr + 0) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[1] = (ht216->ht_regs[0xf5] & (1 << (((addr + 1) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[2] = (ht216->ht_regs[0xf5] & (1 << (((addr + 2) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + fg_data[3] = (ht216->ht_regs[0xf5] & (1 << (((addr + 3) & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + } + } + break; + case 0x08: + fg_data[0] = ht216->ht_regs[0xec]; + fg_data[1] = ht216->ht_regs[0xed]; + fg_data[2] = ht216->ht_regs[0xee]; + fg_data[3] = ht216->ht_regs[0xef]; + break; + case 0x0c: + fg_data[0] = ht216->ht_regs[0xec]; + fg_data[1] = ht216->ht_regs[0xed]; + fg_data[2] = ht216->ht_regs[0xee]; + fg_data[3] = ht216->ht_regs[0xef]; + break; + } + + + 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[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) + { + if (writemask2 & 1) svga->vram[addr] = fg_data[0]; + if (writemask2 & 2) svga->vram[addr | 0x1] = fg_data[1]; + if (writemask2 & 4) svga->vram[addr | 0x2] = fg_data[2]; + if (writemask2 & 8) svga->vram[addr | 0x3] = fg_data[3]; + } + else + { + if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + else vala = fg_data[0]; + if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + else valb = fg_data[1]; + if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + else valc = fg_data[2]; + if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + else vald = fg_data[3]; + + 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] || svga->set_reset_disabled)) + { + if (writemask2 & 1) svga->vram[addr] = (((cpu_dat & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((cpu_dat & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((cpu_dat & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((cpu_dat & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + } + else + { + vala = ((cpu_dat & 1) ? 0xff : 0); + valb = ((cpu_dat & 2) ? 0xff : 0); + valc = ((cpu_dat & 4) ? 0xff : 0); + vald = ((cpu_dat & 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: + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= cpu_dat; + + 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; + } +} + +static void ht216_dm_extalu_write(ht216_t *ht216, uint32_t addr, uint8_t cpu_dat, uint8_t bit_mask, uint8_t cpu_dat_unexpanded, uint8_t rop_select) +{ + /*Input B = CD.5 + Input A = FE[3:2] + 00 = Set/Reset output mode + output = CPU-side ALU input + 01 = Solid fg/bg mode (3C4:FA/FB) + Bit mask = 3CF.F5 or CPU byte + 10 = Dithered fg (3CF:EC-EF) + 11 = RMW (dest data) (set if CD.5 = 1) + F/B ROP select = FE[5:4] + 00 = CPU byte + 01 = Bit mask (3CF:8) + 1x = (3C4:F5)*/ + svga_t *svga = &ht216->svga; + uint8_t input_a = 0, input_b = 0; + uint8_t fg, bg; + uint8_t output; + uint32_t remapped_addr = dword_remap(svga, addr); + + if (ht216->ht_regs[0xcd] & HT_REG_CD_RMWMDE) /*RMW*/ + input_b = svga->vram[remapped_addr]; + else + input_b = ht216->bg_latch[addr & 7]; + + switch (ht216->ht_regs[0xfe] & HT_REG_FE_FBMC) + { + case 0x00: + input_a = cpu_dat; + break; + case 0x04: + if (ht216->ht_regs[0xfe] & HT_REG_FE_FBRC) + input_a = (cpu_dat_unexpanded & (1 << ((addr & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + else + input_a = (ht216->ht_regs[0xf5] & (1 << ((addr & 7) ^ 7))) ? ht216->ht_regs[0xfa] : ht216->ht_regs[0xfb]; + break; + case 0x08: + input_a = ht216->ht_regs[0xec + (addr & 3)]; + break; + case 0x0c: + input_a = ht216->bg_latch[addr & 7]; + break; + } + + fg = extalu(ht216->ht_regs[0xce] >> 4, input_a, input_b); + bg = extalu(ht216->ht_regs[0xce] & 0xf, input_a, input_b); +// svga->vram[addr] + output = (fg & rop_select) | (bg & ~rop_select); + svga->vram[addr] = (svga->vram[remapped_addr] & ~bit_mask) | (output & bit_mask); +// pclog(" A=%02x B=%02x R=%02x FG=%02x BG=%02x ops=%02x val=%02x addr=%05x\n", input_a, input_b, rop_select, fg, bg, ht216->ht_regs[0xce], svga->vram[addr], addr); + svga->changedvram[remapped_addr >> 12] = changeframecount; +} + +static void ht216_write_common(ht216_t *ht216, uint32_t addr, uint8_t val) +{ + /*Input B = CD.5 + Input A = FE[3:2] + 00 = Set/Reset output mode + output = CPU-side ALU input + 01 = Solid fg/bg mode (3C4:FA/FB) + Bit mask = 3CF.F5 or CPU byte + 10 = Dithered fg (3CF:EC-EF) + 11 = RMW (dest data) (set if CD.5 = 1) + F/B ROP select = FE[5:4] + 00 = CPU byte + 01 = Bit mask (3CF:8) + 1x = (3C4:F5) + */ + svga_t *svga = &ht216->svga; + + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; + + egawrites++; + + addr &= 0xfffff; + +// pclog("%08X %02x %08x\n", addr, svga->gdcreg[6], svga->banked_mask); + + val = svga_rotate[svga->gdcreg[3] & 7][val]; + + if (ht216->ht_regs[0xcd] & HT_REG_CD_EXALU) /*Extended ALU*/ + { + uint8_t bit_mask = 0, rop_select = 0; + + switch (ht216->ht_regs[0xfe] & HT_REG_FE_FBRSL) + { + case 0x00: + rop_select = val; + break; + case 0x10: + rop_select = svga->gdcreg[8]; + break; + case 0x20: case 0x30: + rop_select = ht216->ht_regs[0xf5]; + break; + } + + switch (ht216->ht_regs[0xcd] & HT_REG_CD_BMSKSL) + { + case 0x00: + bit_mask = svga->gdcreg[8]; + break; + case 0x04: + bit_mask = val; + break; + case 0x08: case 0x0c: + bit_mask = ht216->ht_regs[0xf5]; + break; + } + + if (ht216->ht_regs[0xcd] & HT_REG_CD_FP8PCEXP) /*1->8 bit expansion*/ + { + addr = (addr << 3) & 0xfffff; + ht216_dm_extalu_write(ht216, addr, (val & 0x80) ? 0xff : 0, (bit_mask & 0x80) ? 0xff : 0, val, (rop_select & 0x80) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 1, (val & 0x40) ? 0xff : 0, (bit_mask & 0x40) ? 0xff : 0, val, (rop_select & 0x40) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 2, (val & 0x20) ? 0xff : 0, (bit_mask & 0x20) ? 0xff : 0, val, (rop_select & 0x20) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 3, (val & 0x10) ? 0xff : 0, (bit_mask & 0x10) ? 0xff : 0, val, (rop_select & 0x10) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 4, (val & 0x08) ? 0xff : 0, (bit_mask & 0x08) ? 0xff : 0, val, (rop_select & 0x08) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 5, (val & 0x04) ? 0xff : 0, (bit_mask & 0x04) ? 0xff : 0, val, (rop_select & 0x04) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 6, (val & 0x02) ? 0xff : 0, (bit_mask & 0x02) ? 0xff : 0, val, (rop_select & 0x02) ? 0xff : 0); + ht216_dm_extalu_write(ht216, addr + 7, (val & 0x01) ? 0xff : 0, (bit_mask & 0x01) ? 0xff : 0, val, (rop_select & 0x01) ? 0xff : 0); + } + else + ht216_dm_extalu_write(ht216, addr, val, bit_mask, val, rop_select); + } + else + { + if (ht216->ht_regs[0xcd] & HT_REG_CD_FP8PCEXP) /*1->8 bit expansion*/ + { + addr = (addr << 3) & 0xfffff; + ht216_dm_write(ht216, addr, (val & 0x80) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 1, (val & 0x40) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 2, (val & 0x20) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 3, (val & 0x10) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 4, (val & 0x08) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 5, (val & 0x04) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 6, (val & 0x02) ? 0xff : 0, val); + ht216_dm_write(ht216, addr + 7, (val & 0x01) ? 0xff : 0, val); + } + else + ht216_dm_write(ht216, addr, val, val); + } +} + +static void ht216_write(uint32_t addr, uint8_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + +/* if (ht216->ht_regs[0xcd]) + pclog("ht216_write: [CD]=%02x [FE]=%02x %08x %02x ", ht216->ht_regs[0xcd], ht216->ht_regs[0xfe], addr, val); + pclog("ht216_write : %05X %02X ", addr, val);*/ + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; +// pclog("phys_addr=%05x\n", addr); + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_write_linear(addr, val, &ht216->svga); + else + { + ht216_write_common(ht216, addr, val); + } +} +static void ht216_writew(uint32_t addr, uint16_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_writew_linear(addr, val, &ht216->svga); + else + { + ht216_write_common(ht216, addr, val); + ht216_write_common(ht216, addr+1, val >> 8); + } +} +static void ht216_writel(uint32_t addr, uint32_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_writel_linear(addr, val, &ht216->svga); + else + { + ht216_write_common(ht216, addr, val); + ht216_write_common(ht216, addr+1, val >> 8); + ht216_write_common(ht216, addr+2, val >> 16); + ht216_write_common(ht216, addr+3, val >> 24); + } +} + +static void ht216_write_linear(uint32_t addr, uint8_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (!svga->chain4) /*Bits 16 and 17 of linear address seem to be unused in planar modes*/ + addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_write_linear(addr, val, &ht216->svga); + else + ht216_write_common(ht216, addr, val); +} +static void ht216_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (!svga->chain4) + addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_writew_linear(addr, val, &ht216->svga); + else + { + ht216_write_common(ht216, addr, val); + ht216_write_common(ht216, addr+1, val >> 8); + } +} +static void ht216_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (!svga->chain4) + addr = (addr & 0xffff) | ((addr & 0xc0000) >> 2); + + if (!ht216->ht_regs[0xcd] && !ht216->ht_regs[0xfe]) + svga_writel_linear(addr, val, &ht216->svga); + else + { + ht216_write_common(ht216, addr, val); + ht216_write_common(ht216, addr+1, val >> 8); + ht216_write_common(ht216, addr+2, val >> 16); + ht216_write_common(ht216, addr+3, val >> 24); + } +} + +static uint8_t ht216_read_common(ht216_t *ht216, uint32_t addr) +{ + svga_t *svga = &ht216->svga; + uint8_t temp, temp2, temp3, temp4; + int readplane = svga->readplane; + uint32_t latch_addr; + + if (ht216->ht_regs[0xc8] & HT_REG_C8_MOVSB) + addr <<= 3; +// pclog("%08X\n", addr); + + addr &= 0xfffff; + + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; + + egareads++; + + if (svga->chain4) + { +// if (ht216->ht_regs[0xcd]) +// pclog(" addr=%08x decode_mask=%08x vram_max=%08x\n", addr, svga->decode_mask, svga->vram_max); + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + latch_addr = (addr & svga->vram_mask) & ~7; + if (ht216->ht_regs[0xcd] & HT_REG_CD_ASTODE) + latch_addr += (svga->gdcreg[3] & 7); + ht216->bg_latch[0] = svga->vram[dword_remap(svga, latch_addr)]; + ht216->bg_latch[1] = svga->vram[dword_remap(svga, latch_addr + 1)]; + ht216->bg_latch[2] = svga->vram[dword_remap(svga, latch_addr + 2)]; + ht216->bg_latch[3] = svga->vram[dword_remap(svga, latch_addr + 3)]; + ht216->bg_latch[4] = svga->vram[dword_remap(svga, latch_addr + 4)]; + ht216->bg_latch[5] = svga->vram[dword_remap(svga, latch_addr + 5)]; + ht216->bg_latch[6] = svga->vram[dword_remap(svga, latch_addr + 6)]; + ht216->bg_latch[7] = svga->vram[dword_remap(svga, latch_addr + 7)]; + +/*pclog(" Read %08x %02x %02x %02x %02x %02x %02x %02x %02x\n", addr, + ht216->bg_latch[0],ht216->bg_latch[1],ht216->bg_latch[2],ht216->bg_latch[3], + ht216->bg_latch[4],ht216->bg_latch[5],ht216->bg_latch[6],ht216->bg_latch[7]);*/ + + return svga->vram[dword_remap(svga, addr) & svga->vram_mask]; + } + else if (svga->chain2_read) + { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + addr <<= 2; + } + else + addr<<=2; + + addr &= svga->decode_mask; + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + + latch_addr = addr & ~7; + if (ht216->ht_regs[0xcd] & HT_REG_CD_ASTODE) + { + int offset = addr & 7; + + ht216->bg_latch[0] = svga->vram[latch_addr | offset]; + ht216->bg_latch[1] = svga->vram[latch_addr | ((offset + 1) & 7)]; + ht216->bg_latch[2] = svga->vram[latch_addr | ((offset + 2) & 7)]; + ht216->bg_latch[3] = svga->vram[latch_addr | ((offset + 3) & 7)]; + ht216->bg_latch[4] = svga->vram[latch_addr | ((offset + 4) & 7)]; + ht216->bg_latch[5] = svga->vram[latch_addr | ((offset + 5) & 7)]; + ht216->bg_latch[6] = svga->vram[latch_addr | ((offset + 6) & 7)]; + ht216->bg_latch[7] = svga->vram[latch_addr | ((offset + 7) & 7)]; + } + else + { + ht216->bg_latch[0] = svga->vram[latch_addr]; + ht216->bg_latch[1] = svga->vram[latch_addr | 1]; + ht216->bg_latch[2] = svga->vram[latch_addr | 2]; + ht216->bg_latch[3] = svga->vram[latch_addr | 3]; + ht216->bg_latch[4] = svga->vram[latch_addr | 4]; + ht216->bg_latch[5] = svga->vram[latch_addr | 5]; + ht216->bg_latch[6] = svga->vram[latch_addr | 6]; + ht216->bg_latch[7] = svga->vram[latch_addr | 7]; + } +/*pclog(" Read %02x %02x %02x %02x %02x %02x %02x %02x\n", + ht216->bg_latch[0],ht216->bg_latch[1],ht216->bg_latch[2],ht216->bg_latch[3], + ht216->bg_latch[4],ht216->bg_latch[5],ht216->bg_latch[6],ht216->bg_latch[7]);*/ + if (addr & 4) + { + svga->la = ht216->bg_latch[4]; + svga->lb = ht216->bg_latch[5]; + svga->lc = ht216->bg_latch[6]; + svga->ld = ht216->bg_latch[7]; + } + else + { + svga->la = ht216->bg_latch[0]; + svga->lb = ht216->bg_latch[1]; + svga->lc = ht216->bg_latch[2]; + svga->ld = ht216->bg_latch[3]; + } + if (svga->readmode) + { + temp = svga->la; + temp ^= (svga->colourcompare & 1) ? 0xff : 0; + temp &= (svga->colournocare & 1) ? 0xff : 0; + temp2 = svga->lb; + temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; + temp2 &= (svga->colournocare & 2) ? 0xff : 0; + temp3 = svga->lc; + temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; + temp3 &= (svga->colournocare & 4) ? 0xff : 0; + temp4 = svga->ld; + temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + temp4 &= (svga->colournocare & 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]; + +// return svga_read_linear(addr, &ht216->svga); +} +static uint8_t ht216_read(uint32_t addr, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + +// if (ht216->ht_regs[0xcd]) +// pclog("ht216_read: [CD]=%02x [FC]=%02x %08x\n", ht216->ht_regs[0xcd], ht216->ht_regs[0xfc], addr); +// pclog("ht216_read : %05X ", addr); + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->read_bank[(addr >> 15) & 1]; + + return ht216_read_common(ht216, addr); +} + +/*static uint16_t ht216_readw(uint32_t addr, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + ht216->write_bank[(addr >> 15) & 1]; + return svga_readw_linear(addr, &ht216->svga); +}*/ + +static uint8_t ht216_read_linear(uint32_t addr, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + svga_t *svga = &ht216->svga; + + if (svga->chain4) + return ht216_read_common(ht216, addr); + else + return ht216_read_common(ht216, (addr & 0xffff) | ((addr & 0xc0000) >> 2)); +} + +void *ht216_init() +{ + ht216_t *ht216 = malloc(sizeof(ht216_t)); + svga_t *svga = &ht216->svga; + memset(ht216, 0, sizeof(ht216_t)); + + io_sethandler(0x03c0, 0x0020, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + io_sethandler(0x46e8, 0x0001, ht216_in, NULL, NULL, ht216_out, NULL, NULL, ht216); + + svga_init(&ht216->svga, ht216, 1 << 20, /*1MB*/ + ht216_recalctimings, + ht216_in, ht216_out, + ht216_hwcursor_draw, + NULL); + svga->hwcursor.ysize = 32; + ht216->vram_mask = 0xfffff; + svga->decode_mask = 0xfffff; + + mem_mapping_set_handler(&ht216->svga.mapping, ht216_read, NULL/*ht216_readw*/, NULL, ht216_write, ht216_writew, ht216_writel); + mem_mapping_set_p(&ht216->svga.mapping, ht216); + mem_mapping_add(&ht216->linear_mapping, 0, 0, ht216_read_linear, NULL, NULL, ht216_write_linear, ht216_writew_linear, ht216_writel_linear, NULL, 0, &ht216->svga); + + svga->bpp = 8; + svga->miscout = 1; + + ht216->ht_regs[0xb4] = 0x08; /*32-bit DRAM bus*/ + + return ht216; +} + +static void *ht216_pb410a_init() +{ + ht216_t *ht216 = ht216_init(); + + return ht216; +} + +void ht216_close(void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + + svga_close(&ht216->svga); + + free(ht216); +} + +void ht216_speed_changed(void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + + svga_recalctimings(&ht216->svga); +} + +void ht216_force_redraw(void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + + ht216->svga.fullchange = changeframecount; +} + +void ht216_add_status_info(char *s, int max_len, void *p) +{ + ht216_t *ht216 = (ht216_t *)p; + + svga_add_status_info(s, max_len, &ht216->svga); +} + +device_t ht216_32_pb410a_device = +{ + "Headland HT216-32 (Packard Bell PB410A)", + 0, + ht216_pb410a_init, + ht216_close, + NULL, + ht216_speed_changed, + ht216_force_redraw, + ht216_add_status_info +}; diff --git a/src/vid_ht216.h b/src/vid_ht216.h new file mode 100644 index 0000000..c5e7b3a --- /dev/null +++ b/src/vid_ht216.h @@ -0,0 +1 @@ +extern device_t ht216_32_pb410a_device; diff --git a/src/vid_im1024.c b/src/vid_im1024.c new file mode 100644 index 0000000..386059a --- /dev/null +++ b/src/vid_im1024.c @@ -0,0 +1,906 @@ +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_pgc.h" +#include "vid_im1024.h" + +/* This implements just enough of the Vermont Microsystems IM-1024 to + * support the Windows 1.03 driver. Functions are partially implemented + * or hardwired to the behaviour expected by the Windows driver. + * + * One major difference seems to be that in hex mode, coordinates are + * passed as 2-byte integer words rather than 4-byte fixed-point fractions. + * I don't know what triggers this, so for now it's always on. + */ + +extern uint8_t fontdat12x18[256][36]; + +typedef struct im1024_t +{ + pgc_core_t pgc; + unsigned char fontx[256]; + unsigned char fonty[256]; + unsigned char font[256][128]; + + unsigned char *fifo; + unsigned fifo_len, fifo_wrptr, fifo_rdptr; +} im1024_t; + +/* As well as the usual PGC ring buffer at 0xC6000, the IM1024 appears to + * have an alternate method of passing commands. This is enabled by setting + * 0xC6330 to 1, and then: + * + * CX = count to write + * SI -> bytes to write + * + * Set pending bytes to 0 + * Read [C6331]. This gives number of bytes that can be written: + * 0xFF => 0, 0xFE => 1, 0xFD => 2 etc. + * Write that number of bytes to C6000. + * If there are more to come, go back to reading [C6331]. + * As far as I can see, at least one byte is always written; there's no + * provision to pause if the queue is full. + * + * I am implementing this by holding a FIFO of unlimited depth in the + * IM1024 to receive the data. + * + */ + +static void fifo_write(im1024_t *im1024, unsigned char val) +{ +/* PGCLOG(("fifo_write: %02x [rd=%04x wr=%04x]\n", val, + im1024->fifo_rdptr, im1024->fifo_wrptr)); */ + if (((im1024->fifo_wrptr + 1) % im1024->fifo_len) == im1024->fifo_rdptr) + { +/* FIFO is full. Double its size. */ + unsigned char *buf; + + PGCLOG(("fifo_resize: %d to %d\n", + im1024->fifo_len, 2 * im1024->fifo_len)); + + buf = realloc(im1024->fifo, 2 * im1024->fifo_len); + if (!buf) return; +/* Move the [0..wrptr] range to the newly-allocated area [len..len+wrptr] */ + memmove(buf + im1024->fifo_len, buf, im1024->fifo_wrptr); + im1024->fifo = buf; + im1024->fifo_wrptr += im1024->fifo_len; + im1024->fifo_len *= 2; + } +/* Append to the queue */ + im1024->fifo[im1024->fifo_wrptr] = val; + ++im1024->fifo_wrptr; + +/* Wrap if end of buffer reached */ + if (im1024->fifo_wrptr >= im1024->fifo_len) + { + im1024->fifo_wrptr = 0; + } +} + + +static int fifo_read(im1024_t *im1024) +{ + uint8_t result; + + if (im1024->fifo_wrptr == im1024->fifo_rdptr) + { + return -1; /* FIFO empty */ + } + result = im1024->fifo[im1024->fifo_rdptr]; + ++im1024->fifo_rdptr; + if (im1024->fifo_rdptr >= im1024->fifo_len) + { + im1024->fifo_rdptr = 0; + } +/* + PGCLOG(("fifo_read: %02x\n", result)); +*/ + return result; + +} + +/* Where a normal PGC would just read from the ring buffer at 0xC6300, the + * IM-1024 can read either from this or from its internal FIFO. The internal + * FIFO has priority. */ +int im1024_input_byte(pgc_core_t *pgc, uint8_t *result) +{ + im1024_t *im1024 = (im1024_t *)pgc; + + /* If input buffer empty, wait for it to fill */ + while ((im1024->fifo_wrptr == im1024->fifo_rdptr) && + (pgc->mapram[0x300] == pgc->mapram[0x301])) + { + pgc->waiting_input_fifo = 1; + pgc_sleep(pgc); + } + if (pgc->mapram[0x3FF]) /* Reset triggered */ + { + pgc_reset(pgc); + return 0; + } + if (im1024->fifo_wrptr == im1024->fifo_rdptr) + { + *result = pgc->mapram[pgc->mapram[0x301]]; + ++pgc->mapram[0x301]; + } + else + { + *result = fifo_read(im1024); + } + return 1; +} + +/* Macros to disable clipping and save clip state */ +#define PUSHCLIP { \ + uint16_t vp_x1, vp_x2, vp_y1, vp_y2; \ + vp_x1 = pgc->vp_x1; \ + vp_y1 = pgc->vp_y1; \ + vp_x2 = pgc->vp_x2; \ + vp_y2 = pgc->vp_y2; \ + pgc->vp_x1 = 0; \ + pgc->vp_y1 = 0; \ + pgc->vp_x2 = pgc->maxw - 1; \ + pgc->vp_y2 = pgc->maxh - 1; \ + +/* And to restore clip state */ +#define POPCLIP \ + pgc->vp_x1 = vp_x1; \ + pgc->vp_y1 = vp_y1; \ + pgc->vp_x2 = vp_x2; \ + pgc->vp_y2 = vp_y2; \ + } + + +/* Override memory read to return FIFO space */ +uint8_t im1024_read(uint32_t addr, void *p) +{ + im1024_t *im1024 = (im1024_t *)p; + + if (addr == 0xC6331 && im1024->pgc.mapram[0x330] == 1) + { + return 0x80; /* Hardcode that there are 128 bytes + * free */ + } + return pgc_read(addr, &im1024->pgc); +} + +/* Override memory write to handle writes to the FIFO */ +void im1024_write(uint32_t addr, uint8_t val, void *p) +{ + im1024_t *im1024 = (im1024_t *)p; + + /* If we are in 'fast' input mode, send all writes to the internal + * FIFO */ + if (addr >= 0xC6000 && addr < 0xC6100 && im1024->pgc.mapram[0x330] == 1) + { + fifo_write(im1024, val); +/* + PGCLOG(("im1024_write(%02x)\n", val)); +*/ + if (im1024->pgc.waiting_input_fifo) + { + im1024->pgc.waiting_input_fifo = 0; + pgc_wake(&im1024->pgc); + } + return; + } + pgc_write(addr, val, &im1024->pgc); +} + + + +/* I don't know what the IMGSIZ command does, only that the Windows driver + * issues it. So just parse and ignore it */ +void hndl_imgsiz(pgc_core_t *pgc) +{ + int16_t w,h; + uint8_t a,b; +// im1024_t *im1024 = (im1024_t *)pgc; + + if (!pgc_param_word(pgc, &w)) return; + if (!pgc_param_word(pgc, &h)) return; + if (!pgc_param_byte(pgc, &a)) return; + if (!pgc_param_byte(pgc, &b)) return; + + PGCLOG(("IMGSIZ %d,%d,%d,%d\n", w,h,a,b)); +} + + +/* I don't know what the IPREC command does, only that the Windows driver + * issues it. So just parse and ignore it */ +void hndl_iprec(pgc_core_t *pgc) +{ + uint8_t param; +// im1024_t *im1024 = (im1024_t *)pgc; + + if (!pgc_param_byte(pgc, ¶m)) return; + + PGCLOG(("IPREC %d\n", param)); +} + +/* I think PAN controls which part of the 1024x1024 framebuffer is displayed + * in the 1024x800 visible screen. */ +void hndl_pan(pgc_core_t *pgc) +{ + int16_t x,y; + + if (!pgc_param_word(pgc, &x)) return; + if (!pgc_param_word(pgc, &y)) return; + + PGCLOG(("PAN %d,%d\n", x, y)); + + pgc->pan_x = x; + pgc->pan_y = y; +} + +/* PLINE draws a non-filled polyline at a fixed position */ +void hndl_pline(pgc_core_t *pgc) +{ + int16_t x[257]; + int16_t y[257]; + uint8_t count; + unsigned n; + uint16_t linemask = pgc->line_pattern; + + if (!pgc_param_byte(pgc, &count)) return; + + PGCLOG(("PLINE (%d) ", count)); + for (n = 0; n < count; n++) + { + if (!pgc_param_word(pgc, &x[n])) return; + if (!pgc_param_word(pgc, &y[n])) return; + PGCLOG((" (%d,%d)\n", x[n], y[n])); + } + for (n = 1; n < count; n++) + { + linemask = pgc_draw_line(pgc, x[n - 1] << 16, y[n - 1] << 16, + x[n] << 16, y[n] << 16, linemask); + } +} + + +/* Blit a single row of pixels from one location to another. To avoid + * difficulties if the two overlap, read both rows into memory, process them + * there, and write the result back. */ +void blkmov_row(pgc_core_t *pgc, int16_t x0, int16_t x1, int16_t x2, + int16_t sy, int16_t ty) +{ + int16_t x; + uint8_t src[1024]; + uint8_t dst[1024]; + + for (x = x0; x <= x1; x++) + { + src[x - x0] = pgc_read_pixel(pgc, x, sy); + dst[x - x0] = pgc_read_pixel(pgc, x - x0 + x2, ty); + } + for (x = x0; x <= x1; x++) + { + switch (pgc->draw_mode) + { + default: + case 0: pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0]); break; + case 1: pgc_write_pixel(pgc, (x - x0 + x2), ty, dst[x - x0] ^ 0xFF); break; + case 2: pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0] ^ dst[x - x0]); break; + case 3: pgc_write_pixel(pgc, (x - x0 + x2), ty, src[x - x0] & dst[x - x0]); break; + } + } + +} + + +/* BLKMOV blits a rectangular area from one location to another, with no + * clipping. */ +void hndl_blkmov(pgc_core_t *pgc) +{ + int16_t x0,y0; + int16_t x1,y1; + int16_t x2,y2; + int16_t y; +// im1024_t *im1024 = (im1024_t *)pgc; + + if (!pgc_param_word(pgc, &x0)) return; + if (!pgc_param_word(pgc, &y0)) return; + if (!pgc_param_word(pgc, &x1)) return; + if (!pgc_param_word(pgc, &y1)) return; + if (!pgc_param_word(pgc, &x2)) return; + if (!pgc_param_word(pgc, &y2)) return; + + PGCLOG(("BLKMOV %d,%d,%d,%d,%d,%d\n", x0,y0,x1,y1,x2,y2)); + + /* Disable clipping */ + PUSHCLIP + + /* Either go down from the top, or up from the bottom, depending + * whether areas might overlap */ + if (y2 <= y0) + { + for (y = y0; y <= y1; y++) + { + blkmov_row(pgc, x0, x1, x2, y, y - y0 + y2); + } + } + else + { + for (y = y1; y >= y0; y--) + { + blkmov_row(pgc, x0, x1, x2, y, y - y0 + y2); + } + } + /* Restore clipping */ + POPCLIP +} + + +/* This overrides the PGC ELIPSE command to parse its parameters as words + * rather than coordinates */ +static void hndl_ellipse(pgc_core_t *pgc) +{ + int16_t x, y; + + if (!pgc_param_word(pgc, &x)) return; + if (!pgc_param_word(pgc, &y)) return; + + PGCLOG(("ELLIPSE %d,%d @ %d,%d\n", x,y, + pgc->x >> 16, pgc->y >> 16)); + pgc_draw_ellipse(pgc, x << 16, y << 16); +} + + + +/* This overrides the PGC MOVE command to parse its parameters as words + * rather than coordinates */ +static void hndl_move(pgc_core_t *pgc) +{ + int16_t x, y; + + if (!pgc_param_word(pgc, &x)) return; + if (!pgc_param_word(pgc, &y)) return; + + pgc->x = x << 16; + pgc->y = y << 16; + PGCLOG(("MOVE %d,%d\n", x,y)); +} + +/* This overrides the PGC DRAW command to parse its parameters as words + * rather than coordinates */ +static void hndl_draw(pgc_core_t *pgc) +{ + int16_t x, y; + + if (!pgc_param_word(pgc, &x)) return; + if (!pgc_param_word(pgc, &y)) return; + + PGCLOG(("DRAW %d,%d to %d,%d\n", + pgc->x >> 16, pgc->y >> 16, x, y)); + pgc_draw_line(pgc, pgc->x, pgc->y, x << 16, y << 16, pgc->line_pattern); + pgc->x = x << 16; + pgc->y = y << 16; +} + + + + +/* This overrides the PGC POLY command to parse its parameters as words + * rather than coordinates */ +static void hndl_poly(pgc_core_t *pgc) +{ + int32_t *x, *y; + int32_t n; + int16_t xw, yw, mask; + unsigned realcount = 0; + int parsing = 1; + int as = 256; + + x = malloc(as * sizeof(int32_t)); + y = malloc(as * sizeof(int32_t)); + + if (!x || !y) + { + PGCLOG(("hndl_poly: malloc failed\n")); + return; + } + while (parsing) + { + uint8_t count; + if (!pgc_param_byte(pgc, &count)) return; + + if (count + realcount >= as) + { + int32_t *nx, *ny; + + nx = realloc(x, 2 * as * sizeof(int32_t)); + ny = realloc(y, 2 * as * sizeof(int32_t)); + if (!x || !y) + { + PGCLOG(("hndl_poly: realloc failed\n")); + break; + } + x = nx; + y = ny; + as *= 2; + } + + for (n = 0; n < count; n++) + { + if (!pgc_param_word(pgc, &xw)) return; + if (!pgc_param_word(pgc, &yw)) return; + + /* Skip degenerate line segments */ + if (realcount > 0 && + (xw << 16) == x[realcount - 1] && + (yw << 16) == y[realcount - 1]) + { + continue; + } + x[realcount] = xw << 16; + y[realcount] = yw << 16; + ++realcount; + } +/* If we're in a command list, peek ahead to see if the next command is + * also POLY. If so, that's a continuation of this polygon! */ + parsing = 0; + if (pgc->clcur && (pgc->clcur->rdptr+1) < pgc->clcur->wrptr && + pgc->clcur->list[pgc->clcur->rdptr] == 0x30) + { + PGCLOG(("hndl_poly: POLY continues!\n")); + parsing = 1; + /* Swallow the POLY */ + ++pgc->clcur->rdptr; + } + + } + + PGCLOG(("POLY (%d) fill_mode=%d\n", realcount, pgc->fill_mode)); + for (n = 0; n < realcount; n++) + { + PGCLOG((" (%d,%d)\n", x[n] >> 16, y[n] >> 16)); + } + if (pgc->fill_mode) + { + pgc_fill_polygon(pgc, realcount, x, y); + } + /* Now draw borders */ + mask = pgc->line_pattern; + for (n = 1; n < realcount; n++) + { + mask = pgc_draw_line(pgc, x[n - 1], y[n - 1], x[n], y[n], mask); + } + pgc_draw_line(pgc, x[realcount - 1], y[realcount - 1], x[0], y[0], mask); + free(y); + free(x); +} + + +static int parse_poly(pgc_core_t *pgc, pgc_commandlist_t *cl, int c) +{ + uint8_t count; + + PGCLOG(("parse_poly\n")); + if (!pgc_param_byte(pgc, &count)) return 0; + + PGCLOG(("parse_poly: count=%02x\n", count)); + if (!pgc_commandlist_append(cl, count)) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + return 0; + } + PGCLOG(("parse_poly: parse %d words\n", 2 * count)); + return pgc_parse_words(pgc, cl, count * 2); +} + + + +/* This overrides the PGC RECT command to parse its parameters as words + * rather than coordinates */ +static void hndl_rect(pgc_core_t *pgc) +{ + int16_t x0, y0, x1, y1, p, q; + + x0 = pgc->x >> 16; + y0 = pgc->y >> 16; + + if (!pgc_param_word(pgc, &x1)) return; + if (!pgc_param_word(pgc, &y1)) return; + + /* Convert to raster coords */ + pgc_sto_raster(pgc, &x0, &y0); + pgc_sto_raster(pgc, &x1, &y1); + + if (x0 > x1) { p = x0; x0 = x1; x1 = p; } + if (y0 > y1) { q = y0; y0 = y1; y1 = q; } + + PGCLOG(("RECT (%d,%d) -> (%d,%d)\n", x0, y0, x1, y1)); + + if (pgc->fill_mode) + { + for (p = y0; p <= y1; p++) + { + pgc_fill_line_r(pgc, x0, x1, p); + } + } + else /* Outline: 4 lines */ + { + p = pgc->line_pattern; + p = pgc_draw_line_r(pgc, x0, y0, x1, y0, p); + p = pgc_draw_line_r(pgc, x1, y0, x1, y1, p); + p = pgc_draw_line_r(pgc, x1, y1, x0, y1, p); + p = pgc_draw_line_r(pgc, x0, y1, x0, y0, p); + } +} + + +/* TODO: Text drawing should probably be implemented in vid_pgc.c rather + * than vid_im1024.c */ +static void hndl_tdefin(pgc_core_t *pgc) +{ + unsigned char ch, bt; + unsigned char rows, cols; + unsigned len, n; +// unsigned x = 0; + im1024_t * im1024 = (im1024_t *)pgc; + + if (!pgc_param_byte(pgc, &ch)) return; + if (!pgc_param_byte(pgc, &cols)) return; + if (!pgc_param_byte(pgc, &rows)) return; + + PGCLOG(("TDEFIN (%d,%d,%d) 0x%02x 0x%02x\n", ch, rows, cols, + pgc->mapram[0x300], pgc->mapram[0x301])); + + len = ((cols + 7) / 8) * rows; + for (n = 0; n < len; n++) + { +// char buf[10]; +// unsigned char mask; + + if (!pgc_param_byte(pgc, &bt)) return; + +// buf[0] = 0; +// for (mask = 0x80; mask != 0; mask >>= 1) +// { +// if (bt & mask) strcat(buf, "#"); +// else strcat(buf, "-"); +// ++x; +// if (x == cols) { strcat(buf, "\n"); x = 0; } +// } +// PGCLOG((buf)); + + if (n < sizeof(im1024->font[ch])) im1024->font[ch][n] = bt; + } + im1024->fontx[ch] = cols; + im1024->fonty[ch] = rows; +} + +static void hndl_tsize(pgc_core_t *pgc) +{ + int16_t size; + + if (!pgc_param_word(pgc, &size)) return; + PGCLOG(("TSIZE(%d)\n", size)); + + pgc->tsize = size << 16; +} + + + +static void hndl_twrite(pgc_core_t *pgc) +{ + unsigned char count; + unsigned char mask; + unsigned char *row; + int x, y, wb, n; + im1024_t * im1024 = (im1024_t *)pgc; + int16_t x0 = pgc->x >> 16; + int16_t y0 = pgc->y >> 16; + unsigned char buf[256]; +/* unsigned char rbuf[256];*/ + + if (!pgc_param_byte(pgc, &count)) return; + + for (n = 0; n < count; n++) + { + if (!pgc_param_byte(pgc, &buf[n])) return; + } + buf[count] = 0; +/* for (n = 0; n <= count; n++) + { + if (isprint(buf[n]) || 0 == buf[n]) + { + rbuf[n] = buf[n]; + } + else rbuf[n] = '?'; + }*/ + pgc_sto_raster(pgc, &x0, &y0); + PGCLOG(("TWRITE (%d,%-*.*s) x0=%d y0=%d\n", count, count, count, rbuf, x0, y0)); + + for (n = 0; n < count; n++) + { + wb = (im1024->fontx[buf[n]] + 7) / 8; + PGCLOG(("ch=0x%02x w=%d h=%d wb=%d\n", + buf[n], im1024->fontx[buf[n]], + im1024->fonty[buf[n]], wb)); + for (y = 0; y < im1024->fonty[buf[n]]; y++) + { + mask = 0x80; + row = &im1024->font[buf[n]][y * wb]; + for (x = 0; x < im1024->fontx[buf[n]]; x++) + { +/* rbuf[x] = (row[0] & mask) ? '#' : '-';*/ + if (row[0] & mask) pgc_plot(pgc, x + x0, y0 - y); + mask = mask >> 1; + if (mask == 0) { mask = 0x80; ++row; } + } +/* rbuf[x++] = '\n'; + rbuf[x++] = 0;*/ +// PGCLOG((rbuf); + } + x0 += im1024->fontx[buf[n]]; + } +} + + + +static void hndl_txt88(pgc_core_t *pgc) +{ + unsigned char count; + unsigned char mask; + unsigned char *row; + int x, y, /*wb, */n; + int16_t x0 = pgc->x >> 16; + int16_t y0 = pgc->y >> 16; + unsigned char buf[256]; +/* unsigned char rbuf[256];*/ + + if (!pgc_param_byte(pgc, &count)) return; + + for (n = 0; n < count; n++) + { + if (!pgc_param_byte(pgc, &buf[n])) return; + } + buf[count] = 0; +/* for (n = 0; n <= count; n++) + { + if (isprint(buf[n]) || 0 == buf[n]) + { + rbuf[n] = buf[n]; + } + else rbuf[n] = '?'; + }*/ + pgc_sto_raster(pgc, &x0, &y0); + PGCLOG(("TXT88 (%d,%-*.*s) x0=%d y0=%d\n", count, count, count, rbuf, x0, y0)); + + for (n = 0; n < count; n++) + { +/* wb = 2;*/ + PGCLOG(("ch=0x%02x w=%d h=%d wb=%d\n", buf[n], 12, 18, wb)); + for (y = 0; y < 18; y++) + { + mask = 0x80; + row = &fontdat12x18[buf[n]][y * 2]; + for (x = 0; x < 12; x++) + { +/* rbuf[x] = (row[0] & mask) ? '#' : '-';*/ + if (row[0] & mask) pgc_plot(pgc, x + x0, y0 - y); + mask = mask >> 1; + if (mask == 0) { mask = 0x80; ++row; } + } +/* rbuf[x++] = '\n'; + rbuf[x++] = 0;*/ +// PGCLOG((rbuf); + } + x0 += 12; + } +} + + + + +static void hndl_imagew(pgc_core_t *pgc) +{ + int16_t row1, col1, col2; + uint8_t v1, v2; + int16_t vp_x1, vp_y1, vp_x2, vp_y2; + + if (!pgc_param_word(pgc, &row1)) return; + if (!pgc_param_word(pgc, &col1)) return; + if (!pgc_param_word(pgc, &col2)) return; + + /* IMAGEW already uses raster coordinates so there is no need to + * convert it */ + PGCLOG(("IMAGEW (row=%d,col1=%d,col2=%d)\n", row1, col1, col2)); + + vp_x1 = pgc->vp_x1; + vp_y1 = pgc->vp_y1; + vp_x2 = pgc->vp_x2; + vp_y2 = pgc->vp_y2; + /* Disable clipping */ + pgc->vp_x1 = 0; + pgc->vp_y1 = 0; + pgc->vp_x2 = pgc->maxw - 1; + pgc->vp_y2 = pgc->maxh - 1; + + /* In ASCII mode, what is written is a stream of bytes */ + if (pgc->ascii_mode) + { + while (col1 <= col2) + { + if (!pgc_param_byte(pgc, &v1)) return; + pgc_write_pixel(pgc, col1, row1, v1); + ++col1; + } + return; + } + else /* In hex mode, it's RLE compressed */ + { + while (col1 <= col2) + { + if (!pgc_param_byte(pgc, &v1)) return; + + if (v1 & 0x80) /* Literal run */ + { + v1 -= 0x7F; + while (col1 <= col2 && v1 != 0) + { + if (!pgc_param_byte(pgc, &v2)) return; + pgc_write_pixel(pgc, col1, row1, v2); + ++col1; + --v1; + } + } + else /* Repeated run */ + { + if (!pgc_param_byte(pgc, &v2)) return; + + ++v1; + while (col1 <= col2 && v1 != 0) + { + pgc_write_pixel(pgc, col1, row1, v2); + ++col1; + --v1; + } + } + } + } + /* Restore clipping */ + pgc->vp_x1 = vp_x1; + pgc->vp_y1 = vp_y1; + pgc->vp_x2 = vp_x2; + pgc->vp_y2 = vp_y2; +} + +/* I have called this command DOT - I don't know its proper name. Draws a + * single pixel at the current location */ +static void hndl_dot(pgc_core_t *pgc) +{ + int16_t x = pgc->x >> 16, y = pgc->y >> 16; + + pgc_sto_raster(pgc, &x, &y); + + PGCLOG(("Dot @ %d,%d ink=%d mode=%d\n", x, y, pgc->colour, pgc->draw_mode)); + pgc_plot(pgc, x, y); +} + +/* This command (which I have called IMAGEX, since I don't know its real + * name) is a screen-to-memory blit. It reads a rectangle of bytes, rather + * than the single row read by IMAGER, and does not attempt to compress + * the result */ +static void hndl_imagex(pgc_core_t *pgc) +{ + int16_t x0, x1, y0, y1; + int16_t p,q; + + if (!pgc_param_word(pgc, &x0)) return; + if (!pgc_param_word(pgc, &y0)) return; + if (!pgc_param_word(pgc, &x1)) return; + if (!pgc_param_word(pgc, &y1)) return; + + /* IMAGEX already uses raster coordinates so don't convert */ + PGCLOG(("IMAGEX (%d,%d,%d,%d)\n", x0,y0,x1,y1)); + + for (p = y0; p <= y1; p++) + { + for (q = x0; q <= x1; q++) + { + if (!pgc_result_byte(pgc, pgc_read_pixel(pgc, q, p))) + return; + } + } +} + +/* Commands implemented by the IM-1024. + * + * TODO: A lot of commands need commandlist parsers. + * TODO: The IM-1024 has a lot more commands that are not included here + * (BLINK, BUTRD, COPROC, RBAND etc) because the Windows 1.03 driver + * does not use them. + */ +static const pgc_command_t im1024_commands[] = +{ + { "BLKMOV", 0xDF, hndl_blkmov, pgc_parse_words, 6 }, + { "DRAW", 0x28, hndl_draw, pgc_parse_words, 2 }, + { "D", 0x28, hndl_draw, pgc_parse_words, 2 }, + { "DOT", 0x08, hndl_dot }, + { "ELIPSE", 0x39, hndl_ellipse, pgc_parse_words, 2 }, + { "EL", 0x39, hndl_ellipse, pgc_parse_words, 2 }, + { "IMAGEW", 0xD9, hndl_imagew }, + { "IW", 0xD9, hndl_imagew }, + { "IMAGEX", 0xDA, hndl_imagex }, + { "TXT88", 0x88, hndl_txt88 }, + { "TWRITE", 0x8B, hndl_twrite }, + { "TDEFIN", 0x84, hndl_tdefin }, + { "TD", 0x84, hndl_tdefin }, + { "TSIZE", 0x81, hndl_tsize }, + { "TS", 0x81, hndl_tsize }, + { "IPREC", 0xE4, hndl_iprec }, + { "IMGSIZ", 0x4E, hndl_imgsiz }, + { "LUT8", 0xE6, pgc_hndl_lut8 }, + { "L8", 0xE6, pgc_hndl_lut8 }, + { "LUT8RD", 0x53, pgc_hndl_lut8rd }, + { "L8RD", 0x53, pgc_hndl_lut8rd }, + { "PAN", 0xB7, hndl_pan }, + { "POLY", 0x30, hndl_poly, parse_poly }, + { "P", 0x30, hndl_poly, parse_poly }, + { "PLINE", 0x36, hndl_pline }, + { "PL", 0x37, hndl_pline }, + { "MOVE", 0x10, hndl_move, pgc_parse_words, 2 }, + { "M", 0x10, hndl_move, pgc_parse_words, 2 }, + { "RECT", 0x34, hndl_rect }, + { "R", 0x34, hndl_rect }, + { "******", 0x00, NULL } +}; + + +void *im1024_init() +{ + im1024_t *im1024 = malloc(sizeof(im1024_t)); + memset(im1024, 0, sizeof(im1024_t)); + + im1024->fifo = malloc(4096); + im1024->fifo_len = 4096; + im1024->fifo_wrptr = 0; + im1024->fifo_rdptr = 0; + + /* 1024x1024 framebuffer with 1024x800 visible + Pixel clock is a guess */ + pgc_core_init(&im1024->pgc, 1024, 1024, 1024, 800, im1024_input_byte, 65000000.0); + + mem_mapping_set_handler(&im1024->pgc.mapping, + im1024_read, NULL, NULL, + im1024_write, NULL, NULL); + + im1024->pgc.pgc_commands = im1024_commands; + return im1024; +} + +void im1024_close(void *p) +{ + im1024_t *im1024 = (im1024_t *)p; + + pgc_close(&im1024->pgc); +} + +void im1024_speed_changed(void *p) +{ + im1024_t *im1024 = (im1024_t *)p; + + pgc_speed_changed(&im1024->pgc); +} + +device_t im1024_device = +{ + "Image Manager 1024", + 0, + im1024_init, + im1024_close, + NULL, + im1024_speed_changed, + NULL, + NULL, + NULL +}; diff --git a/src/vid_im1024.h b/src/vid_im1024.h new file mode 100644 index 0000000..145401e --- /dev/null +++ b/src/vid_im1024.h @@ -0,0 +1 @@ +extern device_t im1024_device; diff --git a/src/vid_incolor.c b/src/vid_incolor.c index 88df9c2..76fa405 100644 --- a/src/vid_incolor.c +++ b/src/vid_incolor.c @@ -148,8 +148,8 @@ typedef struct incolor_t uint8_t ctrl, ctrl2, stat; - int dispontime, dispofftime; - int vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; @@ -358,8 +358,8 @@ void incolor_recalctimings(incolor_t *incolor) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - incolor->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - incolor->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + incolor->dispontime = (uint64_t)_dispontime; + incolor->dispofftime = (uint64_t)_dispofftime; } @@ -851,7 +851,7 @@ void incolor_poll(void *p) if (!incolor->linepos) { // pclog("InColor poll %i %i\n", incolor->vc, incolor->sc); - incolor->vidtime += incolor->dispofftime; + timer_advance_u64(&incolor->timer, incolor->dispofftime); incolor->stat |= 1; incolor->linepos = 1; oldsc = incolor->sc; @@ -886,7 +886,7 @@ void incolor_poll(void *p) } else { - incolor->vidtime += incolor->dispontime; + timer_advance_u64(&incolor->timer, incolor->dispontime); if (incolor->dispon) incolor->stat &= ~1; incolor->linepos = 0; @@ -1006,8 +1006,8 @@ void *incolor_init() 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); + timer_add(&incolor->timer, incolor_poll, incolor, 1); + mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, incolor); io_sethandler(0x03b0, 0x0010, incolor_in, NULL, NULL, incolor_out, NULL, NULL, incolor); for (c = 0; c < 64; c++) diff --git a/src/vid_mda.c b/src/vid_mda.c index a3a7b39..31ba65a 100644 --- a/src/vid_mda.c +++ b/src/vid_mda.c @@ -8,31 +8,8 @@ #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]; +static uint32_t mdacols[256][2][2]; void mda_recalctimings(mda_t *mda); @@ -96,8 +73,8 @@ void mda_recalctimings(mda_t *mda) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - mda->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - mda->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + mda->dispontime = (uint64_t)_dispontime; + mda->dispofftime = (uint64_t)_dispofftime; } void mda_poll(void *p) @@ -112,7 +89,7 @@ void mda_poll(void *p) int blink; if (!mda->linepos) { - mda->vidtime += mda->dispofftime; + timer_advance_u64(&mda->timer, mda->dispofftime); mda->stat |= 1; mda->linepos = 1; oldsc = mda->sc; @@ -135,20 +112,22 @@ void mda_poll(void *p) if (mda->sc == 12 && ((attr & 7) == 1)) { for (c = 0; c < 9; c++) - buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][1]; + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->line[mda->displine])[(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) + ((uint32_t *)buffer32->line[mda->displine])[(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][mda->sc] & 1]; + else + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->line[mda->displine])[(x * 9) + c] ^= mdacols[attr][0][1]; } } } @@ -164,7 +143,7 @@ void mda_poll(void *p) } else { - mda->vidtime += mda->dispontime; + timer_advance_u64(&mda->timer, mda->dispontime); if (mda->dispon) mda->stat&=~1; mda->linepos=0; if (mda->vsynctime) @@ -233,7 +212,7 @@ void mda_poll(void *p) updatewindowsize(xsize, ysize); } - video_blit_memtoscreen_8(0, mda->firstline, xsize, mda->lastline - mda->firstline); + video_blit_memtoscreen(0, mda->firstline, 0, ysize, xsize, ysize); frames++; video_res_x = mda->crtc[1]; @@ -259,38 +238,54 @@ void mda_poll(void *p) } } -void *mda_init() +void *mda_standalone_init() { - int c; mda_t *mda = malloc(sizeof(mda_t)); + memset(mda, 0, sizeof(mda_t)); + mda_init(mda); 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); + mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + return mda; +} + + +void mda_init(mda_t *mda) +{ + int display_type; + int c; + + display_type = device_get_config_int("display_type"); + cgapal_rebuild(display_type, 0); + 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[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = cgapal[0]; + if (c & 8) mdacols[c][0][1] = cgapal[0xf]; + else mdacols[c][0][1] = cgapal[0x7]; } - 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; + mdacols[0x70][0][1] = cgapal[0]; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = cgapal[0xf]; + mdacols[0xF0][0][1] = cgapal[0]; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = cgapal[0xf]; + mdacols[0x78][0][1] = cgapal[0x7]; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = cgapal[0xf]; + mdacols[0xF8][0][1] = cgapal[0x7]; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = cgapal[0xf]; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = cgapal[0]; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = cgapal[0]; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = cgapal[0]; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = cgapal[0]; + + timer_add(&mda->timer, mda_poll, mda, 1); +} - return mda; +void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink) +{ + mdacols[chr][blink][fg] = cgapal[cga_ink]; } void mda_close(void *p) @@ -308,14 +303,46 @@ void mda_speed_changed(void *p) mda_recalctimings(mda); } +static device_config_t mda_config[] = +{ + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Green", + .value = DISPLAY_GREEN + }, + { + .description = "Amber", + .value = DISPLAY_AMBER + }, + { + .description = "White", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + }, + .default_int = DISPLAY_WHITE + }, + { + .type = -1 + } +}; + device_t mda_device = { "MDA", 0, - mda_init, + mda_standalone_init, mda_close, NULL, mda_speed_changed, NULL, - NULL + NULL, + mda_config }; diff --git a/src/vid_mda.h b/src/vid_mda.h index 99aa13c..7a5a2f7 100644 --- a/src/vid_mda.h +++ b/src/vid_mda.h @@ -1 +1,38 @@ + +typedef struct mda_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, stat; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; + + 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; + +void mda_init(mda_t *mda); +void mda_out(uint16_t addr, uint8_t val, void *p); +uint8_t mda_in(uint16_t addr, void *p); +void mda_write(uint32_t addr, uint8_t val, void *p); +uint8_t mda_read(uint32_t addr, void *p); +void mda_recalctimings(mda_t *mda); +void mda_poll(void *p); + +/* Override mapping of attribute to colour */ +void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink); + extern device_t mda_device; + diff --git a/src/vid_mga.c b/src/vid_mga.c new file mode 100644 index 0000000..4bcc091 --- /dev/null +++ b/src/vid_mga.c @@ -0,0 +1,5439 @@ +/*Matrox Mystique 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_mga.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) +#define FIFO_THRESHOLD 0xe000 + +#define WAKE_DELAY (100 * TIMER_USEC) /*100us*/ + +#define FIFO_ENTRIES (mystique->fifo_write_idx - mystique->fifo_read_idx) +#define FIFO_FULL ((mystique->fifo_write_idx - mystique->fifo_read_idx) >= (FIFO_SIZE-1)) +#define FIFO_EMPTY (mystique->fifo_read_idx == mystique->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_CTRL_BYTE = (0x01 << 24), + FIFO_WRITE_CTRL_LONG = (0x02 << 24), + FIFO_WRITE_ILOAD_LONG = (0x03 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct mystique_t +{ + svga_t svga; + + rom_t bios_rom; + + mem_mapping_t lfb_mapping; + mem_mapping_t ctrl_mapping; + mem_mapping_t iload_mapping; + + uint8_t pci_regs[256]; + uint8_t int_line; + int card; + + int vram_size; + uint32_t vram_mask, vram_mask_w, vram_mask_l; + + uint32_t lfb_base, ctrl_base, iload_base; + + uint8_t crtcext_regs[6]; + int crtcext_idx; + + uint8_t xreg_regs[256]; + int xreg_idx; + + uint32_t ma_latch_old; + + uint32_t maccess, mctlwtst; + uint32_t maccess_running; + + uint32_t status; + + uint8_t xcurctrl; + + uint8_t xsyspllm, xsysplln, xsyspllp; + struct + { + int m, n, p, s; + } xpixpll[3]; + + uint8_t xgenioctrl; + uint8_t xgeniodata; + uint8_t xmulctrl; + uint8_t xgenctrl; + uint8_t xmiscctrl; + uint8_t xpixclkctrl; + uint8_t xvrefctrl; + uint8_t xcolkeymskl, xcolkeymskh; + uint8_t xcolkeyl, xcolkeyh; + int xzoomctrl; + uint8_t xcrcbitsel; + + uint8_t ien; + + struct + { + uint8_t funcnt, stylelen; + int xoff, yoff; + + uint16_t cxleft, cxright; + int16_t fxleft, fxright; + uint16_t length; + + uint32_t dwgctrl; + uint32_t dwgctrl_running; + uint32_t bcol, fcol; + uint32_t pitch; + uint32_t plnwt; + uint32_t ybot; + uint32_t ydstorg; + uint32_t ytop; + int selline; + + uint32_t src[4]; + uint32_t ar[7]; + uint32_t dr[16]; + + int pattern[8][8]; + + struct + { + int sdydxl; + int scanleft; + int sdxl; + int sdy; + int sdxr; + } sgn; + + uint32_t tmr[9]; + uint32_t texorg, texwidth, texheight; + uint32_t texctl, textrans; + uint32_t zorg; + + int ydst; + uint32_t ydst_lin; + + int length_cur; + int16_t xdst; + uint32_t src_addr; + uint32_t z_base; + + int iload_rem_count; + uint32_t iload_rem_data; + int idump_end_of_line; + + int words; + + int ta_key, ta_mask; + + int lastpix_r, lastpix_g, lastpix_b; + + int highv_line; + uint32_t highv_data; + + int beta; + + int dither; + + uint8_t dmamod; + } dwgreg; + + struct + { + uint8_t r, g, b; + } lut[256]; + + struct + { + uint16_t pos_x, pos_y; + uint16_t addr; + uint32_t col[3]; + } cursor; + + uint8_t dmamod, dmadatasiz, dirdatasiz; + struct + { + uint32_t primaddress, primend; + uint32_t secaddress, secend; + + int pri_pos, sec_pos, iload_pos; + uint32_t pri_header, sec_header, iload_header; + + int pri_state, sec_state, iload_state; + + int state; + + mutex_t *lock; +// pc_timer_t timer; + } dma; + + uint8_t dmamap[16]; + + volatile int busy; + volatile int blitter_submit_refcount; + volatile int blitter_submit_dma_refcount; + volatile int blitter_complete_refcount; + + volatile int endprdmasts_pending; + volatile int softrap_pending; + uint32_t softrap_pending_val; + + pc_timer_t softrap_pending_timer; + + uint64_t blitter_time; + uint64_t status_time; + + int pixel_count, trap_count; + + 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; + + pc_timer_t wake_timer; +} mystique_t; + +static void mystique_start_blit(mystique_t *mystique); +static void mystique_update_irqs(mystique_t *mystique); + +static void wake_fifo_thread(mystique_t *mystique); +static void wait_fifo_idle(mystique_t *mystique); +static void mystique_queue(mystique_t *mystique, uint32_t addr, uint32_t val, uint32_t type); + +static uint8_t mystique_readb_linear(uint32_t addr, void *p); +static uint16_t mystique_readw_linear(uint32_t addr, void *p); +static uint32_t mystique_readl_linear(uint32_t addr, void *p); +static void mystique_writeb_linear(uint32_t addr, uint8_t val, void *p); +static void mystique_writew_linear(uint32_t addr, uint16_t val, void *p); +static void mystique_writel_linear(uint32_t addr, uint32_t val, void *p); + +static const uint8_t trans_masks[16][16] = +{ + { + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1, + 1, 1, 1, 1 + }, + { + 1, 0, 1, 0, + 0, 1, 0, 1, + 1, 0, 1, 0, + 0, 1, 0, 1 + }, + { + 0, 1, 0, 1, + 1, 0, 1, 0, + 0, 1, 0, 1, + 1, 0, 1, 0 + }, + { + 1, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 1, 0, + 0, 0, 0, 0 + }, + { + 0, 1, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 1, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 1, 0 + }, + { + 0, 0, 0, 0, + 0, 1, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 1 + }, + { + 1, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1 + }, + { + 0, 0, 0, 1, + 0, 0, 0, 0, + 0, 1, 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, 0, 0, + 0, 0, 0, 0, + 0, 0, 1, 0 + }, + { + 0, 1, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 0, 0, 1, + 0, 0, 0, 0, + 0, 1, 0, 0 + }, + { + 0, 0, 1, 0, + 0, 0, 0, 0, + 1, 0, 0, 0, + 0, 0, 0, 0 + }, + { + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + } +}; + +static int8_t dither5[256][2][2]; +static int8_t dither6[256][2][2]; + +enum +{ + DMA_STATE_IDLE = 0, + DMA_STATE_PRI, + DMA_STATE_SEC +}; + +#define DMA_POLL_TIME_US 100 /*100us*/ +#define DMA_MAX_WORDS 256 /*256 quad words per 100us poll*/ + +/*These registers are also mirrored into 0x1dxx, with the mirrored versions starting + the blitter*/ +#define REG_DWGCTL 0x1c00 +#define REG_MACCESS 0x1c04 +#define REG_MCTLWTST 0x1c08 +#define REG_ZORG 0x1c0c +#define REG_PAT0 0x1c10 +#define REG_PAT1 0x1c14 +#define REG_PLNWT 0x1c1c +#define REG_BCOL 0x1c20 +#define REG_FCOL 0x1c24 +#define REG_SRC0 0x1c30 +#define REG_SRC1 0x1c34 +#define REG_SRC2 0x1c38 +#define REG_SRC3 0x1c3c +#define REG_XYSTRT 0x1c40 +#define REG_XYEND 0x1c44 +#define REG_SHIFT 0x1c50 +#define REG_DMAPAD 0x1c54 +#define REG_SGN 0x1c58 +#define REG_LEN 0x1c5c +#define REG_AR0 0x1c60 +#define REG_AR1 0x1c64 +#define REG_AR2 0x1c68 +#define REG_AR3 0x1c6c +#define REG_AR4 0x1c70 +#define REG_AR5 0x1c74 +#define REG_AR6 0x1c78 +#define REG_CXBNDRY 0x1c80 +#define REG_FXBNDRY 0x1c84 +#define REG_YDSTLEN 0x1c88 +#define REG_PITCH 0x1c8c +#define REG_YDST 0x1c90 +#define REG_YDSTORG 0x1c94 +#define REG_YTOP 0x1c98 +#define REG_YBOT 0x1c9c +#define REG_CXLEFT 0x1ca0 +#define REG_CXRIGHT 0x1ca4 +#define REG_FXLEFT 0x1ca8 +#define REG_FXRIGHT 0x1cac +#define REG_XDST 0x1cb0 +#define REG_DR0 0x1cc0 +#define REG_DR2 0x1cc8 +#define REG_DR3 0x1ccc +#define REG_DR4 0x1cd0 +#define REG_DR6 0x1cd8 +#define REG_DR7 0x1cdc +#define REG_DR8 0x1ce0 +#define REG_DR10 0x1ce8 +#define REG_DR11 0x1cec +#define REG_DR12 0x1cf0 +#define REG_DR14 0x1cf8 +#define REG_DR15 0x1cfc + +#define REG_FIFOSTATUS 0x1e10 +#define REG_STATUS 0x1e14 +#define REG_ICLEAR 0x1e18 +#define REG_IEN 0x1e1c +#define REG_VCOUNT 0x1e20 +#define REG_DMAMAP 0x1e30 +#define REG_RST 0x1e40 +#define REG_OPMODE 0x1e54 +#define REG_PRIMADDRESS 0x1e58 +#define REG_PRIMEND 0x1e5c +#define REG_DWG_INDIR_WT 0x1e80 + +#define REG_ATTR_IDX 0x1fc0 +#define REG_ATTR_DATA 0x1fc1 +#define REG_INSTS0 0x1fc2 +#define REG_MISC 0x1fc2 +#define REG_SEQ_IDX 0x1fc4 +#define REG_SEQ_DATA 0x1fc5 +#define REG_MISCREAD 0x1fcc +#define REG_GCTL_IDX 0x1fce +#define REG_GCTL_DATA 0x1fcf +#define REG_CRTC_IDX 0x1fd4 +#define REG_CRTC_DATA 0x1fd5 +#define REG_INSTS1 0x1fda +#define REG_CRTCEXT_IDX 0x1fde +#define REG_CRTCEXT_DATA 0x1fdf +#define REG_CACHEFLUSH 0x1fff + +#define REG_TMR0 0x2c00 +#define REG_TMR1 0x2c04 +#define REG_TMR2 0x2c08 +#define REG_TMR3 0x2c0c +#define REG_TMR4 0x2c10 +#define REG_TMR5 0x2c14 +#define REG_TMR6 0x2c18 +#define REG_TMR7 0x2c1c +#define REG_TMR8 0x2c20 +#define REG_TEXORG 0x2c24 +#define REG_TEXWIDTH 0x2c28 +#define REG_TEXHEIGHT 0x2c2c +#define REG_TEXCTL 0x2c30 +#define REG_TEXTRANS 0x2c34 +#define REG_SECADDRESS 0x2c40 +#define REG_SECEND 0x2c44 +#define REG_SOFTRAP 0x2c48 + +#define REG_PALWTADD 0x3c00 +#define REG_PALDATA 0x3c01 +#define REG_PIXRDMSK 0x3c02 +#define REG_PALRDADD 0x3c03 +#define REG_X_DATAREG 0x3c0a +#define REG_CURPOSX 0x3c0c +#define REG_CURPOSY 0x3c0e + +#define REG_STATUS_VSYNCSTS (1 << 3) + +#define CRTCX_R0_STARTADD_MASK (0xf << 0) +#define CRTCX_R0_OFFSET_MASK (3 << 4) + +#define CRTCX_R1_HTOTAL8 (1 << 0) + +#define CRTCX_R2_VTOTAL10 (1 << 0) +#define CRTCX_R2_VTOTAL11 (1 << 1) +#define CRTCX_R2_VDISPEND10 (1 << 2) +#define CRTCX_R2_VBLKSTR10 (1 << 3) +#define CRTCX_R2_VBLKSTR11 (1 << 4) +#define CRTCX_R2_VSYNCSTR10 (1 << 5) +#define CRTCX_R2_VSYNCSTR11 (1 << 6) +#define CRTCX_R2_LINECOMP10 (1 << 7) + +#define CRTCX_R3_MGAMODE (1 << 7) + +#define XREG_XCURADDL 0x04 +#define XREG_XCURADDH 0x05 +#define XREG_XCURCTRL 0x06 + +#define XREG_XCURCOL0R 0x08 +#define XREG_XCURCOL0G 0x09 +#define XREG_XCURCOL0B 0x0a + +#define XREG_XCURCOL1R 0x0c +#define XREG_XCURCOL1G 0x0d +#define XREG_XCURCOL1B 0x0e + +#define XREG_XCURCOL2R 0x10 +#define XREG_XCURCOL2G 0x11 +#define XREG_XCURCOL2B 0x12 + +#define XREG_XVREFCTRL 0x18 +#define XREG_XMULCTRL 0x19 +#define XREG_XPIXCLKCTRL 0x1a +#define XREG_XGENCTRL 0x1d +#define XREG_XMISCCTRL 0x1e + +#define XREG_XGENIOCTRL 0x2a +#define XREG_XGENIODATA 0x2b + +#define XREG_XSYSPLLM 0x2c +#define XREG_XSYSPLLN 0x2d +#define XREG_XSYSPLLP 0x2e +#define XREG_XSYSPLLSTAT 0x2f + +#define XREG_XZOOMCTRL 0x38 + +#define XREG_XSENSETEST 0x3a + +#define XREG_XCRCREML 0x3c +#define XREG_XCRCREMH 0x3d +#define XREG_XCRCBITSEL 0x3e + +#define XREG_XCOLKEYMSKL 0x40 +#define XREG_XCOLKEYMSKH 0x41 +#define XREG_XCOLKEYL 0x42 +#define XREG_XCOLKEYH 0x43 + +#define XREG_XPIXPLLCM 0x4c +#define XREG_XPIXPLLCN 0x4d +#define XREG_XPIXPLLCP 0x4e +#define XREG_XPIXPLLSTAT 0x4f + +#define XMISCCTRL_VGA8DAC (1 << 3) + +#define XMULCTRL_DEPTH_MASK (7 << 0) +#define XMULCTRL_DEPTH_8 (0 << 0) +#define XMULCTRL_DEPTH_15 (1 << 0) +#define XMULCTRL_DEPTH_16 (2 << 0) +#define XMULCTRL_DEPTH_24 (3 << 0) +#define XMULCTRL_DEPTH_32_OVERLAYED (4 << 0) +#define XMULCTRL_DEPTH_2G8V16 (5 << 0) +#define XMULCTRL_DEPTH_G16V16 (6 << 0) +#define XMULCTRL_DEPTH_32 (7 << 0) + +#define XSYSPLLSTAT_SYSLOCK (1 << 6) + +#define XPIXPLLSTAT_SYSLOCK (1 << 6) + +#define XCURCTRL_CURMODE_MASK (3 << 0) +#define XCURCTRL_CURMODE_3COL (1 << 0) +#define XCURCTRL_CURMODE_XGA (2 << 0) +#define XCURCTRL_CURMODE_XWIN (3 << 0) + +#define DWGCTRL_OPCODE_MASK (0xf << 0) +#define DWGCTRL_OPCODE_LINE_OPEN (0x0 << 0) +#define DWGCTRL_OPCODE_AUTOLINE_OPEN (0x1 << 0) +#define DWGCTRL_OPCODE_AUTOLINE_CLOSE (0x3 << 0) +#define DWGCTRL_OPCODE_TRAP (0x4 << 0) +#define DWGCTRL_OPCODE_TEXTURE_TRAP (0x6 << 0) +#define DWGCTRL_OPCODE_ILOAD_HIGH (0x7 << 0) +#define DWGCTRL_OPCODE_BITBLT (0x8 << 0) +#define DWGCTRL_OPCODE_ILOAD (0x9 << 0) +#define DWGCTRL_OPCODE_IDUMP (0xa << 0) +#define DWGCTRL_OPCODE_ILOAD_SCALE (0xd << 0) +#define DWGCTRL_OPCODE_ILOAD_HIGHV (0xe << 0) +#define DWGCTRL_ATYPE_MASK (7 << 4) +#define DWGCTRL_ATYPE_RPL (0 << 4) +#define DWGCTRL_ATYPE_RSTR (1 << 4) +#define DWGCTRL_ATYPE_ZI (3 << 4) +#define DWGCTRL_ATYPE_BLK (4 << 4) +#define DWGCTRL_ATYPE_I (7 << 4) +#define DWGCTRL_LINEAR (1 << 7) +#define DWGCTRL_ZMODE_MASK (7 << 8) +#define DWGCTRL_ZMODE_NOZCMP (0 << 8) +#define DWGCTRL_ZMODE_ZE (2 << 8) +#define DWGCTRL_ZMODE_ZNE (3 << 8) +#define DWGCTRL_ZMODE_ZLT (4 << 8) +#define DWGCTRL_ZMODE_ZLTE (5 << 8) +#define DWGCTRL_ZMODE_ZGT (6 << 8) +#define DWGCTRL_ZMODE_ZGTE (7 << 8) +#define DWGCTRL_SOLID (1 << 11) +#define DWGCTRL_ARZERO (1 << 12) +#define DWGCTRL_SGNZERO (1 << 13) +#define DWGCTRL_SHTZERO (1 << 14) +#define DWGCTRL_BOP_MASK (0xf << 16) +#define DWGCTRL_TRANS_SHIFT (20) +#define DWGCTRL_TRANS_MASK (0xf << DWGCTRL_TRANS_SHIFT) +#define DWGCTRL_BLTMOD_MASK (0xf << 25) +#define DWGCTRL_BLTMOD_BMONOLEF (0x0 << 25) +#define DWGCTRL_BLTMOD_BFCOL (0x2 << 25) +#define DWGCTRL_BLTMOD_BMONOWF (0x4 << 25) +#define DWGCTRL_BLTMOD_BU32RGB (0x7 << 25) +#define DWGCTRL_BLTMOD_BUYUV (0xe << 25) +#define DWGCTRL_BLTMOD_BU24RGB (0xf << 25) +#define DWGCTRL_PATTERN (1 << 29) +#define DWGCTRL_TRANSC (1 << 30) +#define BOP(x) ((x) << 16) + +#define MACCESS_PWIDTH_MASK (3 << 0) +#define MACCESS_PWIDTH_8 (0 << 0) +#define MACCESS_PWIDTH_16 (1 << 0) +#define MACCESS_PWIDTH_32 (2 << 0) +#define MACCESS_PWIDTH_24 (3 << 0) +#define MACCESS_TLUTLOAD (1 << 29) +#define MACCESS_NODITHER (1 << 30) +#define MACCESS_DIT555 (1 << 31) + +#define PITCH_MASK 0x7e0 +#define PITCH_YLIN (1 << 15) + +#define SGN_SDYDXL (1 << 0) +#define SGN_SCANLEFT (1 << 0) +#define SGN_SDXL (1 << 1) +#define SGN_SDY (1 << 2) +#define SGN_SDXR (1 << 5) + +#define DMA_ADDR_MASK 0xfffffffc +#define DMA_MODE_MASK 3 + +#define DMA_MODE_REG 0 +#define DMA_MODE_BLIT 1 +#define DMA_MODE_VECTOR 2 + +#define STATUS_SOFTRAPEN (1 << 0) +#define STATUS_VSYNCPEN (1 << 4) +#define STATUS_VLINEPEN (1 << 5) +#define STATUS_DWGENGSTS (1 << 16) +#define STATUS_ENDPRDMASTS (1 << 17) + +#define ICLEAR_SOFTRAPICLR (1 << 0) +#define ICLEAR_VLINEICLR (1 << 5) + +#define IEN_SOFTRAPEN (1 << 0) + +#define TEXCTL_TEXFORMAT_MASK (7 << 0) +#define TEXCTL_TEXFORMAT_TW4 (0 << 0) +#define TEXCTL_TEXFORMAT_TW8 (1 << 0) +#define TEXCTL_TEXFORMAT_TW15 (2 << 0) +#define TEXCTL_TEXFORMAT_TW16 (3 << 0) +#define TEXCTL_TEXFORMAT_TW12 (4 << 0) +#define TEXCTL_PALSEL_MASK (0xf << 4) +#define TEXCTL_TPITCH_SHIFT (16) +#define TEXCTL_TPITCH_MASK (7 << TEXCTL_TPITCH_SHIFT) +#define TEXCTL_NPCEN (1 << 21) +#define TEXCTL_DECALCKEY (1 << 24) +#define TEXCTL_TAKEY (1 << 25) +#define TEXCTL_TAMASK (1 << 26) +#define TEXCTL_CLAMPV (1 << 27) +#define TEXCTL_CLAMPU (1 << 28) +#define TEXCTL_TMODULATE (1 << 29) +#define TEXCTL_STRANS (1 << 30) +#define TEXCTL_ITRANS (1 << 31) + +#define TEXHEIGHT_TH_MASK (0x3f << 0) +#define TEXHEIGHT_THMASK_SHIFT (18) +#define TEXHEIGHT_THMASK_MASK (0x7ff << TEXHEIGHT_THMASK_SHIFT) + +#define TEXWIDTH_TW_MASK (0x3f << 0) +#define TEXWIDTH_TWMASK_SHIFT (18) +#define TEXWIDTH_TWMASK_MASK (0x7ff << TEXWIDTH_TWMASK_SHIFT) + +#define TEXTRANS_TCKEY_MASK (0xffff) +#define TEXTRANS_TKMASK_SHIFT (16) +#define TEXTRANS_TKMASK_MASK (0xffff << TEXTRANS_TKMASK_SHIFT) + +#define DITHER_565 0 +#define DITHER_NONE_565 1 +#define DITHER_555 2 +#define DITHER_NONE_555 3 + +static void mystique_recalc_mapping(mystique_t *mystique); +static int mystique_line_compare(svga_t *svga); + +static uint8_t mystique_iload_read_b(uint32_t addr, void *p); +static uint32_t mystique_iload_read_l(uint32_t addr, void *p); +static void mystique_iload_write_b(uint32_t addr, uint8_t val, void *p); +static void mystique_iload_write_l(uint32_t addr, uint32_t val, void *p); + +static uint32_t blit_idump_read(mystique_t *mystique); +static void blit_iload_write(mystique_t *mystique, uint32_t data, int size); + +void mystique_out(uint16_t addr, uint8_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + svga_t *svga = &mystique->svga; + uint8_t old; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; // mono / color addr selection + +// pclog("mystique_out : %04X %02X\n", addr, val); +// pclog(" %04X:%04X\n", CS,cpu_state.pc); + switch (addr) + { + case 0x3c8: + mystique->xreg_idx = val; + break; + + case 0x3cf: + if ((svga->gdcaddr & 15) == 6 && svga->gdcreg[6] != val) + { + svga->gdcreg[svga->gdcaddr & 15] = val; + mystique_recalc_mapping(mystique); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: +// if (svga->crtcreg == 0xc) +// pclog("Buffer swap\n"); + if (((svga->crtcreg & 0x3f) < 7) && (svga->crtc[0x11] & 0x80)) + return; + if (((svga->crtcreg & 0x3f) == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg & 0x3f]; + svga->crtc[svga->crtcreg & 0x3f] = val; + if (old != val) + { + if ((svga->crtcreg & 0x3f) < 0xE || (svga->crtcreg & 0x3f) > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + if (svga->crtcreg == 0x11) + { + if (!(val & 0x10)) + mystique->status &= ~STATUS_VSYNCPEN; + mystique_update_irqs(mystique); + } + } + break; + + case 0x3de: + mystique->crtcext_idx = val; + break; + case 0x3df: + if (mystique->crtcext_idx < 6) + mystique->crtcext_regs[mystique->crtcext_idx] = val; + if (mystique->crtcext_idx < 4) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + if (mystique->crtcext_idx == 3) + { + if (val & CRTCX_R3_MGAMODE) + svga->fb_only = 1; + else + svga->fb_only = 0; + svga_recalctimings(svga); + +// pclog("Write CRTCX[3]=%02x\n", val); + } + if (mystique->crtcext_idx == 4) + { + if (svga->gdcreg[6] & 0xc) + { + /*64k banks*/ + svga->read_bank = (val & 0x7f) << 16; + svga->write_bank = (val & 0x7f) << 16; + } + else + { + /*128k banks*/ + svga->read_bank = (val & 0x7e) << 16; + svga->write_bank = (val & 0x7e) << 16; + } +// pclog("Write CRTCX[4]=%02x %08x\n", val, svga->read_bank); + } + break; + + } + svga_out(addr, val, svga); +} + +uint8_t mystique_in(uint16_t addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + svga_t *svga = &mystique->svga; + uint8_t temp = 0xff; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; // mono / color addr selection + +// if (addr != 0x3da && addr != 0x3ba) pclog("mystique_in : %04X ", addr); + + switch (addr) + { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg & 0x3f]; + break; + + case 0x3df: + if (mystique->crtcext_idx < 6) + temp = mystique->crtcext_regs[mystique->crtcext_idx]; + break; + + default: + temp = svga_in(addr, svga); + break; + } + +// if (addr != 0x3da && addr != 0x3ba) pclog("%02X\n", temp); + return temp; +} + +static int mystique_line_compare(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *)svga->p; + + mystique->status |= STATUS_VLINEPEN; + mystique_update_irqs(mystique); + + return 0; +} + +static void mystique_vsync_callback(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *)svga->p; + + if (svga->crtc[0x11] & 0x10) + { + mystique->status |= STATUS_VSYNCPEN; + mystique_update_irqs(mystique); + } + +} + +void mystique_recalctimings(svga_t *svga) +{ + mystique_t *mystique = (mystique_t *)svga->p; + int clk_sel = (svga->miscout >> 2) & 3; + + if (clk_sel & 2) + { + int m = mystique->xpixpll[2].m; + int n = mystique->xpixpll[2].n; + int p = mystique->xpixpll[2].p; + + double fvco = 14318181.0 * (n + 1) / (m + 1); + double fo = fvco / (p + 1); + +// pclog("m=%i n=%i p=%i fo=%g\n", m, n, p, fo); + svga->clock = (cpuclock * (float)(1ull << 32)) / fo; + } + + if (mystique->crtcext_regs[1] & CRTCX_R1_HTOTAL8) + svga->htotal += 0x100; + if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL10) + svga->vtotal += 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VTOTAL11) + svga->vtotal += 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_VDISPEND10) + svga->dispend += 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VBLKSTR10) + svga->vblankstart += 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VBLKSTR11) + svga->vblankstart += 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_VSYNCSTR10) + svga->vsyncstart += 0x400; + if (mystique->crtcext_regs[2] & CRTCX_R2_VSYNCSTR11) + svga->vsyncstart += 0x800; + if (mystique->crtcext_regs[2] & CRTCX_R2_LINECOMP10) + svga->split += 0x400; +// pclog("svga->split=%i\n", svga->split); + + if (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) + { + int row_offset = svga->crtc[0x13] | ((mystique->crtcext_regs[0] & CRTCX_R0_OFFSET_MASK) << 4); + +// svga->split = 99999; + svga->lowres = 0; + svga->char_width = 8; + svga->hdisp = (svga->crtc[1] + 1) * 8; + svga->hdisp_time = svga->hdisp; + svga->rowoffset = row_offset * 2; + svga->ma_latch = ((mystique->crtcext_regs[0] & CRTCX_R0_STARTADD_MASK) << 17) | + (svga->crtc[0xc] << 9) | (svga->crtc[0xd] << 1); + + /*Mystique, unlike most SVGA cards, allows display start to take + effect mid-screen*/ + if (svga->ma_latch != mystique->ma_latch_old) + { +// pclog("ma_latch change: old=%08x new=%08x ma=%08x ", mystique->ma_latch_old, svga->ma_latch, svga->maback); + svga->ma = svga->maback = (svga->maback - (mystique->ma_latch_old << 2)) + (svga->ma_latch << 2); +// pclog("ma_new=%08x\n", svga->maback); + mystique->ma_latch_old = svga->ma_latch; + } + + switch (mystique->xmulctrl & XMULCTRL_DEPTH_MASK) + { + case XMULCTRL_DEPTH_8: + case XMULCTRL_DEPTH_2G8V16: + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + break; + case XMULCTRL_DEPTH_15: + case XMULCTRL_DEPTH_G16V16: + svga->render = svga_render_15bpp_highres; + svga->bpp = 15; + break; + case XMULCTRL_DEPTH_16: + svga->render = svga_render_16bpp_highres; + svga->bpp = 15; + break; + case XMULCTRL_DEPTH_24: + svga->render = svga_render_24bpp_highres; + svga->bpp = 24; + break; + case XMULCTRL_DEPTH_32: + case XMULCTRL_DEPTH_32_OVERLAYED: + svga->render = svga_render_32bpp_highres; + svga->bpp = 32; + break; + } + + svga->line_compare = mystique_line_compare; +// pclog("recalc: htotal=%i vtotal=%i dispend=%i\n", svga->htotal, svga->vtotal, svga->dispend); + + mem_mapping_set_handler(&mystique->lfb_mapping, + mystique_readb_linear, mystique_readw_linear, mystique_readl_linear, + mystique_writeb_linear, mystique_writew_linear, mystique_writel_linear); + } + else + { + svga->line_compare = NULL; + svga->bpp = 8; + + mem_mapping_set_handler(&mystique->lfb_mapping, + svga_read_linear, svga_readw_linear, svga_readl_linear, + svga_write_linear, svga_writew_linear, svga_writel_linear); + } +} + +static void mystique_recalc_mapping(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + + io_removehandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + if ((mystique->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && (mystique->pci_regs[0x41] & 1)) + io_sethandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + + if (!(mystique->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&mystique->ctrl_mapping); + mem_mapping_disable(&mystique->lfb_mapping); + mem_mapping_disable(&mystique->iload_mapping); + return; + } + + if (mystique->ctrl_base) + mem_mapping_set_addr(&mystique->ctrl_mapping, mystique->ctrl_base, 0x4000); + else + mem_mapping_disable(&mystique->ctrl_mapping); + if (mystique->lfb_base) + mem_mapping_set_addr(&mystique->lfb_mapping, mystique->lfb_base, 0x800000); + else + mem_mapping_disable(&mystique->lfb_mapping); + if (mystique->iload_base) + mem_mapping_set_addr(&mystique->iload_mapping, mystique->iload_base, 0x800000); + else + mem_mapping_disable(&mystique->iload_mapping); + + if (mystique->pci_regs[0x41] & 1) + { + switch (svga->gdcreg[6] & 0x0C) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + 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; + } + if (svga->gdcreg[6] & 0xc) + { + /*64k banks*/ + svga->read_bank = (mystique->crtcext_regs[4] & 0x7f) << 16; + svga->write_bank = (mystique->crtcext_regs[4] & 0x7f) << 16; + } + else + { + /*128k banks*/ + svga->read_bank = (mystique->crtcext_regs[4] & 0x7e) << 16; + svga->write_bank = (mystique->crtcext_regs[4] & 0x7e) << 16; + } + } + else + mem_mapping_disable(&svga->mapping); +} + +static void mystique_update_irqs(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + int irq = 0; + + if ((mystique->status & mystique->ien) & STATUS_SOFTRAPEN) + irq = 1; + if ((mystique->status & STATUS_VSYNCPEN) && (svga->crtc[0x11] & 0x30) == 0x10) + irq = 1; + + if (irq) + pci_set_irq(mystique->card, PCI_INTA); + else + pci_clear_irq(mystique->card, PCI_INTA); +} + +#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 uint8_t mystique_read_xreg(mystique_t *mystique, int reg) +{ + uint8_t ret = 0xff; + + switch (reg) + { + case XREG_XCURADDL: + ret = mystique->cursor.addr & 0xff; + break; + case XREG_XCURADDH: + ret = mystique->cursor.addr >> 8; + break; + case XREG_XCURCTRL: + ret = mystique->xcurctrl; + break; + + case XREG_XCURCOL0R: case XREG_XCURCOL0G: case XREG_XCURCOL0B: + READ8(reg, mystique->cursor.col[0]); + break; + case XREG_XCURCOL1R: case XREG_XCURCOL1G: case XREG_XCURCOL1B: + READ8(reg, mystique->cursor.col[1]); + break; + case XREG_XCURCOL2R: case XREG_XCURCOL2G: case XREG_XCURCOL2B: + READ8(reg, mystique->cursor.col[2]); + break; + + case XREG_XMULCTRL: + ret = mystique->xmulctrl; + break; + + case XREG_XMISCCTRL: + ret = mystique->xmiscctrl; + break; + + case XREG_XGENCTRL: + ret = mystique->xgenctrl; + break; + + case XREG_XVREFCTRL: + ret = mystique->xvrefctrl; + break; + + case XREG_XGENIOCTRL: + ret = mystique->xgenioctrl; + break; + case XREG_XGENIODATA: + ret = mystique->xgeniodata; + break; + + case XREG_XSYSPLLM: + ret = mystique->xsyspllm; + break; + case XREG_XSYSPLLN: + ret = mystique->xsysplln; + break; + case XREG_XSYSPLLP: + ret = mystique->xsyspllp; + break; + + case XREG_XZOOMCTRL: + ret = mystique->xzoomctrl; + break; + + case XREG_XSENSETEST: + ret = 0; + if (mystique->svga.vgapal[0].b < 0x80) + ret |= 1; + if (mystique->svga.vgapal[0].g < 0x80) + ret |= 2; + if (mystique->svga.vgapal[0].r < 0x80) + ret |= 4; + break; + + case XREG_XCRCREML: /*CRC not implemented*/ + ret = 0; + break; + case XREG_XCRCREMH: + ret = 0; + break; + case XREG_XCRCBITSEL: + ret = mystique->xcrcbitsel; + break; + + case XREG_XCOLKEYMSKL: + ret = mystique->xcolkeymskl; + break; + case XREG_XCOLKEYMSKH: + ret = mystique->xcolkeymskh; + break; + case XREG_XCOLKEYL: + ret = mystique->xcolkeyl; + break; + case XREG_XCOLKEYH: + ret = mystique->xcolkeyh; + break; + + case XREG_XPIXCLKCTRL: + ret = mystique->xpixclkctrl; + break; + + case XREG_XSYSPLLSTAT: + ret = XSYSPLLSTAT_SYSLOCK; + break; + + case XREG_XPIXPLLSTAT: + ret = XPIXPLLSTAT_SYSLOCK; + break; + + case XREG_XPIXPLLCM: + ret = mystique->xpixpll[2].m; + break; + case XREG_XPIXPLLCN: + ret = mystique->xpixpll[2].n; + break; + case XREG_XPIXPLLCP: + ret = mystique->xpixpll[2].p | (mystique->xpixpll[2].s << 3); + break; + + case 0x00: case 0x20: case 0x3f: + ret = 0xff; + break; + + default: + if (reg >= 0x50) + ret = 0xff; + else + fatal("Read XREG %02x\n", reg); + break; + } + return ret; +} + +static void mystique_write_xreg(mystique_t *mystique, int reg, uint8_t val) +{ + svga_t *svga = &mystique->svga; + + switch (reg) + { + case XREG_XCURADDL: + mystique->cursor.addr = (mystique->cursor.addr & 0x1f00) | val; + svga->hwcursor.addr = mystique->cursor.addr << 10; + break; + case XREG_XCURADDH: + mystique->cursor.addr = (mystique->cursor.addr & 0x00ff) | ((val & 0x1f) << 8); + svga->hwcursor.addr = mystique->cursor.addr << 10; + break; + + case XREG_XCURCTRL: + mystique->xcurctrl = val; + svga->hwcursor.ena = (val & 3) ? 1 : 0; + break; + + case XREG_XCURCOL0R: case XREG_XCURCOL0G: case XREG_XCURCOL0B: + WRITE8(reg, mystique->cursor.col[0], val); + break; + case XREG_XCURCOL1R: case XREG_XCURCOL1G: case XREG_XCURCOL1B: + WRITE8(reg, mystique->cursor.col[1], val); + break; + case XREG_XCURCOL2R: case XREG_XCURCOL2G: case XREG_XCURCOL2B: + WRITE8(reg, mystique->cursor.col[2], val); + break; + + case XREG_XMULCTRL: + mystique->xmulctrl = val; + break; + + case XREG_XMISCCTRL: + mystique->xmiscctrl = val; + svga_set_ramdac_type(svga, (val & XMISCCTRL_VGA8DAC) ? RAMDAC_8BIT : RAMDAC_6BIT); + break; + + case XREG_XGENCTRL: + mystique->xgenctrl = val; + break; + + case XREG_XVREFCTRL: + mystique->xvrefctrl = val; + break; + + case XREG_XGENIOCTRL: + mystique->xgenioctrl = val; + break; + case XREG_XGENIODATA: + mystique->xgeniodata = val; + break; + + case XREG_XSYSPLLM: + mystique->xsyspllm = val; + break; + case XREG_XSYSPLLN: + mystique->xsysplln = val; + break; + case XREG_XSYSPLLP: + mystique->xsyspllp = val; + break; + + case XREG_XZOOMCTRL: + mystique->xzoomctrl = val & 3; + break; + + case XREG_XSENSETEST: + break; + + case XREG_XCRCREML: /*CRC not implemented*/ + break; + case XREG_XCRCREMH: + break; + case XREG_XCRCBITSEL: + mystique->xcrcbitsel = val & 0x1f; + break; + + case XREG_XCOLKEYMSKL: + mystique->xcolkeymskl = val; + break; + case XREG_XCOLKEYMSKH: + mystique->xcolkeymskh = val; + break; + case XREG_XCOLKEYL: + mystique->xcolkeyl = val; + break; + case XREG_XCOLKEYH: + mystique->xcolkeyh = val; + break; + + case XREG_XSYSPLLSTAT: + break; + + case XREG_XPIXPLLSTAT: + break; + + case XREG_XPIXCLKCTRL: + mystique->xpixclkctrl = val; + break; + + case XREG_XPIXPLLCM: + mystique->xpixpll[2].m = val; + break; + case XREG_XPIXPLLCN: + mystique->xpixpll[2].n = val; + break; + case XREG_XPIXPLLCP: + mystique->xpixpll[2].p = val & 7; + mystique->xpixpll[2].s = (val >> 3) & 3; + break; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x07: case 0x0b: case 0x0f: + case 0x13: case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1b: case 0x1c: case 0x20: case 0x39: case 0x3b: case 0x3f: + case 0x47: case 0x4b: + break; + + default: + if (reg < 0x50) + fatal("Write XREG %02x %02x\n", reg, val); + break; + } +} + +static uint8_t mystique_ctrl_read_b(uint32_t addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + svga_t *svga = &mystique->svga; + uint8_t ret = 0xff; + int fifocount; + +// pclog("mystique read %04x %08x\n", addr & 0x3fff, cpu_state.pc); + + switch (addr & 0x3fff) + { + case REG_FIFOSTATUS: + fifocount = FIFO_SIZE - FIFO_ENTRIES; + if (fifocount > 64) + fifocount = 64; + ret = fifocount; + break; + case REG_FIFOSTATUS+1: + if (FIFO_EMPTY) + ret |= 2; + else if (FIFO_ENTRIES >= 64) + ret |= 1; +// ret = 2; /*Empty*/ + break; + case REG_FIFOSTATUS+2: case REG_FIFOSTATUS+3: + ret = 0; + break; + + case REG_STATUS: + ret = mystique->status & 0xff; + if (svga->cgastat & 8) + ret |= REG_STATUS_VSYNCSTS; +// pclog("REG_STATUS %02x\n", ret); + break; + case REG_STATUS+1: + ret = (mystique->status >> 8) & 0xff; + break; + case REG_STATUS+2: + ret = (mystique->status >> 16) & 0xff; + if (mystique->busy || + ((mystique->blitter_submit_refcount + mystique->blitter_submit_dma_refcount) != mystique->blitter_complete_refcount) || + !FIFO_EMPTY) + ret |= (STATUS_DWGENGSTS >> 16); +/* thread_lock_mutex(mystique->dma.lock); + if (mystique->dma.state == DMA_STATE_IDLE) + ret |= (STATUS_ENDPRDMASTS >> 16); + thread_unlock_mutex(mystique->dma.lock);*/ +/* pclog("Read status %02x %i %i %i fifo=%i\n", ret, mystique->busy, + ((mystique->blitter_submit_refcount + mystique->blitter_submit_dma_refcount) != mystique->blitter_complete_refcount), + !FIFO_EMPTY, FIFO_ENTRIES);*/ +// ret |= 2; + break; + case REG_STATUS+3: + ret = (mystique->status >> 24) & 0xff; + break; + + case REG_IEN: + ret = mystique->ien & 0x64; + break; + case REG_IEN+1: case REG_IEN+2: case REG_IEN+3: + ret = 0; + break; + + case REG_OPMODE: + ret = mystique->dmamod << 2; + break; + case REG_OPMODE+1: + ret = mystique->dmadatasiz; + break; + case REG_OPMODE+2: + ret = mystique->dirdatasiz; + break; + case REG_OPMODE+3: + break; + + case REG_PRIMADDRESS: case REG_PRIMADDRESS+1: case REG_PRIMADDRESS+2: case REG_PRIMADDRESS+3: + READ8(addr, mystique->dma.primaddress); + break; + case REG_PRIMEND: case REG_PRIMEND+1: case REG_PRIMEND+2: case REG_PRIMEND+3: + READ8(addr, mystique->dma.primend); + break; + + case REG_SECADDRESS: case REG_SECADDRESS+1: case REG_SECADDRESS+2: case REG_SECADDRESS+3: + READ8(addr, mystique->dma.secaddress); + break; + + case REG_VCOUNT: case REG_VCOUNT+1: case REG_VCOUNT+2: case REG_VCOUNT+3: + READ8(addr, svga->vc); + break; + + case REG_ATTR_IDX: + ret = svga_in(0x3c0, svga); + break; + case REG_ATTR_DATA: + ret = svga_in(0x3c1, svga); + break; + + case REG_INSTS0: + ret = svga_in(0x3c2, svga); + break; + + case REG_SEQ_IDX: + ret = svga_in(0x3c4, svga); + break; + case REG_SEQ_DATA: + ret = svga_in(0x3c5, svga); + break; + + case REG_MISCREAD: + ret = svga_in(0x3cc, svga); + break; + + case REG_GCTL_IDX: + ret = mystique_in(0x3ce, mystique); + break; + case REG_GCTL_DATA: + ret = mystique_in(0x3cf, mystique); + break; + + case REG_CRTC_IDX: + ret = mystique_in(0x3d4, mystique); + break; + case REG_CRTC_DATA: + ret = mystique_in(0x3d5, mystique); + break; + + case REG_INSTS1: + ret = mystique_in(0x3da, mystique); + break; + + case REG_CRTCEXT_IDX: + ret = mystique_in(0x3de, mystique); + break; + case REG_CRTCEXT_DATA: + ret = mystique_in(0x3df, mystique); + break; + + case REG_PALWTADD: + ret = svga_in(0x3c8, svga); + break; + case REG_PALDATA: + ret = svga_in(0x3c9, svga); + break; + case REG_PIXRDMSK: + ret = svga_in(0x3c6, svga); + break; + case REG_PALRDADD: + ret = svga_in(0x3c7, svga); + break; + + case REG_X_DATAREG: + ret = mystique_read_xreg(mystique, mystique->xreg_idx); + break; + + case 0x1e50: case 0x1e51: case 0x1e52: case 0x1e53: + case REG_ICLEAR: case REG_ICLEAR+1: case REG_ICLEAR+2: case REG_ICLEAR+3: + case 0x2c30: case 0x2c31: case 0x2c32: case 0x2c33: + case 0x3e08: + break; + + case 0x3c08: case 0x3c09: case 0x3c0b: + break; + + default: + if ((addr & 0x3fff) >= 0x2c00 && (addr & 0x3fff) < 0x2c40) + break; + if ((addr & 0x3fff) >= 0x3e00) + break; + fatal("Read MGA control %08x\n", addr & 0x3fff); + } + +// pclog("mcrb: addr=%08x ret=%02x\n", addr, ret); + return ret; +} + +static void mystique_accel_ctrl_write_b(uint32_t addr, uint8_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + int start_blit = 0; + int x; + +// pclog("mystique accel addr=%04x val=%02x\n", addr & 0x3fff, val); + + if ((addr & 0x300) == 0x100) + { + addr &= ~0x100; + start_blit = 1; + } + + switch (addr & 0x3fff) + { + case REG_MACCESS: case REG_MACCESS+1: case REG_MACCESS+2: case REG_MACCESS+3: + WRITE8(addr, mystique->maccess, val); + mystique->dwgreg.dither = mystique->maccess >> 30; + break; + + case REG_MCTLWTST: case REG_MCTLWTST+1: case REG_MCTLWTST+2: case REG_MCTLWTST+3: + WRITE8(addr, mystique->mctlwtst, val); + break; + + + case REG_PAT0: case REG_PAT0+1: case REG_PAT0+2: case REG_PAT0+3: + case REG_PAT1: case REG_PAT1+1: case REG_PAT1+2: case REG_PAT1+3: + for (x = 0; x < 8; x++) + mystique->dwgreg.pattern[addr & 7][x] = val & (1 << (7-x)); + break; + + case REG_XYSTRT: case REG_XYSTRT+1: + WRITE8(addr&1, mystique->dwgreg.ar[5], val); + if (mystique->dwgreg.ar[5] & 0x8000) + mystique->dwgreg.ar[5] |= 0xffff8000; + else + mystique->dwgreg.ar[5] &= ~0xffff8000; + WRITE8(addr&1, mystique->dwgreg.xdst, val); + break; + case REG_XYSTRT+2: case REG_XYSTRT+3: + WRITE8(addr & 1, mystique->dwgreg.ar[6], val); + if (mystique->dwgreg.ar[6] & 0x8000) + mystique->dwgreg.ar[6] |= 0xffff8000; + else + mystique->dwgreg.ar[6] &= ~0xffff8000; + WRITE8(addr & 1, mystique->dwgreg.ydst, val); + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + break; + + case REG_XYEND: case REG_XYEND+1: + WRITE8(addr&1, mystique->dwgreg.ar[0], val); + if (mystique->dwgreg.ar[0] & 0x8000) + mystique->dwgreg.ar[0] |= 0xffff8000; + else + mystique->dwgreg.ar[0] &= ~0xffff8000; +// pclog("XYEND AR[0]=%08x\n", mystique->dwgreg.ar[0]); + break; + case REG_XYEND+2: case REG_XYEND+3: + WRITE8(addr & 1, mystique->dwgreg.ar[2], val); + if (mystique->dwgreg.ar[2] & 0x8000) + mystique->dwgreg.ar[2] |= 0xffff8000; + else + mystique->dwgreg.ar[2] &= ~0xffff8000; + break; + + + case REG_SGN: + mystique->dwgreg.sgn.sdydxl = val & SGN_SDYDXL; + mystique->dwgreg.sgn.scanleft = val & SGN_SCANLEFT; + mystique->dwgreg.sgn.sdxl = val & SGN_SDXL; + mystique->dwgreg.sgn.sdy = val & SGN_SDY; + mystique->dwgreg.sgn.sdxr = val & SGN_SDXR; + break; + case REG_SGN+1: case REG_SGN+2: case REG_SGN+3: + break; + + + case REG_LEN: case REG_LEN+1: + WRITE8(addr, mystique->dwgreg.length, val); + break; + case REG_LEN+2: + break; + case REG_LEN+3: + mystique->dwgreg.beta = val >> 4; + if (!mystique->dwgreg.beta) + mystique->dwgreg.beta = 16; + break; + + case REG_CXBNDRY: case REG_CXBNDRY+1: + WRITE8(addr, mystique->dwgreg.cxleft, val); + break; + case REG_CXBNDRY+2: case REG_CXBNDRY+3: + WRITE8(addr & 1, mystique->dwgreg.cxright, val); + break; + case REG_FXBNDRY: case REG_FXBNDRY+1: + WRITE8(addr, mystique->dwgreg.fxleft, val); + break; + case REG_FXBNDRY+2: case REG_FXBNDRY+3: + WRITE8(addr & 1, mystique->dwgreg.fxright, val); + break; + + case REG_YDSTLEN: case REG_YDSTLEN+1: + WRITE8(addr, mystique->dwgreg.length, val); +// pclog("Write YDSTLEN+%i %i\n", addr&1, mystique->dwgreg.length); + break; + case REG_YDSTLEN+2: + mystique->dwgreg.ydst = (mystique->dwgreg.ydst & ~0xff) | val; + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else + { + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val & 7; + } +// pclog("Write YDSTLEN+2 %i %08x\n", mystique->dwgreg.ydst, mystique->dwgreg.ydst_lin); + break; + case REG_YDSTLEN+3: + mystique->dwgreg.ydst = (mystique->dwgreg.ydst & 0xff) | (((int32_t)(int8_t)val) << 8); + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; +// pclog("Write YDSTLEN+3 %i %08x\n", mystique->dwgreg.ydst, mystique->dwgreg.ydst_lin); + break; + + + case REG_XDST: case REG_XDST+1: + WRITE8(addr & 1, mystique->dwgreg.xdst, val); + break; + case REG_XDST+2: case REG_XDST+3: + break; + + + case REG_YDSTORG: case REG_YDSTORG+1: case REG_YDSTORG+2: case REG_YDSTORG+3: + WRITE8(addr, mystique->dwgreg.ydstorg, val); + mystique->dwgreg.z_base = mystique->dwgreg.ydstorg*2 + mystique->dwgreg.zorg; +// pclog("ydstorg=%06x z_base=%06x\n", mystique->dwgreg.ydstorg, mystique->dwgreg.z_base); + break; + case REG_YTOP: case REG_YTOP+1: case REG_YTOP+2: case REG_YTOP+3: + WRITE8(addr, mystique->dwgreg.ytop, val); + break; + case REG_YBOT: case REG_YBOT+1: case REG_YBOT+2: case REG_YBOT+3: + WRITE8(addr, mystique->dwgreg.ybot, val); + break; + + case REG_CXLEFT: case REG_CXLEFT+1: + WRITE8(addr, mystique->dwgreg.cxleft, val); + break; + case REG_CXLEFT+2: case REG_CXLEFT+3: + break; + case REG_CXRIGHT: case REG_CXRIGHT+1: + WRITE8(addr, mystique->dwgreg.cxright, val); + break; + case REG_CXRIGHT+2: case REG_CXRIGHT+3: + break; + + case REG_FXLEFT: case REG_FXLEFT+1: + WRITE8(addr, mystique->dwgreg.fxleft, val); + break; + case REG_FXLEFT+2: case REG_FXLEFT+3: + break; + case REG_FXRIGHT: case REG_FXRIGHT+1: + WRITE8(addr, mystique->dwgreg.fxright, val); + break; + case REG_FXRIGHT+2: case REG_FXRIGHT+3: + break; + + + case REG_SECADDRESS: case REG_SECADDRESS+1: case REG_SECADDRESS+2: case REG_SECADDRESS+3: + WRITE8(addr, mystique->dma.secaddress, val); + mystique->dma.sec_state = 0; + break; + + + case REG_TMR0: case REG_TMR0+1: case REG_TMR0+2: case REG_TMR0+3: + WRITE8(addr, mystique->dwgreg.tmr[0], val); + break; + case REG_TMR1: case REG_TMR1+1: case REG_TMR1+2: case REG_TMR1+3: + WRITE8(addr, mystique->dwgreg.tmr[1], val); + break; + case REG_TMR2: case REG_TMR2+1: case REG_TMR2+2: case REG_TMR2+3: + WRITE8(addr, mystique->dwgreg.tmr[2], val); + break; + case REG_TMR3: case REG_TMR3+1: case REG_TMR3+2: case REG_TMR3+3: + WRITE8(addr, mystique->dwgreg.tmr[3], val); + break; + case REG_TMR4: case REG_TMR4+1: case REG_TMR4+2: case REG_TMR4+3: + WRITE8(addr, mystique->dwgreg.tmr[4], val); + break; + case REG_TMR5: case REG_TMR5+1: case REG_TMR5+2: case REG_TMR5+3: + WRITE8(addr, mystique->dwgreg.tmr[5], val); + break; + case REG_TMR6: case REG_TMR6+1: case REG_TMR6+2: case REG_TMR6+3: + WRITE8(addr, mystique->dwgreg.tmr[6], val); + break; + case REG_TMR7: case REG_TMR7+1: case REG_TMR7+2: case REG_TMR7+3: + WRITE8(addr, mystique->dwgreg.tmr[7], val); + break; + case REG_TMR8: case REG_TMR8+1: case REG_TMR8+2: case REG_TMR8+3: + WRITE8(addr, mystique->dwgreg.tmr[8], val); + break; + + case REG_TEXORG: case REG_TEXORG+1: case REG_TEXORG+2: case REG_TEXORG+3: + WRITE8(addr, mystique->dwgreg.texorg, val); +// if ((addr & 3) == 3) pclog("texorg=%08x\n", mystique->dwgreg.texorg); + break; + case REG_TEXWIDTH: case REG_TEXWIDTH+1: case REG_TEXWIDTH+2: case REG_TEXWIDTH+3: + WRITE8(addr, mystique->dwgreg.texwidth, val); +// if ((addr & 3) == 3) pclog("texwith=%08x\n", mystique->dwgreg.texwidth); + break; + case REG_TEXHEIGHT: case REG_TEXHEIGHT+1: case REG_TEXHEIGHT+2: case REG_TEXHEIGHT+3: + WRITE8(addr, mystique->dwgreg.texheight, val); +// if ((addr & 3) == 3) pclog("texheight=%08x %i %i\n", mystique->dwgreg.texheight, mystique->dwgreg.texheight&0x3f, (int)(((mystique->dwgreg.texheight >> 9) & 0x3f) | ((mystique->dwgreg.texheight & (1 << 14)) ? 0xffffffc0 : 0))); + break; + case REG_TEXCTL: case REG_TEXCTL+1: case REG_TEXCTL+2: case REG_TEXCTL+3: + WRITE8(addr, mystique->dwgreg.texctl, val); +// if ((addr & 3) == 3) pclog("texctl=%08x\n", mystique->dwgreg.texctl); + mystique->dwgreg.ta_key = (mystique->dwgreg.texctl & TEXCTL_TAKEY) ? 1 : 0; + mystique->dwgreg.ta_mask = (mystique->dwgreg.texctl & TEXCTL_TAMASK) ? 1 : 0; + break; + case REG_TEXTRANS: case REG_TEXTRANS+1: case REG_TEXTRANS+2: case REG_TEXTRANS+3: + WRITE8(addr, mystique->dwgreg.textrans, val); +// /*if ((addr & 3) == 3) */pclog("textrans=%08x\n", mystique->dwgreg.textrans); + break; + + case 0x1c28: case 0x1c29: case 0x1c2a: case 0x1c2b: + case 0x1c2c: case 0x1c2d: case 0x1c2e: case 0x1c2f: + case 0x1cc4: case 0x1cc5: case 0x1cc6: case 0x1cc7: + case 0x1cd4: case 0x1cd5: case 0x1cd6: case 0x1cd7: + case 0x1ce4: case 0x1ce5: case 0x1ce6: case 0x1ce7: + case 0x1cf4: case 0x1cf5: case 0x1cf6: case 0x1cf7: + break; + + case REG_OPMODE: + mystique->dwgreg.dmamod = (val >> 2) & 3; + mystique->dma.iload_state = 0; + break; + + default: + if ((addr & 0x3fff) >= 0x2c4c && (addr & 0x3fff) <= 0x2cff) + break; + fatal("Write MGA accel control %08x %02x\n", addr & 0x3fff, val); + break; + } + + if (start_blit) + { + mystique_start_blit(mystique); +// fatal("Start blit\n"); + } +} +static void mystique_ctrl_write_b(uint32_t addr, uint8_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + svga_t *svga = &mystique->svga; + +// pclog("mystique addr=%04x val=%02x\n", addr & 0x3fff, val); + + if ((addr & 0x3fff) < 0x1c00) + { + mystique_iload_write_b(addr, val, p); + return; + } + if ((addr & 0x3e00) == 0x1c00 || (addr & 0x3e00) == 0x2c00) + { + if ((addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; +// pclog("mystique queue addr=%04x val=%02x\n", addr & 0x3fff, val); + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_BYTE); + return; + } + + switch (addr & 0x3fff) + { + case REG_ICLEAR: +// pclog("ICLEAR %02x\n", val); + if (val & ICLEAR_SOFTRAPICLR) + { + mystique->status &= ~STATUS_SOFTRAPEN; + mystique_update_irqs(mystique); + } + if (val & ICLEAR_VLINEICLR) + { + mystique->status &= ~STATUS_VLINEPEN; + mystique_update_irqs(mystique); + } + break; + case REG_ICLEAR+1: case REG_ICLEAR+2: case REG_ICLEAR+3: + break; + + case REG_IEN: + mystique->ien = val & 0x65; +// pclog("Write IEN %02x\n", val); + break; + case REG_IEN+1: case REG_IEN+2: case REG_IEN+3: + break; + + case REG_OPMODE: + mystique->dmamod = (val >> 2) & 3; +// pclog("OPMODE\n"); + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_BYTE); + break; + case REG_OPMODE+1: + mystique->dmadatasiz = val & 3; + break; + case REG_OPMODE+2: + mystique->dirdatasiz = val & 3; + break; + case REG_OPMODE+3: + break; + + case REG_PRIMADDRESS: case REG_PRIMADDRESS+1: case REG_PRIMADDRESS+2: case REG_PRIMADDRESS+3: + thread_lock_mutex(mystique->dma.lock); + WRITE8(addr, mystique->dma.primaddress, val); + mystique->dma.pri_state = 0; +// pclog("PRIMADDRESS write %04x %08x\n", addr, mystique->dma.primaddress); + thread_unlock_mutex(mystique->dma.lock); + break; + + case REG_DMAMAP: case REG_DMAMAP+0x1: case REG_DMAMAP+0x2: case REG_DMAMAP+0x3: + case REG_DMAMAP+0x4: case REG_DMAMAP+0x5: case REG_DMAMAP+0x6: case REG_DMAMAP+0x7: + case REG_DMAMAP+0x8: case REG_DMAMAP+0x9: case REG_DMAMAP+0xa: case REG_DMAMAP+0xb: + case REG_DMAMAP+0xc: case REG_DMAMAP+0xd: case REG_DMAMAP+0xe: case REG_DMAMAP+0xf: + mystique->dmamap[addr & 0xf] = val; + break; + + case REG_RST: case REG_RST+1: case REG_RST+2: case REG_RST+3: +// pclog("Write REG_RST\n"); + wait_fifo_idle(mystique); + mystique->busy = 0; + mystique->blitter_submit_refcount = 0; + mystique->blitter_submit_dma_refcount = 0; + mystique->blitter_complete_refcount = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->status = STATUS_ENDPRDMASTS; + break; + + case REG_ATTR_IDX: + svga_out(0x3c0, val, svga); + break; + case REG_ATTR_DATA: + svga_out(0x3c1, val, svga); + break; + + case REG_MISC: + svga_out(0x3c2, val, svga); + break; + + case REG_SEQ_IDX: + svga_out(0x3c4, val, svga); + break; + case REG_SEQ_DATA: + svga_out(0x3c5, val, svga); + break; + + case REG_GCTL_IDX: + mystique_out(0x3ce, val, mystique); + break; + case REG_GCTL_DATA: + mystique_out(0x3cf, val, mystique); + break; + + case REG_CRTC_IDX: + mystique_out(0x3d4, val, mystique); + break; + case REG_CRTC_DATA: + mystique_out(0x3d5, val, mystique); + break; + + case REG_CRTCEXT_IDX: + mystique_out(0x3de, val, mystique); + break; + case REG_CRTCEXT_DATA: + mystique_out(0x3df, val, mystique); + break; + + case REG_CACHEFLUSH: + break; + + case REG_PALWTADD: + svga_out(0x3c8, val, svga); + mystique->xreg_idx = val; + break; + case REG_PALDATA: + svga_out(0x3c9, val, svga); + break; + case REG_PIXRDMSK: + svga_out(0x3c6, val, svga); + break; + case REG_PALRDADD: + svga_out(0x3c7, val, svga); + break; + + case REG_X_DATAREG: + mystique_write_xreg(mystique, mystique->xreg_idx, val); + break; + + case REG_CURPOSX: case REG_CURPOSX+1: + WRITE8(addr, mystique->cursor.pos_x, val); + svga->hwcursor.x = mystique->cursor.pos_x - 64; + break; + case REG_CURPOSY: case REG_CURPOSY+1: + WRITE8(addr & 1, mystique->cursor.pos_y, val); + svga->hwcursor.y = mystique->cursor.pos_y - 64; + break; + + case 0x1e50: case 0x1e51: case 0x1e52: case 0x1e53: + case 0x3c0b: case 0x3e02: case 0x3e08: + break; + + default: + if ((addr & 0x3fff) >= 0x2c4c && (addr & 0x3fff) <= 0x2cff) + break; + if ((addr & 0x3fff) >= 0x3e00) + break; + fatal("Write MGA control %08x %02x\n", addr & 0x3fff, val); + break; + } +} + +static uint32_t mystique_ctrl_read_l(uint32_t addr, void *p) +{ + uint32_t ret; + +// pclog("mystique_ctrl_read_l: addr=%08x %08x\n", addr, cpu_state.pc); + if ((addr & 0x3fff) < 0x1c00) + return mystique_iload_read_l(addr, p); + + ret = mystique_ctrl_read_b(addr, p); + ret |= mystique_ctrl_read_b(addr+1, p) << 8; + ret |= mystique_ctrl_read_b(addr+2, p) << 16; + ret |= mystique_ctrl_read_b(addr+3, p) << 24; +// pclog("mcrl: addr=%08x ret=%08x %08x\n", addr, ret, mystique->status); + + return ret; +} + +static void mystique_accel_ctrl_write_l(uint32_t addr, uint32_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + int start_blit = 0; + +// pclog("mystique accel addr=%04x val=%08x\n", addr & 0x3fff, val); + if ((addr & 0x300) == 0x100) + { + addr &= ~0x100; + start_blit = 1; + } + + switch (addr & 0x3ffc) + { + case REG_DWGCTL: +// pclog(" dwgctrl write %08x %08x\n", addr2, val); + mystique->dwgreg.dwgctrl = val; + break; + + case REG_ZORG: + mystique->dwgreg.zorg = val; + mystique->dwgreg.z_base = mystique->dwgreg.ydstorg*2 + mystique->dwgreg.zorg; +// pclog("zorg=%08x z_base=%08x\n", mystique->dwgreg.zorg, mystique->dwgreg.z_base); + break; + + case REG_PLNWT: + mystique->dwgreg.plnwt = val; + break; + + case REG_SHIFT: + mystique->dwgreg.funcnt = val & 0xff; + mystique->dwgreg.xoff = val & 7; + mystique->dwgreg.yoff = (val >> 4) & 7; + mystique->dwgreg.stylelen = (val >> 16) & 0xff; + break; + + case REG_PITCH: + mystique->dwgreg.pitch = val & 0xffff; + if (mystique->dwgreg.pitch & PITCH_YLIN) + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + else + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; +// pclog("pitch=%04x %i\n", mystique->dwgreg.pitch, addr&1); + break; + + case REG_YDST: + mystique->dwgreg.ydst = val & 0x3fffff; + if (mystique->dwgreg.pitch & PITCH_YLIN) + { + mystique->dwgreg.ydst_lin = (mystique->dwgreg.ydst << 5) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val >> 29; + } + else + { + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; + mystique->dwgreg.selline = val & 7; + } +// pclog("ydst=%i ydsth=%08x %08x pitch=%08x\n", mystique->dwgreg.ydst, mystique->dwgreg.ydst, mystique->dwgreg.ydst_lin, mystique->dwgreg.pitch); + break; + + case REG_BCOL: + mystique->dwgreg.bcol = val; +// pclog("BCOL %i %02x\n", addr & 3, val); + break; + case REG_FCOL: + mystique->dwgreg.fcol = val; +// pclog("FCOL %i %02x\n", addr & 3, val); + break; + + case REG_SRC0: + mystique->dwgreg.src[0] = val; + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[0], 32); + break; + case REG_SRC1: + mystique->dwgreg.src[1] = val; + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[1], 32); + break; + case REG_SRC2: + mystique->dwgreg.src[2] = val; + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[2], 32); + break; + case REG_SRC3: + mystique->dwgreg.src[3] = val; + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, mystique->dwgreg.src[3], 32); + break; + + + case REG_DMAPAD: + if (mystique->busy && (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) == DWGCTRL_OPCODE_ILOAD) + blit_iload_write(mystique, val, 32); + break; + + case REG_AR0: + mystique->dwgreg.ar[0] = val; +// pclog("AR[0]=%08x\n", mystique->dwgreg.ar[0]); + break; + case REG_AR1: + mystique->dwgreg.ar[1] = val; + break; + case REG_AR2: + mystique->dwgreg.ar[2] = val; + break; + case REG_AR3: + mystique->dwgreg.ar[3] = val; +// pclog("AR[3]=%08x\n", mystique->dwgreg.ar[3]); + break; + case REG_AR4: + mystique->dwgreg.ar[4] = val; + break; + case REG_AR5: + mystique->dwgreg.ar[5] = val; + break; + case REG_AR6: + mystique->dwgreg.ar[6] = val; + break; + + case REG_DR0: + mystique->dwgreg.dr[0] = val; + break; + case REG_DR2: + mystique->dwgreg.dr[2] = val; + break; + case REG_DR3: + mystique->dwgreg.dr[3] = val; + break; + case REG_DR4: + mystique->dwgreg.dr[4] = val; +// if ((addr & 3) == 3) pclog("DR[4]=%08x\n", mystique->dwgreg.dr[4]); + break; + case REG_DR6: + mystique->dwgreg.dr[6] = val; +// if ((addr & 3) == 3) pclog("DR[6]=%08x\n", mystique->dwgreg.dr[6]); + break; + case REG_DR7: + mystique->dwgreg.dr[7] = val; +// if ((addr & 3) == 3) pclog("DR[7]=%08x\n", mystique->dwgreg.dr[7]); + break; + case REG_DR8: + mystique->dwgreg.dr[8] = val; + break; + case REG_DR10: + mystique->dwgreg.dr[10] = val; + break; + case REG_DR11: + mystique->dwgreg.dr[11] = val; + break; + case REG_DR12: + mystique->dwgreg.dr[12] = val; + break; + case REG_DR14: + mystique->dwgreg.dr[14] = val; + break; + case REG_DR15: + mystique->dwgreg.dr[15] = val; + break; + + case REG_SECEND: +// pclog("SECEND write %08x\n", val); + mystique->dma.secend = val; + if (mystique->dma.state != DMA_STATE_SEC && (mystique->dma.secaddress & DMA_ADDR_MASK) != (mystique->dma.secend & DMA_ADDR_MASK)) + { +// pclog(" DMA state STATE_SEC\n"); + mystique->dma.state = DMA_STATE_SEC; + } + break; + + case REG_SOFTRAP: +// pclog("SOFTRAP\n"); +/* mystique->dma.secaddress = val;*/ + mystique->dma.state = DMA_STATE_IDLE; + mystique->endprdmasts_pending = 1; + mystique->softrap_pending_val = val; + mystique->softrap_pending = 1; +// pclog("SOFTRAP DMA state STATE_IDLE\n"); +/* mystique->status |= STATUS_SOFTRAPEN; + mystique_update_irqs(mystique);*/ + break; + + default: + mystique_accel_ctrl_write_b(addr, val & 0xff, p); + mystique_accel_ctrl_write_b(addr+1, (val >> 8) & 0xff, p); + mystique_accel_ctrl_write_b(addr+2, (val >> 16) & 0xff, p); + mystique_accel_ctrl_write_b(addr+3, (val >> 24) & 0xff, p); + break; + } + + if (start_blit) + { + mystique_start_blit(mystique); +// fatal("Start blit\n"); + } +} + +static void mystique_ctrl_write_l(uint32_t addr, uint32_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + uint32_t reg_addr; + +// pclog("mystique addr=%04x val=%08x\n", addr & 0x3fff, val); + if ((addr & 0x3fff) < 0x1c00) + { + mystique_iload_write_l(addr, val, p); + return; + } + + if ((addr & 0x3e00) == 0x1c00 || (addr & 0x3e00) == 0x2c00) + { + if ((addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; +// pclog("mystique queue addr=%04x val=%08x\n", addr & 0x3fff, val); + mystique_queue(mystique, addr & 0x3fff, val, FIFO_WRITE_CTRL_LONG); + return; + } + + switch (addr & 0x3ffc) + { + case REG_PRIMEND: + thread_lock_mutex(mystique->dma.lock); +// pclog("PRIMEND write %08x\n", val); + mystique->dma.primend = val; + if (mystique->dma.state == DMA_STATE_IDLE && (mystique->dma.primaddress & DMA_ADDR_MASK) != (mystique->dma.primend & DMA_ADDR_MASK)) + { +// pclog("Clear DMA end flag\n"); + mystique->endprdmasts_pending = 0; + mystique->status &= ~STATUS_ENDPRDMASTS; + + mystique->dma.state = DMA_STATE_PRI; +// pclog(" DMA state STATE_PRI\n"); + mystique->dma.pri_state = 0; + wake_fifo_thread(mystique); + } + thread_unlock_mutex(mystique->dma.lock); + break; + + case REG_DWG_INDIR_WT: case REG_DWG_INDIR_WT+0x04: case REG_DWG_INDIR_WT+0x08: case REG_DWG_INDIR_WT+0x0c: + case REG_DWG_INDIR_WT+0x10: case REG_DWG_INDIR_WT+0x14: case REG_DWG_INDIR_WT+0x18: case REG_DWG_INDIR_WT+0x1c: + case REG_DWG_INDIR_WT+0x20: case REG_DWG_INDIR_WT+0x24: case REG_DWG_INDIR_WT+0x28: case REG_DWG_INDIR_WT+0x2c: + case REG_DWG_INDIR_WT+0x30: case REG_DWG_INDIR_WT+0x34: case REG_DWG_INDIR_WT+0x38: case REG_DWG_INDIR_WT+0x3c: + reg_addr = (mystique->dmamap[(addr >> 2) & 0xf] & 0x7f) << 2; + if (mystique->dmamap[(addr >> 2) & 0xf] & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_refcount++; + +// pclog("mystique queue dwg addr=%04x val=%08x\n", reg_addr, val); + mystique_queue(mystique, reg_addr, val, FIFO_WRITE_CTRL_LONG); + break; + + default: + mystique_ctrl_write_b(addr, val & 0xff, p); + mystique_ctrl_write_b(addr+1, (val >> 8) & 0xff, p); + mystique_ctrl_write_b(addr+2, (val >> 16) & 0xff, p); + mystique_ctrl_write_b(addr+3, (val >> 24) & 0xff, p); + break; + } +} + +static uint8_t mystique_iload_read_b(uint32_t addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + wait_fifo_idle(mystique); + if (!mystique->busy) + { +// fatal("mystique_iload_read_b: %08x !busy\n", addr); + return 0xff; + } + +// pclog("Readb MGA ILOAD %08x\n", addr); + return blit_idump_read(mystique); +} +static uint32_t mystique_iload_read_l(uint32_t addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + wait_fifo_idle(mystique); + if (!mystique->busy) + { +// fatal("mystique_iload_read_l: !busy\n"); + return 0xffffffff; + } + +// pclog("Readl MGA ILOAD %08x %i\n", addr, mystique->dwgreg.words); + mystique->dwgreg.words++; + return blit_idump_read(mystique); +} +static void mystique_iload_write_b(uint32_t addr, uint8_t val, void *p) +{ + fatal("Write MGA ILOAD %08x %02x\n", addr, val); +} +static void mystique_iload_write_l(uint32_t addr, uint32_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + +// pclog("mystique queue iload addr=%04x val=%08x\n", addr, val); + mystique_queue(mystique, 0, val, FIFO_WRITE_ILOAD_LONG); +} + +static void mystique_accel_iload_write_l(uint32_t addr, uint32_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + +// pclog(" Write ILOAD %08x %i %i %08x\n", val, mystique->dwgreg.dmamod, mystique->dma.iload_state, mystique->dwgreg.dwgctrl); + switch (mystique->dwgreg.dmamod) + { + case DMA_MODE_REG: + if (mystique->dma.iload_state == 0) + { +// pclog(" ILOAD header\n"); + mystique->dma.iload_header = val; + mystique->dma.iload_state = 1; + } + else + { + uint32_t reg_addr = (mystique->dma.iload_header & 0x7f) << 2; + if (mystique->dma.iload_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + +// pclog(" ILOAD write %08x to %02x %04x\n", val, mystique->dma.iload_header & 0xff, reg_addr); + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + + mystique->dma.iload_header >>= 8; + mystique->dma.iload_state = (mystique->dma.iload_state == 4) ? 0 : (mystique->dma.iload_state+1); + } + break; + + case DMA_MODE_BLIT: + if (mystique->busy) + blit_iload_write(mystique, val, 32); + break; + + default: + fatal("ILOAD write DMAMOD %i\n", mystique->dwgreg.dmamod); + } +} + + +static uint8_t mystique_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + egareads++; + + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + return svga->vram[addr & svga->vram_mask]; +} +static uint16_t mystique_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + egareads += 2; + + cycles -= video_timing_read_w; + cycles_lost += video_timing_read_w; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; + + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; +} +static uint32_t mystique_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + egareads += 4; + + cycles -= video_timing_read_l; + cycles_lost += video_timing_read_l; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + +static void mystique_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + egawrites++; + + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + svga->vram[addr] = val; +} +static void mystique_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + egawrites += 2; + + cycles -= video_timing_write_w; + cycles_lost += video_timing_write_w; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} +static void mystique_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + egawrites += 4; + + cycles -= video_timing_write_l; + cycles_lost += video_timing_write_l; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + + +static uint32_t mystique_dma_read(uint32_t addr) +{ + if ((addr & DMA_ADDR_MASK) > (mem_size * 1024)) + { +// pclog("PCI DMA out of range\n"); + return -1; + } + return *(uint32_t *)&ram[addr & DMA_ADDR_MASK]; +} + +static void run_dma(mystique_t *mystique) +{ + int words_transferred = 0; + + thread_lock_mutex(mystique->dma.lock); + + if (mystique->dma.state == DMA_STATE_IDLE) + { + thread_unlock_mutex(mystique->dma.lock); + return; + } + + while (words_transferred < DMA_MAX_WORDS && mystique->dma.state != DMA_STATE_IDLE) + { + switch (mystique->dma.state)// != DMA_STATE_IDLE) + { + case DMA_STATE_PRI: + switch (mystique->dma.primaddress & DMA_MODE_MASK) + { + case DMA_MODE_REG: + if (mystique->dma.pri_state == 0) + { + mystique->dma.pri_header = mystique_dma_read(mystique->dma.primaddress); +// pclog("DMA pri read header %08x from %08x %08x\n", mystique->dma.pri_header, mystique->dma.primaddress, mystique->dma.primend); + mystique->dma.primaddress += 4; + } + +// if ((mystique->dma.pri_header & 0xff) != 0x15) + { + uint32_t val = mystique_dma_read(mystique->dma.primaddress); + uint32_t reg_addr; + + mystique->dma.primaddress += 4; + + reg_addr = (mystique->dma.pri_header & 0x7f) << 2; + if (mystique->dma.pri_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + +// pclog(" DMA pri write %08x to %02x %04x %08x %08x\n", val, mystique->dma.pri_header & 0xff, reg_addr, (mystique->dma.primaddress & DMA_ADDR_MASK), (mystique->dma.primend & DMA_ADDR_MASK)); + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + } + + mystique->dma.pri_header >>= 8; + mystique->dma.pri_state = (mystique->dma.pri_state + 1) & 3; + + words_transferred++; + if (mystique->dma.state == DMA_STATE_SEC) + mystique->dma.pri_state = 0; + else if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) + { +// pclog("DMA pri end\n"); + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + } + break; + + default: + fatal("DMA_STATE_PRI: mode %i\n", mystique->dma.primaddress & DMA_MODE_MASK); + } + break; + + case DMA_STATE_SEC: + switch (mystique->dma.secaddress & DMA_MODE_MASK) + { + case DMA_MODE_REG: + if (mystique->dma.sec_state == 0) + { + mystique->dma.sec_header = mystique_dma_read(mystique->dma.secaddress); +// pclog("DMA sec read header %08x from %08x %08x\n", mystique->dma.sec_header, mystique->dma.secaddress, mystique->dma.secend); + mystique->dma.secaddress += 4; + } + +// if ((mystique->dma.sec_header & 0xff) != 0x15) + { + uint32_t val = mystique_dma_read(mystique->dma.secaddress); + uint32_t reg_addr; + + mystique->dma.secaddress += 4; + + reg_addr = (mystique->dma.sec_header & 0x7f) << 2; + if (mystique->dma.sec_header & 0x80) + reg_addr += 0x2c00; + else + reg_addr += 0x1c00; + +// pclog(" DMA sec write %08x to %02x %04x %08x %08x\n", val, mystique->dma.sec_header & 0xff, reg_addr, (mystique->dma.secaddress & DMA_ADDR_MASK), (mystique->dma.secend & DMA_ADDR_MASK)); + if ((reg_addr & 0x300) == 0x100) + mystique->blitter_submit_dma_refcount++; + + mystique_accel_ctrl_write_l(reg_addr, val, mystique); + } + + mystique->dma.sec_header >>= 8; + mystique->dma.sec_state = (mystique->dma.sec_state + 1) & 3; + + words_transferred++; + if ((mystique->dma.secaddress & DMA_ADDR_MASK) == (mystique->dma.secend & DMA_ADDR_MASK)) + { +// pclog("DMA sec end\n"); + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) + { +// pclog("DMA pri end\n"); + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + } + else + { +// pclog("DMA pri resume\n"); + mystique->dma.state = DMA_STATE_PRI; + } + } + break; + + case DMA_MODE_BLIT: + { + uint32_t val = mystique_dma_read(mystique->dma.secaddress); +// pclog(" DMA_MODE_BLIT %08x %08x %08x %08x\n", mystique->dma.secaddress & DMA_ADDR_MASK, mystique->dma.secend & DMA_ADDR_MASK, mystique->dwgreg.dwgctrl_running, mystique->maccess_running); + mystique->dma.secaddress += 4; + + if (mystique->busy) + blit_iload_write(mystique, val, 32); + + words_transferred++; + if ((mystique->dma.secaddress & DMA_ADDR_MASK) == (mystique->dma.secend & DMA_ADDR_MASK)) + { +// pclog("DMA sec end\n"); + if ((mystique->dma.primaddress & DMA_ADDR_MASK) == (mystique->dma.primend & DMA_ADDR_MASK)) + { +// pclog("DMA pri end\n"); + mystique->endprdmasts_pending = 1; + mystique->dma.state = DMA_STATE_IDLE; + } + else + { +// pclog("DMA pri resume\n"); + mystique->dma.state = DMA_STATE_PRI; + } + } + } + break; + + default: + fatal("DMA_STATE_SEC: mode %i\n", mystique->dma.secaddress & DMA_MODE_MASK); + } + break; + } + } + thread_unlock_mutex(mystique->dma.lock); +} + +static void fifo_thread(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + while (1) + { + thread_set_event(mystique->fifo_not_full_event); + thread_wait_event(mystique->wake_fifo_thread, -1); + thread_reset_event(mystique->wake_fifo_thread); + + while (!FIFO_EMPTY || mystique->dma.state != DMA_STATE_IDLE) + { + int words_transferred = 0; + + while (!FIFO_EMPTY && words_transferred < 100) + { + fifo_entry_t *fifo = &mystique->fifo[mystique->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_CTRL_BYTE: + mystique_accel_ctrl_write_b(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + case FIFO_WRITE_CTRL_LONG: + mystique_accel_ctrl_write_l(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + case FIFO_WRITE_ILOAD_LONG: + mystique_accel_iload_write_l(fifo->addr_type & FIFO_ADDR, fifo->val, mystique); + break; + } + + fifo->addr_type = FIFO_INVALID; + mystique->fifo_read_idx++; + + if (FIFO_ENTRIES > FIFO_THRESHOLD) + thread_set_event(mystique->fifo_not_full_event); + + words_transferred++; + } + /*Only run DMA once the FIFO is empty. Required by + Screamer 2 / Rally which will incorrectly clip an ILOAD + if DMA runs ahead*/ + if (!words_transferred) + run_dma(mystique); + } + } +} + +static void wake_fifo_thread(mystique_t *mystique) +{ + if (!timer_is_enabled(&mystique->wake_timer)) + { + /*Don't wake FIFO thread immediately - if we do that it will probably + process one word and go back to sleep, requiring it to be woken on + almost every write. Instead, wait a short while so that the CPU + emulation writes more data so we have more batched-up work.*/ + timer_set_delay_u64(&mystique->wake_timer, WAKE_DELAY); + } +} + +static void wake_fifo_thread_now(mystique_t *mystique) +{ + thread_set_event(mystique->wake_fifo_thread); +} + +static void mystique_wake_timer(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + thread_set_event(mystique->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void wait_fifo_idle(mystique_t *mystique) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread_now(mystique); + thread_wait_event(mystique->fifo_not_full_event, 1); + } +} + +/*IRQ code (PCI & PIC) is not currently thread safe. SOFTRAP IRQ requests must + therefore be submitted from the main emulation thread, in this case via a timer + callback. End-of-DMA status is also deferred here to prevent races between + SOFTRAP IRQs and code reading the status register. Croc will get into an IRQ + loop and triple fault if the ENDPRDMASTS flag is seen before the IRQ is taken*/ +static void mystique_softrap_pending_timer(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + timer_advance_u64(&mystique->softrap_pending_timer, TIMER_USEC * 100); + + if (mystique->endprdmasts_pending) + { + mystique->endprdmasts_pending = 0; + mystique->status |= STATUS_ENDPRDMASTS; + } + if (mystique->softrap_pending) + { + mystique->softrap_pending = 0; + +// pclog("Take SOFTRAP %08x\n", cpu_state.pc); + mystique->dma.secaddress = mystique->softrap_pending_val; + mystique->status |= STATUS_SOFTRAPEN; + mystique_update_irqs(mystique); + } +} + +static void mystique_queue(mystique_t *mystique, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &mystique->fifo[mystique->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(mystique->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(mystique->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + mystique->fifo_write_idx++; + + if (FIFO_ENTRIES > FIFO_THRESHOLD || FIFO_ENTRIES < 8) + wake_fifo_thread(mystique); + +// wait_fifo_idle(mystique); +} + + + +static uint32_t bitop(uint32_t src, uint32_t dst, uint32_t dwgctrl) +{ + switch (dwgctrl & DWGCTRL_BOP_MASK) + { + case BOP(0x0): return 0; + case BOP(0x1): return ~(dst | src); + case BOP(0x2): return dst & ~src; + case BOP(0x3): return ~src; + case BOP(0x4): return ~dst & src; + case BOP(0x5): return ~dst; + case BOP(0x6): return dst ^ src; + case BOP(0x7): return ~(dst & src); + case BOP(0x8): return dst & src; + case BOP(0x9): return ~(dst ^ src); + case BOP(0xa): return dst; + case BOP(0xb): return dst | ~src; + case BOP(0xc): return src; + case BOP(0xd): return ~dst | src; + case BOP(0xe): return dst | src; + case BOP(0xf): return ~0; + } + return 0; +} + +static uint16_t dither(mystique_t *mystique, int r, int g, int b, int x, int y) +{ + switch (mystique->dwgreg.dither) + { + case DITHER_NONE_555: + return (b >> 3) | ((g >> 3) << 5) | ((r >> 3) << 10); + + case DITHER_NONE_565: + return (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11); + + case DITHER_555: + return dither5[b][y][x] | (dither5[g][y][x] << 5) | (dither5[r][y][x] << 10); + + case DITHER_565: + default: + return dither5[b][y][x] | (dither6[g][y][x] << 5) | (dither5[r][y][x] << 11); + } +} + + +static uint32_t blit_idump_idump(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint64_t val64 = 0; + uint32_t val = 0; + int count = 0; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BU32RGB: + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: +// pclog(" IDUMP %08x\n", mystique->dwgreg.src_addr); + while (count < 32) + { + val |= (svga->vram[mystique->dwgreg.src_addr & mystique->vram_mask] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } + else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 8; + } + break; + + case MACCESS_PWIDTH_16: + // pclog(" IDUMP %08x\n", mystique->dwgreg.src_addr); + while (count < 32) + { + val |= (((uint16_t *)svga->vram)[mystique->dwgreg.src_addr & mystique->vram_mask_w] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } + else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 16; + } + break; + + case MACCESS_PWIDTH_24: + if (mystique->dwgreg.idump_end_of_line) + { + mystique->dwgreg.idump_end_of_line = 0; + val = mystique->dwgreg.iload_rem_data; + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = 0; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + + count += mystique->dwgreg.iload_rem_count; + val64 = mystique->dwgreg.iload_rem_data; + +// pclog(" IDUMP %08x\n", mystique->dwgreg.src_addr); + while ((count < 32) && !mystique->dwgreg.idump_end_of_line) + { + val64 |= (uint64_t)((*(uint32_t *)&svga->vram[(mystique->dwgreg.src_addr * 3) & mystique->vram_mask]) & 0xffffff) << count; +/* pclog(" %i %i %i %016llx\n", count, mystique->dwgreg.xdst, + mystique->dwgreg.length_cur, val64);*/ + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } + else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + if (count > 8) + mystique->dwgreg.idump_end_of_line = 1; + else + { + count = 32; + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_LINEAR)) + { + if (count > 8) + mystique->dwgreg.idump_end_of_line = 1; + else + { + count = 32; + break; + } + } + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + + count += 24; + } + if (count > 32) + mystique->dwgreg.iload_rem_count = count - 32; + else + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = (uint32_t)(val64 >> 32); + val = val64 & 0xffffffff; + break; + + case MACCESS_PWIDTH_32: +// pclog(" IDUMP %08x\n", mystique->dwgreg.src_addr); + + val = (((uint32_t *)svga->vram)[mystique->dwgreg.src_addr & mystique->vram_mask_l] << count); + + if (mystique->dwgreg.src_addr == mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + } + else + mystique->dwgreg.src_addr++; + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + break; + + default: + fatal("IDUMP DWGCTRL_BLTMOD_BU32RGB %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->maccess_running); + } + break; + + default: + fatal("IDUMP DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown IDUMP atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + return val; +} + +static uint32_t blit_idump_read(mystique_t *mystique) +{ + uint32_t ret = 0xffffffff; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) + { + case DWGCTRL_OPCODE_IDUMP: + ret = blit_idump_idump(mystique); + break; + + default: + fatal("blit_idump_read: bad opcode %08x\n", mystique->dwgreg.dwgctrl_running); + } + +// pclog(" idump returned %08x\n", ret); + return ret; +} + +static void blit_iload_iload(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint32_t src, dst; + uint64_t data64; + int min_size; + uint32_t bltckey = mystique->dwgreg.fcol, bltcmsk = mystique->dwgreg.bcol; + const int transc = mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint32_t data_mask = 1; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + bltckey &= 0xff; + bltcmsk &= 0xff; + break; + case MACCESS_PWIDTH_16: + bltckey &= 0xffff; + bltcmsk &= 0xffff; + break; + } + + mystique->dwgreg.words++; +// pclog("blit_iload_iload: %08x %06x %02x %i %08x words=%i %08x %08x\n", data, mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst, data, (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) == DWGCTRL_BLTMOD_BMONOWF, mystique->dwgreg.dwgctrl_running, mystique->dwgreg.words,mystique->dwgreg.words, mystique->maccess_running); + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_RPL: + if (mystique->maccess_running & MACCESS_TLUTLOAD) + { + while ((mystique->dwgreg.length_cur > 0) && (size >= 16)) + { + uint16_t src = data & 0xffff; +// pclog(" LUT[%02x]=%04x\n", mystique->dwgreg.ydst & 0xff, src); + + mystique->lut[mystique->dwgreg.ydst & 0xff].r = (src >> 11) << 3; + mystique->lut[mystique->dwgreg.ydst & 0xff].g = ((src >> 5) & 0x3f) << 2; + mystique->lut[mystique->dwgreg.ydst & 0xff].b = (src & 0x1f) << 3; + mystique->dwgreg.ydst++; + mystique->dwgreg.length_cur--; + data >>= 16; + size -= 16; + } + + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + } + break; + } + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_BLK: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BFCOL: + size += mystique->dwgreg.iload_rem_count; +// pclog(" size=%i xdst=%i cur=%i data= %08x %08x ", size, mystique->dwgreg.xdst, mystique->dwgreg.length_cur, mystique->dwgreg.iload_rem_data, data); + data64 = mystique->dwgreg.iload_rem_data | ((uint64_t)data << mystique->dwgreg.iload_rem_count); +// pclog("%016llx words=%i\n", data64, mystique->dwgreg.words); + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + min_size = 8; + break; + case MACCESS_PWIDTH_16: + min_size = 16; + break; + case MACCESS_PWIDTH_24: + min_size = 24; + break; + case MACCESS_PWIDTH_32: + min_size = 32; + break; + } + + while (size >= min_size) + { + int draw = (!transc || (data & bltcmsk) != bltckey) && trans[mystique->dwgreg.xdst & 3]; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) + { + dst = svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]; + + dst = bitop(data & 0xff, dst, mystique->dwgreg.dwgctrl_running); +// pclog(" 8 %06x=%04x\n", mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst, dst); + svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount; + } +/* else + pclog(" Clipped %i,%i %i %08x,%08x %08x\n", + mystique->dwgreg.cxleft, mystique->dwgreg.cxright, mystique->dwgreg.xdst, + mystique->dwgreg.ytop, mystique->dwgreg.ybot, mystique->dwgreg.ydst_lin);*/ + + data >>= 8; + size -= 8; + break; + + case MACCESS_PWIDTH_16: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) + { + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + + dst = bitop(data & 0xffff, dst, mystique->dwgreg.dwgctrl_running); +// pclog(" 16 %06x=%04x\n", mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst, dst); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + } + + data >>= 16; + size -= 16; + break; + + case MACCESS_PWIDTH_24: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + uint32_t old_dst = *((uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]); + + dst = bitop(data64, old_dst, mystique->dwgreg.dwgctrl_running); + *((uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]) = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12] = changeframecount; + } + + data64 >>= 24; + size -= 24; + break; + + case MACCESS_PWIDTH_32: + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && draw) + { + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + + dst = bitop(data, dst, mystique->dwgreg.dwgctrl_running); +// pclog(" 32 %06x=%04x\n", mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst, dst); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + } + + size = 0; + break; + + default: + fatal("ILOAD RSTR/RPL BFCOL pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + data64 = 0; + size = 0; + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + mystique->dwgreg.iload_rem_count = size; + mystique->dwgreg.iload_rem_data = data64; + break; + + case DWGCTRL_BLTMOD_BMONOWF: + data = (data >> 24) | ((data & 0x00ff0000) >> 8) | ((data & 0x0000ff00) << 8) | (data << 24); + data_mask = (1 << 31); + case DWGCTRL_BLTMOD_BMONOLEF: + while (size) + { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + ((data & data_mask) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && + trans[mystique->dwgreg.xdst & 3]) + { + uint32_t old_dst; + + src = (data & data_mask) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask]; + +// pclog(" %02x %02x %06x ", src, dst, mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); +// pclog("%02x\n", dst); + + svga->vram[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + +// pclog(" %02x %02x %06x ", src, dst, mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); +// pclog("%02x\n", dst); + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask]; + +// pclog(" %02x %02x %06x ", src, old_dst, mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst); + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); +// pclog("%02x %08x %08x %08x %i\n", dst, data, mystique->dwgreg.fcol, mystique->dwgreg.bcol, mystique->dwgreg.xdst); + + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + +// pclog(" %02x %02x %06x ", src, dst, mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); +// pclog("%02x %08x %08x %08x %i\n", dst, data, mystique->dwgreg.fcol, mystique->dwgreg.bcol, mystique->dwgreg.xdst); + + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD RSTR/RPL BMONOWF pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_LINEAR)) + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + if (data_mask == 1) + data >>= 1; + else + data <<= 1; + size--; + } + break; + + case DWGCTRL_BLTMOD_BU24RGB: + size += mystique->dwgreg.iload_rem_count; +// pclog(" size=%i data= %08x %08x ", size, mystique->dwgreg.iload_rem_data, data); + data64 = mystique->dwgreg.iload_rem_data | ((uint64_t)data << mystique->dwgreg.iload_rem_count); +// pclog("%016llx\n", data64); + + while (size >= 24) + { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_32: + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + +// pclog(" %06llx %02x %06x ", data64 & 0xffffff, dst, mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst); +// pclog("x=%i l=%i ", mystique->dwgreg.xdst, mystique->dwgreg.length_cur); + dst = bitop(data64 & 0xffffff, dst, mystique->dwgreg.dwgctrl_running); +// pclog("%02x\n", dst); + + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD RSTR/RPL BU24RGB pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + data64 >>= 24; + size -= 24; + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + data64 = 0; + size = 0; + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + + mystique->dwgreg.iload_rem_count = size; + mystique->dwgreg.iload_rem_data = data64; + break; + + default: + fatal("ILOAD DWGCTRL_ATYPE_RPL\n"); + break; + } + break; + + default: + fatal("Unknown ILOAD iload atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +static void blit_iload_iload_scale(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint64_t data64 = 0; + int y0, y1; + int u, v; + int dR, dG, dB; + int r0, g0, b0; + int r1, g1, b1; + +// pclog(" iload_scale: data=%08x\n", data); + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BUYUV: + y0 = (298 * ((int)(data & 0xff) - 16)) >> 8; + u = ((data >> 8) & 0xff) - 0x80; + y1 = (298 * ((int)((data >> 16) & 0xff) - 16)) >> 8; + v = ((data >> 24) & 0xff) - 0x80; + + dR = (309*v) >> 8; + dG = (100*u + 208*v) >> 8; + dB = (516*u) >> 8; + + r0 = y0 + dR; + CLAMP(r0); + g0 = y0 - dG; + CLAMP(g0); + b0 = y0 + dB; + CLAMP(b0); + r1 = y1 + dR; + CLAMP(r1); + g1 = y1 - dG; + CLAMP(g1); + b1 = y1 + dB; + CLAMP(b1); + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_16: + data = (b0 >> 3) | ((g0 >> 2) << 5) | ((r0 >> 3) << 11); + data |= (((b1 >> 3) | ((g1 >> 2) << 5) | ((r1 >> 3) << 11)) << 16); + size = 32; + break; + case MACCESS_PWIDTH_32: + data64 = b0 | (g0 << 8) | (r0 << 16); + data64 |= ((uint64_t)b0 << 32) | ((uint64_t)g0 << 40) | ((uint64_t)r0 << 48); + size = 64; + break; + + default: + fatal("blit_iload_iload_scale BUYUV pwidth %i\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + break; + + default: + fatal("blit_iload_iload_scale bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_16: + while (size >= 16) + { +// pclog(" Write %i %i %08x\n", mystique->dwgreg.xdst, mystique->dwgreg.fxright, mystique->dwgreg.ar[6]); + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + uint16_t dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + dst = bitop(data & 0xffff, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t)mystique->dwgreg.ar[6] >= 0) + { + mystique->dwgreg.ar[6] -= (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + data >>= 16; + size -= 16; + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + break; + + case MACCESS_PWIDTH_32: + while (size >= 32) + { +// pclog(" Write %i %i %08x\n", mystique->dwgreg.xdst, mystique->dwgreg.fxright, mystique->dwgreg.ar[6]); + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + uint32_t dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + dst = bitop(data64, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t)mystique->dwgreg.ar[6] >= 0) + { + mystique->dwgreg.ar[6] -= (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + data64 >>= 32; + size -= 32; + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } + break; + + default: + fatal("ILOAD_SCALE pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } +} + +static void blit_iload_iload_high(mystique_t *mystique, uint32_t data, int size) +{ + svga_t *svga = &mystique->svga; + uint32_t out_data; + int y0, y1, u, v; + int dR, dG, dB; + int r = 0, g = 0, b = 0; + int next_r = 0, next_g = 0, next_b = 0; + +// pclog(" iload_high: data=%08x\n", data); + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BUYUV: + y0 = (298 * ((int)(data & 0xff) - 16)) >> 8; + u = ((data >> 8) & 0xff) - 0x80; + y1 = (298 * ((int)((data >> 16) & 0xff) - 16)) >> 8; + v = ((data >> 24) & 0xff) - 0x80; + + dR = (309*v) >> 8; + dG = (100*u + 208*v) >> 8; + dB = (516*u) >> 8; + + r = y0 + dR; + CLAMP(r); + g = y0 - dG; + CLAMP(g); + b = y0 + dB; + CLAMP(b); + + next_r = y1 + dR; + CLAMP(next_r); + next_g = y1 - dG; + CLAMP(next_g); + next_b = y1 + dB; + CLAMP(next_b); + + size = 32; + break; + + default: + fatal("blit_iload_iload_high bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + + while (size >= 16) + { + if (mystique->dwgreg.xdst >= mystique->dwgreg.cxleft && mystique->dwgreg.xdst <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + uint32_t dst; + int f1 = (mystique->dwgreg.ar[6] >> 12) & 0xf; + int f0 = 0x10 - f1; + int out_r = ((mystique->dwgreg.lastpix_r * f0) + (r * f1)) >> 4; + int out_g = ((mystique->dwgreg.lastpix_g * f0) + (g * f1)) >> 4; + int out_b = ((mystique->dwgreg.lastpix_b * f0) + (b * f1)) >> 4; + +// pclog(" Write %i %i %08x %i %i %i %i %i\n", mystique->dwgreg.xdst, mystique->dwgreg.fxright, mystique->dwgreg.ar[6], mystique->dwgreg.lastpix_r, r, f0, f1, out_r); + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_16: + out_data = (out_b >> 3) | ((out_g >> 2) << 5) | ((out_r >> 3) << 11); + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w]; + dst = bitop(out_data, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + case MACCESS_PWIDTH_32: + out_data = out_b | (out_g << 8) | (out_r << 16); + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l]; + dst = bitop(out_data, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + mystique->dwgreg.xdst) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("ILOAD_SCALE_HIGH RSTR/RPL BUYUV pwidth %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + mystique->dwgreg.ar[6] += mystique->dwgreg.ar[2]; + if ((int32_t)mystique->dwgreg.ar[6] >= 0) + { + mystique->dwgreg.ar[6] -= 65536; + size -= 16; + + mystique->dwgreg.lastpix_r = r; + mystique->dwgreg.lastpix_g = g; + mystique->dwgreg.lastpix_b = b; + r = next_r; + g = next_g; + b = next_b; + } + + if (mystique->dwgreg.xdst == mystique->dwgreg.fxright) + { + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + mystique->dwgreg.ar[6] = mystique->dwgreg.ar[2] - (mystique->dwgreg.fxright - mystique->dwgreg.fxleft); + mystique->dwgreg.lastpix_r = 0; + mystique->dwgreg.lastpix_g = 0; + mystique->dwgreg.lastpix_b = 0; + + mystique->dwgreg.length_cur--; + if (!mystique->dwgreg.length_cur) + { + mystique->busy = 0; + mystique->blitter_complete_refcount++; + break; + } + break; + } + else + mystique->dwgreg.xdst = (mystique->dwgreg.xdst + 1) & 0xffff; + } +} + +static void blit_iload_iload_highv(mystique_t *mystique, uint32_t data, int size) +{ + uint8_t *src0, *src1; + +// pclog(" iload_highv: data=%08x\n", data); + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BUYUV: + if (!mystique->dwgreg.highv_line) + { + mystique->dwgreg.highv_data = data; + mystique->dwgreg.highv_line = 1; + return; + } + mystique->dwgreg.highv_line = 0; + + src0 = (uint8_t *)&mystique->dwgreg.highv_data; + src1 = (uint8_t *)&data; + + src1[0] = ((src0[0] * mystique->dwgreg.beta) + (src1[0] * (16 - mystique->dwgreg.beta))) >> 4; + src1[1] = ((src0[1] * mystique->dwgreg.beta) + (src1[1] * (16 - mystique->dwgreg.beta))) >> 4; + src1[2] = ((src0[2] * mystique->dwgreg.beta) + (src1[2] * (16 - mystique->dwgreg.beta))) >> 4; + src1[3] = ((src0[3] * mystique->dwgreg.beta) + (src1[3] * (16 - mystique->dwgreg.beta))) >> 4; + blit_iload_iload_high(mystique, data, 32); + break; + + default: + fatal("blit_iload_iload_highv bltmod %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } +} + +static void blit_iload_write(mystique_t *mystique, uint32_t data, int size) +{ +// pclog(" ILOAD %08x %08x\n", data, mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK); + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) + { + case DWGCTRL_OPCODE_ILOAD: + blit_iload_iload(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_SCALE: + blit_iload_iload_scale(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGH: + blit_iload_iload_high(mystique, data, size); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGHV: + blit_iload_iload_highv(mystique, data, size); + break; + + default: + fatal("blit_iload_write: bad opcode %08x\n", mystique->dwgreg.dwgctrl_running); + } +} + +static int z_check(uint16_t z, uint16_t old_z, uint32_t z_mode)//mystique->dwgreg.dwgctrl & DWGCTRL_ZMODE_MASK) +{ + switch (z_mode) + { + case DWGCTRL_ZMODE_ZE: + return (z == old_z); + case DWGCTRL_ZMODE_ZNE: + return (z != old_z); + case DWGCTRL_ZMODE_ZLT: + return (z < old_z); + case DWGCTRL_ZMODE_ZLTE: + return (z <= old_z); + case DWGCTRL_ZMODE_ZGT: + return (z > old_z); + case DWGCTRL_ZMODE_ZGTE: + return (z >= old_z); + + case DWGCTRL_ZMODE_NOZCMP: + default: + return 1; + } +} + +static void blit_line(mystique_t *mystique, int closed) +{ + svga_t *svga = &mystique->svga; + uint32_t src, dst, old_dst; + int x; + int z_write; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_RPL: + x = mystique->dwgreg.xdst; + while (mystique->dwgreg.length > 0) + { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + src = mystique->dwgreg.fcol; + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + +// pclog(" LINE %i %08x %08x\n", x, mystique->dwgreg.ydst_lin, mystique->dwgreg.ar[1]); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + src = mystique->dwgreg.fcol; + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + +// pclog(" LINE %i %08x %08x\n", x, mystique->dwgreg.ydst_lin, mystique->dwgreg.ar[1]); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + src = mystique->dwgreg.fcol; + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + +// pclog(" LINE %i %08x %08x\n", x, mystique->dwgreg.ydst_lin, mystique->dwgreg.ar[1]); + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + src = mystique->dwgreg.fcol; + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + +// pclog(" LINE %i %08x %08x\n", x, mystique->dwgreg.ydst_lin, mystique->dwgreg.ar[1]); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("LINE RSTR/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (mystique->dwgreg.sgn.sdydxl) + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + + if ((int32_t)mystique->dwgreg.ar[1] >= 0) + { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + if (mystique->dwgreg.sgn.sdydxl) + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + else + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + else + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + + mystique->dwgreg.length--; + } + break; + + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); + x = mystique->dwgreg.xdst; + while (mystique->dwgreg.length > 0) + { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + uint16_t z = ((int32_t)mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t *z_p = (uint16_t *)&svga->vram[(mystique->dwgreg.ydst_lin*2 + mystique->dwgreg.zorg) & mystique->vram_mask]; + uint16_t old_z = z_p[x]; + + if (z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK)) + { + int r = 0, g = 0, b = 0; + + if (z_write) + z_p[x] = z; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_16: + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 18) & 0x1f; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 17) & 0x3f; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 18) & 0x1f; + dst = (r << 11) | (g << 5) | b; + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + default: + fatal("LINE I/ZI PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + } + + if (mystique->dwgreg.sgn.sdydxl) + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + + if ((int32_t)mystique->dwgreg.ar[1] >= 0) + { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + if (mystique->dwgreg.sgn.sdydxl) + mystique->dwgreg.ydst_lin += (mystique->dwgreg.sgn.sdy ? -(mystique->dwgreg.pitch & PITCH_MASK) : (mystique->dwgreg.pitch & PITCH_MASK)); + else + x += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[3]; + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[15]; + } + else + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + + mystique->dwgreg.length--; + } + break; + + + default: + fatal("Unknown atype %03x %08x LINE\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + mystique->blitter_complete_refcount++; +} + +static void blit_autoline(mystique_t *mystique, int closed) +{ + int start_x = (int32_t)mystique->dwgreg.ar[5]; + int start_y = (int32_t)mystique->dwgreg.ar[6]; + int end_x = (int32_t)mystique->dwgreg.ar[0]; + int end_y = (int32_t)mystique->dwgreg.ar[2]; + int dx = end_x - start_x; + int dy = end_y - start_y; + + if (ABS(dx) > ABS(dy)) + { + mystique->dwgreg.sgn.sdydxl = 1; + mystique->dwgreg.ar[0] = 2*ABS(dy); + mystique->dwgreg.ar[1] = 2*ABS(dy) - ABS(dx) - ((start_y > end_y) ? 1 : 0); + mystique->dwgreg.ar[2] = 2*ABS(dy) - 2*ABS(dx); + mystique->dwgreg.length = ABS(end_x - start_x); + } + else + { + mystique->dwgreg.sgn.sdydxl = 0; + mystique->dwgreg.ar[0] = 2*ABS(dx); + mystique->dwgreg.ar[1] = 2*ABS(dx) - ABS(dy) - ((start_y > end_y) ? 1 : 0); + mystique->dwgreg.ar[2] = 2*ABS(dx) - 2*ABS(dy); + mystique->dwgreg.length = ABS(end_y - start_y); + } + mystique->dwgreg.sgn.sdxl = (start_x > end_x) ? 1 : 0; + mystique->dwgreg.sgn.sdy = (start_y > end_y) ? 1 : 0; + + +/* pclog("Autoline %s\n", closed ? "closed" : "open"); + pclog("Start %i,%i\n", start_x, start_y); + pclog("End %i,%i\n", end_x, end_y); + pclog("SGN=%x\n", mystique->dwgreg.sgn); + pclog("AR0=%08x AR1=%08x AR2=%08x\n", mystique->dwgreg.ar[0], + mystique->dwgreg.ar[1], + mystique->dwgreg.ar[2]); + pclog("Length %i\n", mystique->dwgreg.length);*/ + blit_line(mystique, closed); + + mystique->dwgreg.ar[5] = end_x; + mystique->dwgreg.xdst = end_x; + mystique->dwgreg.ar[6] = end_y; + mystique->dwgreg.ydst = end_y; + mystique->dwgreg.ydst_lin = ((int32_t)(int16_t)mystique->dwgreg.ydst * (mystique->dwgreg.pitch & PITCH_MASK)) + mystique->dwgreg.ydstorg; +} + +static void blit_trap(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint32_t z_back, r_back, g_back, b_back; + int z_write; + int y; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + + mystique->trap_count++; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_BLK: + case DWGCTRL_ATYPE_RPL: + //fxleft, fxright + //fcol +/* pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); + pclog("fcol=%08x\n", mystique->dwgreg.fcol); + pclog("ytop=%i length=%i\n", mystique->dwgreg.ytop, mystique->dwgreg.length); + pclog("pitch=%08x\n", mystique->dwgreg.pitch); + pclog("ydst_lin=%08x\n", mystique->dwgreg.ydst_lin);*/ +// if (!(mystique->dwgreg.dwgctrl_running & DWGCTRL_SGNZERO)) +// fatal("Not rectangle\n"); + + for (y = 0; y < mystique->dwgreg.length; y++) + { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int16_t x_l = mystique->dwgreg.fxleft & 0xffff; + int16_t x_r = mystique->dwgreg.fxright & 0xffff; + int yoff = (mystique->dwgreg.yoff + mystique->dwgreg.ydst) & 7; + +// pclog(" line %03i: %08x\n", y, mystique->dwgreg.ydst_lin); + while (x_l != x_r) + { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x_l & 3]) + { + int xoff = (mystique->dwgreg.xoff + x_l) & 7; + int pattern = mystique->dwgreg.pattern[yoff][xoff]; + uint32_t dst; + +// pclog(" %06x %02x\n", mystique->dwgreg.ydst_lin + x, mystique->dwgreg.fcol & 0xff); + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = + (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xff; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = + (pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffff; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + dst = *(uint32_t *)(&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) & 0xff000000; + *(uint32_t *)(&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) = + ((pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffffff) | dst; + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = + pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP BLK/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + x_l++; + mystique->pixel_count++; + } + + if ((int32_t)mystique->dwgreg.ar[1] < 0) + { + while ((int32_t)mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + } + else + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + if ((int32_t)mystique->dwgreg.ar[4] < 0) + { + while ((int32_t)mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) + { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + } + else + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + case DWGCTRL_ATYPE_RSTR: + for (y = 0; y < mystique->dwgreg.length; y++) + { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int16_t x_l = mystique->dwgreg.fxleft & 0xffff; + int16_t x_r = mystique->dwgreg.fxright & 0xffff; + int yoff = (mystique->dwgreg.yoff + mystique->dwgreg.ydst) & 7; + +// pclog(" line %03i: %08x\n", y, mystique->dwgreg.ydst_lin); + while (x_l != x_r) + { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x_l & 3]) + { + int xoff = (mystique->dwgreg.xoff + x_l) & 7; + int pattern = mystique->dwgreg.pattern[yoff][xoff]; + uint32_t src = pattern ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + uint32_t dst, old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); +// pclog(" %06x %02x\n", mystique->dwgreg.ydst_lin + x, mystique->dwgreg.fcol & 0xff); + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); +// pclog(" %06x %02x\n", mystique->dwgreg.ydst_lin + x, mystique->dwgreg.fcol & 0xff); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]; + + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running); +// pclog(" %06x %02x\n", mystique->dwgreg.ydst_lin + x, mystique->dwgreg.fcol & 0xff); + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l]; + + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running); +// pclog(" %06x %02x\n", mystique->dwgreg.ydst_lin + x, mystique->dwgreg.fcol & 0xff); + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP RSTR PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + x_l++; + mystique->pixel_count++; + } + + if ((int32_t)mystique->dwgreg.ar[1] < 0) + { + while ((int32_t)mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + } + else + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + if ((int32_t)mystique->dwgreg.ar[4] < 0) + { + while ((int32_t)mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) + { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + } + else + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); +/* pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); + pclog("fcol=%08x\n", mystique->dwgreg.fcol); + pclog("ytop=%i length=%i\n", mystique->dwgreg.ytop, mystique->dwgreg.length); + pclog("pitch=%08x\n", mystique->dwgreg.pitch); + pclog("ydst_lin=%08x\n", mystique->dwgreg.ydst_lin); + pclog("trap! maccess=%08x %08x %08x %08x\n", mystique->maccess_running, mystique->dwgreg.dr[4], mystique->dwgreg.dr[8], mystique->dwgreg.dr[12]);*/ + + for (y = 0; y < mystique->dwgreg.length; y++) + { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint16_t *z_p = (uint16_t *)&svga->vram[(mystique->dwgreg.ydst_lin*2 + mystique->dwgreg.zorg) & mystique->vram_mask]; + int16_t x_l = mystique->dwgreg.fxleft & 0xffff; + int16_t x_r = mystique->dwgreg.fxright & 0xffff; + int16_t old_x_l = x_l; + int dx; + + z_back = mystique->dwgreg.dr[0]; + r_back = mystique->dwgreg.dr[4]; + g_back = mystique->dwgreg.dr[8]; + b_back = mystique->dwgreg.dr[12]; + +// pclog(" line %03i: %08x\n", y, mystique->dwgreg.ydst_lin); + while (x_l != x_r) + { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x_l & 3]) + { + uint16_t z = ((int32_t)mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t old_z = z_p[x_l]; + + if (z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK)) + { + uint32_t dst = 0, old_dst; + int r = 0, g = 0, b = 0; + + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + r = (mystique->dwgreg.dr[4] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + g = (mystique->dwgreg.dr[8] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + b = (mystique->dwgreg.dr[12] >> 15) & 0xff; + + if (z_write) + z_p[x_l] = z; + +// pclog(" %06x %02x\n", mystique->dwgreg.ydst_lin + x, mystique->dwgreg.fcol & 0xff); + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + svga->vram[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = dither(mystique, r, g, b, x_l & 1, mystique->dwgreg.selline & 1); +// pclog(" %08x %08x %08x %04x\n", mystique->dwgreg.dr[4], mystique->dwgreg.dr[8], mystique->dwgreg.dr[12], dst); + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)(&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) & 0xff000000; + *(uint32_t *)(&svga->vram[((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask]) = old_dst | dst; + svga->changedvram[(((mystique->dwgreg.ydst_lin + x_l) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = b | (g << 8) | (r << 16); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("TRAP BLK/RPL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + } + + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + + x_l++; + mystique->pixel_count++; + } + + mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3]; + mystique->dwgreg.dr[4] = r_back + mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] = g_back + mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] = b_back + mystique->dwgreg.dr[15]; + + while ((int32_t)mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + while ((int32_t)mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) + { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + dx = (int16_t)((mystique->dwgreg.fxleft - old_x_l) & 0xffff); + mystique->dwgreg.dr[0] += dx*mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += dx*mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += dx*mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += dx*mystique->dwgreg.dr[14]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + default: + fatal("Unknown atype %03x %08x TRAP\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + mystique->blitter_complete_refcount++; +} + +static int texture_read(mystique_t *mystique, int *tex_r, int *tex_g, int *tex_b, int *atransp) +{ + svga_t *svga = &mystique->svga; + const int tex_shift = 3 + ((mystique->dwgreg.texctl & TEXCTL_TPITCH_MASK) >> TEXCTL_TPITCH_SHIFT); + const unsigned int palsel = mystique->dwgreg.texctl & TEXCTL_PALSEL_MASK; + const uint16_t tckey = mystique->dwgreg.textrans & TEXTRANS_TCKEY_MASK; + const uint16_t tkmask = (mystique->dwgreg.textrans & TEXTRANS_TKMASK_MASK) >> TEXTRANS_TKMASK_SHIFT; + const unsigned int w_mask = (mystique->dwgreg.texwidth & TEXWIDTH_TWMASK_MASK) >> TEXWIDTH_TWMASK_SHIFT; + const unsigned int h_mask = (mystique->dwgreg.texheight & TEXHEIGHT_THMASK_MASK) >> TEXHEIGHT_THMASK_SHIFT; + uint16_t src = 0; + int s, t; + + if (mystique->dwgreg.texctl & TEXCTL_NPCEN) + { + const int s_shift = 20 - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK); + const int t_shift = 20 - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK); + + s = (int32_t)mystique->dwgreg.tmr[6] >> s_shift; + t = (int32_t)mystique->dwgreg.tmr[7] >> t_shift; + } + else + { + const int s_shift = (20 + 16) - (mystique->dwgreg.texwidth & TEXWIDTH_TW_MASK); + const int t_shift = (20 + 16) - (mystique->dwgreg.texheight & TEXHEIGHT_TH_MASK); + int64_t q = mystique->dwgreg.tmr[8] ? ((0x100000000ll / (int64_t)(int32_t)mystique->dwgreg.tmr[8]) /*>> 16*/) : 0; + + s = (((int64_t)(int32_t)mystique->dwgreg.tmr[6] * q) /*<< 8*/) >> s_shift;/*((16+20)-12);*/ + t = (((int64_t)(int32_t)mystique->dwgreg.tmr[7] * q) /*<< 8*/) >> t_shift;/*((16+20)-9);*/ + } + + if (mystique->dwgreg.texctl & TEXCTL_CLAMPU) + { + if (s < 0) + s = 0; + else if (s > w_mask) + s = w_mask; + } + else + s &= w_mask; + + if (mystique->dwgreg.texctl & TEXCTL_CLAMPV) + { + if (t < 0) + t = 0; + else if (t > h_mask) + t = h_mask; + } + else + t &= h_mask; + + switch (mystique->dwgreg.texctl & TEXCTL_TEXFORMAT_MASK) + { + case TEXCTL_TEXFORMAT_TW4: + src = svga->vram[(mystique->dwgreg.texorg + (((t << tex_shift) + s) >> 1)) & mystique->vram_mask]; + if (s & 1) + src >>= 4; + else + src &= 0xf; + *tex_r = mystique->lut[src | palsel].r; + *tex_g = mystique->lut[src | palsel].g; + *tex_b = mystique->lut[src | palsel].b; + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW8: + src = svga->vram[(mystique->dwgreg.texorg + (t << tex_shift) + s) & mystique->vram_mask]; + *tex_r = mystique->lut[src].r; + *tex_g = mystique->lut[src].g; + *tex_b = mystique->lut[src].b; + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW15: + src = ((uint16_t *)svga->vram)[((mystique->dwgreg.texorg >> 1) + (t << tex_shift) + s) & mystique->vram_mask_w]; + *tex_r = ((src >> 10) & 0x1f) << 3; + *tex_g = ((src >> 5) & 0x1f) << 3; + *tex_b = (src & 0x1f) << 3; + if (((src >> 15) & mystique->dwgreg.ta_mask) == mystique->dwgreg.ta_key) + *atransp = 1; + else + *atransp = 0; + break; + case TEXCTL_TEXFORMAT_TW16: + src = ((uint16_t *)svga->vram)[((mystique->dwgreg.texorg >> 1) + (t << tex_shift) + s) & mystique->vram_mask_w]; + *tex_r = (src >> 11) << 3; + *tex_g = ((src >> 5) & 0x3f) << 2; + *tex_b = (src & 0x1f) << 3; + *atransp = 0; + break; + default: + fatal("Unknown texture format %i\n", mystique->dwgreg.texctl & TEXCTL_TEXFORMAT_MASK); + break; + } + + return ((src & tkmask) == tckey); +} + +static void blit_texture_trap(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + int y; + int z_write; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + const int dest32 = ((mystique->maccess_running & MACCESS_PWIDTH_MASK) == MACCESS_PWIDTH_32); + + mystique->trap_count++; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_I: + case DWGCTRL_ATYPE_ZI: + z_write = ((mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) == DWGCTRL_ATYPE_ZI); +// pclog("fxleft=%i fxright=%i texctl=%08x texorg=%08x ydst=%i len=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright, mystique->dwgreg.texctl, mystique->dwgreg.texorg, mystique->dwgreg.ydst, mystique->dwgreg.length); +/* pclog("fcol=%08x\n", mystique->dwgreg.fcol); + pclog("ytop=%i length=%i\n", mystique->dwgreg.ytop, mystique->dwgreg.length); + pclog("pitch=%08x\n", mystique->dwgreg.pitch); + pclog("ydst=%i ydst_lin=%08x\n", mystique->dwgreg.ydst, mystique->dwgreg.ydst_lin); + pclog("dYl =%08x errl =%08x -|dXl|=%08x\n", mystique->dwgreg.ar[0], mystique->dwgreg.ar[1], mystique->dwgreg.ar[2]); + pclog("errr=%08x -|dXr|=%08x dYr =%08x\n", mystique->dwgreg.ar[4], mystique->dwgreg.ar[5], mystique->dwgreg.ar[6]); + pclog(" q/wc=%08x q/wc/dX=%08x q/wc/dY=%08x\n", + mystique->dwgreg.tmr[8], mystique->dwgreg.tmr[4], mystique->dwgreg.tmr[5]); + pclog(" s/wc=%08x s/wc/dX=%08x s/wc/dY=%08x\n", + mystique->dwgreg.tmr[6], mystique->dwgreg.tmr[0], mystique->dwgreg.tmr[1]); + pclog(" t/wc=%08x t/wc/dX=%08x t/wc/dY=%08x\n", + mystique->dwgreg.tmr[7], mystique->dwgreg.tmr[2], mystique->dwgreg.tmr[3]);*/ + + for (y = 0; y < mystique->dwgreg.length; y++) + { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint16_t *z_p = (uint16_t *)&svga->vram[(mystique->dwgreg.ydst_lin*2 + mystique->dwgreg.zorg) & mystique->vram_mask]; + int16_t x_l = mystique->dwgreg.fxleft & 0xffff; + int16_t x_r = mystique->dwgreg.fxright & 0xffff; + int16_t old_x_l = x_l; + int dx; + + uint32_t z_back = mystique->dwgreg.dr[0]; + uint32_t r_back = mystique->dwgreg.dr[4]; + uint32_t g_back = mystique->dwgreg.dr[8]; + uint32_t b_back = mystique->dwgreg.dr[12]; + uint32_t s_back = mystique->dwgreg.tmr[6]; + uint32_t t_back = mystique->dwgreg.tmr[7]; + uint32_t q_back = mystique->dwgreg.tmr[8]; + +// pclog(" line %i: %i %i %08x %08x %08x %08x %i\n", __y, x_l, x_r, mystique->dwgreg.dr[0],mystique->dwgreg.dr[2],mystique->dwgreg.dr[3], mystique->dwgreg.ydst_lin*2 + mystique->dwgreg.zorg, z_write); +// pclog(" %08x %08x %08x\n", mystique->dwgreg.tmr[4],mystique->dwgreg.tmr[5], mystique->dwgreg.tmr[8]); +// pclog(" %08x %08x %08x\n", mystique->dwgreg.ar[4], mystique->dwgreg.ar[5], mystique->dwgreg.ar[6]); + + while (x_l != x_r) + { + if (x_l >= mystique->dwgreg.cxleft && x_l <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x_l & 3]) + { + uint16_t z = ((int32_t)mystique->dwgreg.dr[0] < 0) ? 0 : (mystique->dwgreg.dr[0] >> 15); + uint16_t old_z = z_p[x_l]; + + if (z_check(z, old_z, mystique->dwgreg.dwgctrl_running & DWGCTRL_ZMODE_MASK)) + { + int tex_r = 0, tex_g = 0, tex_b = 0; + int ctransp, atransp = 0; + int i_r = 0, i_g = 0, i_b = 0; + + if (!(mystique->dwgreg.dr[4] & (1 << 23))) + i_r = (mystique->dwgreg.dr[4] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[8] & (1 << 23))) + i_g = (mystique->dwgreg.dr[8] >> 15) & 0xff; + if (!(mystique->dwgreg.dr[12] & (1 << 23))) + i_b = (mystique->dwgreg.dr[12] >> 15) & 0xff; + + ctransp = texture_read(mystique, &tex_r, &tex_g, &tex_b, &atransp); + + switch (mystique->dwgreg.texctl & (TEXCTL_TMODULATE | TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY)) + { + case 0: + if (ctransp) + goto skip_pixel; + if (atransp) + { + tex_r = i_r; + tex_g = i_g; + tex_b = i_b; + } + break; + + case TEXCTL_DECALCKEY: + if (ctransp) + { + tex_r = i_r; + tex_g = i_g; + tex_b = i_b; + } + break; + + case (TEXCTL_STRANS | TEXCTL_DECALCKEY): + if (ctransp) + goto skip_pixel; + break; + + case TEXCTL_TMODULATE: + if (ctransp) + goto skip_pixel; + if (mystique->dwgreg.texctl & TEXCTL_TMODULATE) + { + tex_r = (tex_r * i_r) >> 8; + tex_g = (tex_g * i_g) >> 8; + tex_b = (tex_b * i_b) >> 8; + } + break; + + case (TEXCTL_TMODULATE | TEXCTL_STRANS): + if (ctransp || atransp) + goto skip_pixel; + if (mystique->dwgreg.texctl & TEXCTL_TMODULATE) + { + tex_r = (tex_r * i_r) >> 8; + tex_g = (tex_g * i_g) >> 8; + tex_b = (tex_b * i_b) >> 8; + } + break; + + + default: + fatal("Bad TEXCTL %08x %08x\n", mystique->dwgreg.texctl, mystique->dwgreg.texctl & (TEXCTL_TMODULATE | TEXCTL_STRANS | TEXCTL_ITRANS | TEXCTL_DECALCKEY)); + } + + if (dest32) + { + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l] = tex_b | (tex_g << 8) | (tex_r << 16); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_l) >> 10] = changeframecount; + } + else + { + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w] = dither(mystique, tex_r, tex_g, tex_b, x_l & 1, mystique->dwgreg.selline & 1); + svga->changedvram[((mystique->dwgreg.ydst_lin + x_l) & mystique->vram_mask_w) >> 11] = changeframecount; + } + if (z_write) + z_p[x_l] = z; + } + } +skip_pixel: + x_l++; + mystique->pixel_count++; + + mystique->dwgreg.dr[0] += mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += mystique->dwgreg.dr[14]; + mystique->dwgreg.tmr[6] += mystique->dwgreg.tmr[0]; + mystique->dwgreg.tmr[7] += mystique->dwgreg.tmr[2]; + mystique->dwgreg.tmr[8] += mystique->dwgreg.tmr[4]; + } + + mystique->dwgreg.dr[0] = z_back + mystique->dwgreg.dr[3]; + mystique->dwgreg.dr[4] = r_back + mystique->dwgreg.dr[7]; + mystique->dwgreg.dr[8] = g_back + mystique->dwgreg.dr[11]; + mystique->dwgreg.dr[12] = b_back + mystique->dwgreg.dr[15]; + mystique->dwgreg.tmr[6] = s_back + mystique->dwgreg.tmr[1]; + mystique->dwgreg.tmr[7] = t_back + mystique->dwgreg.tmr[3]; + mystique->dwgreg.tmr[8] = q_back + mystique->dwgreg.tmr[5]; + + while ((int32_t)mystique->dwgreg.ar[1] < 0 && mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[0]; + mystique->dwgreg.fxleft += (mystique->dwgreg.sgn.sdxl ? -1 : 1); + } + mystique->dwgreg.ar[1] += mystique->dwgreg.ar[2]; + + while ((int32_t)mystique->dwgreg.ar[4] < 0 && mystique->dwgreg.ar[6]) + { + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[6]; + mystique->dwgreg.fxright += (mystique->dwgreg.sgn.sdxr ? -1 : 1); + } + mystique->dwgreg.ar[4] += mystique->dwgreg.ar[5]; + + dx = (int16_t)((mystique->dwgreg.fxleft - old_x_l) & 0xffff); + mystique->dwgreg.dr[0] += dx*mystique->dwgreg.dr[2]; + mystique->dwgreg.dr[4] += dx*mystique->dwgreg.dr[6]; + mystique->dwgreg.dr[8] += dx*mystique->dwgreg.dr[10]; + mystique->dwgreg.dr[12] += dx*mystique->dwgreg.dr[14]; + mystique->dwgreg.tmr[6] += dx*mystique->dwgreg.tmr[0]; + mystique->dwgreg.tmr[7] += dx*mystique->dwgreg.tmr[2]; + mystique->dwgreg.tmr[8] += dx*mystique->dwgreg.tmr[4]; + + mystique->dwgreg.ydst++; + mystique->dwgreg.ydst &= 0x7fffff; + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + + mystique->dwgreg.selline = (mystique->dwgreg.selline + 1) & 7; + } + break; + + default: + fatal("Unknown atype %03x %08x TEXTURE_TRAP\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + + mystique->blitter_complete_refcount++; +} + +static void blit_bitblt(mystique_t *mystique) +{ + svga_t *svga = &mystique->svga; + uint32_t src_addr; + int y; + int x_dir = mystique->dwgreg.sgn.scanleft ? -1 : 1; + int16_t x_start = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxright : mystique->dwgreg.fxleft; + int16_t x_end = mystique->dwgreg.sgn.scanleft ? mystique->dwgreg.fxleft : mystique->dwgreg.fxright; + const int trans_sel = (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANS_MASK) >> DWGCTRL_TRANS_SHIFT; + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_BLK: +// if (mystique->maccess_running & MACCESS_TLUTLOAD) +// fatal("Bitblt TLUTLOAD BLK\n"); +// if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) +// fatal("BITBLT BLK with pattern\n"); + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BMONOLEF: +// pclog("ar0=%08x ar3=%08x ar5=%08x dwgctrl=%08x\n", mystique->dwgreg.ar[0], mystique->dwgreg.ar[3], mystique->dwgreg.ar[5], mystique->dwgreg.dwgctrl_running); +// pclog("fxleft=%i fxright=%i ydst=%i fcol=%08x bcol=%08x\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright, mystique->dwgreg.ydst, mystique->dwgreg.fcol, mystique->dwgreg.bcol); + + src_addr = mystique->dwgreg.ar[3]; +// mystique->dwgreg.bit_offset = 0; + + for (y = 0; y < mystique->dwgreg.length; y++) + { + int16_t x = x_start; + +// pclog(" line %03i: %08x %08x %02x\n", y, mystique->dwgreg.ydst_lin, src_addr, svga->vram[0x2eba3]); + while (1) + { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot) + { + uint32_t byte_addr = (src_addr >> 3) & mystique->vram_mask; + int bit_offset = src_addr & 7; + uint32_t old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: +// pclog(" pix %i %02x %i %i %06x\n", x, svga->vram[byte_addr], svga->vram[byte_addr] & (1 << bit_offset), mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC, byte_addr); + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) + { + if (svga->vram[byte_addr] & (1 << bit_offset)) + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = mystique->dwgreg.fcol; + } + else + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = + (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: +// pclog(" pix %i %02x %i %i %06x\n", x, svga->vram[byte_addr], svga->vram[byte_addr] & (1 << bit_offset), mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC, byte_addr); + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) + { + if (svga->vram[byte_addr] & (1 << bit_offset)) + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = mystique->dwgreg.fcol; + } + else + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = + (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; +// pclog(" pix %i %02x %i %i %06x\n", x, svga->vram[byte_addr], svga->vram[byte_addr] & (1 << bit_offset), mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC, byte_addr); + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) + { + if (svga->vram[byte_addr] & (1 << bit_offset)) + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = + (old_dst & 0xff000000) | (mystique->dwgreg.fcol & 0xffffff); + } + else + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = + (old_dst & 0xff000000) | (((svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol) & 0xffffff); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: +// pclog(" pix %i %02x %i %i %06x\n", x, svga->vram[byte_addr], svga->vram[byte_addr] & (1 << bit_offset), mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC, byte_addr); + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC) + { + if (svga->vram[byte_addr] & (1 << bit_offset)) + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & 0xfffff] = mystique->dwgreg.fcol; + } + else + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & 0xfffff] = + (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT DWGCTRL_ATYPE_BLK unknown MACCESS %i\n", mystique->maccess_running & MACCESS_PWIDTH_MASK); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } + else + src_addr += x_dir; + + if (x != x_end) + x += x_dir; + else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + default: + fatal("BITBLT BLK %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK); + break; + } + break; + + + case DWGCTRL_ATYPE_RPL: +// pclog(" bitblt RPL\n"); + if (mystique->maccess_running & MACCESS_TLUTLOAD) + { +// pclog("TLUTLOAD!\n"); + src_addr = mystique->dwgreg.ar[3]; + + y = mystique->dwgreg.ydst; + + while (mystique->dwgreg.length) + { + uint16_t src = ((uint16_t *)svga->vram)[src_addr & mystique->vram_mask_w]; +// pclog(" LUT[%02x]=VRAM[%05X]=%04x\n", y & 0xff, src_addr, src); + + mystique->lut[y & 0xff].r = (src >> 11) << 3; + mystique->lut[y & 0xff].g = ((src >> 5) & 0x3f) << 2; + mystique->lut[y & 0xff].b = (src & 0x1f) << 3; + src_addr++; + y++; + mystique->dwgreg.length--; + } + break; + } + case DWGCTRL_ATYPE_RSTR: +// pclog(" bitblt RPL or RSTR\n"); +// if (mystique->maccess_running & MACCESS_TLUTLOAD) +// fatal("Bitblt TLUTLOAD RSTR\n"); + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BMONOLEF: +// pclog("ar0=%08x ar3=%08x ar5=%08x\n", mystique->dwgreg.ar[0], mystique->dwgreg.ar[3], mystique->dwgreg.ar[5]); +// pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); + + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) + fatal("BITBLT RPL/RSTR BMONOLEF with pattern\n"); + + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) + { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + int16_t x = x_start; + +// pclog(" line %03i: %08x %08x\n", y, mystique->dwgreg.ydst_lin, src_addr); + while (1) + { + uint32_t byte_addr = (src_addr >> 3) & mystique->vram_mask; + int bit_offset = src_addr & 7; + + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + ((svga->vram[byte_addr] & (1 << bit_offset)) || !(mystique->dwgreg.dwgctrl_running & DWGCTRL_TRANSC)) && + trans[x & 3]) + { + uint32_t src = (svga->vram[byte_addr] & (1 << bit_offset)) ? mystique->dwgreg.fcol : mystique->dwgreg.bcol; + uint32_t dst, old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + +// pclog(" %02x %02x ", src, dst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK +// pclog("%08x %08x %i dst=%02x\n", src_addr, mystique->dwgreg.ydst_lin + x, mystique->dwgreg.sgn.scanleft, dst); + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + +// pclog(" %02x %02x ", src, dst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK +// pclog("%08x %08x %i dst=%02x\n", src_addr, mystique->dwgreg.ydst_lin + x, mystique->dwgreg.sgn.scanleft, dst); + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + +// pclog(" %02x %02x ", src, old_dst); + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK +// pclog("%08x %08x %i dst=%02x\n", src_addr, mystique->dwgreg.ydst_lin + x, mystique->dwgreg.sgn.scanleft, dst); + + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + +// pclog(" %02x %02x ", src, dst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK +// pclog("%08x %08x %i dst=%02x\n", src_addr, mystique->dwgreg.ydst_lin + x, mystique->dwgreg.sgn.scanleft, dst); + + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT RPL BMONOLEF PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (src_addr == mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } + else + src_addr += x_dir; + + if (x != x_end) + x += x_dir; + else + break; + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + + case DWGCTRL_BLTMOD_BFCOL: + case DWGCTRL_BLTMOD_BU32RGB: +// pclog("ar0=%08x ar3=%08x ar5=%08x\n", mystique->dwgreg.ar[0], mystique->dwgreg.ar[3], mystique->dwgreg.ar[5]); +// pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); + + src_addr = mystique->dwgreg.ar[3]; + + for (y = 0; y < mystique->dwgreg.length; y++) + { + uint8_t const * const trans = &trans_masks[trans_sel][(mystique->dwgreg.selline & 3) * 4]; + uint32_t old_src_addr = src_addr; + int16_t x = x_start; + +// pclog(" line %03i: %08x %08x\n", y, mystique->dwgreg.ydst_lin, src_addr); + while (1) + { + if (x >= mystique->dwgreg.cxleft && x <= mystique->dwgreg.cxright && + mystique->dwgreg.ydst_lin >= mystique->dwgreg.ytop && mystique->dwgreg.ydst_lin <= mystique->dwgreg.ybot && + trans[x & 3]) + { + uint32_t src, dst, old_dst; + + switch (mystique->maccess_running & MACCESS_PWIDTH_MASK) + { + case MACCESS_PWIDTH_8: + src = svga->vram[src_addr & mystique->vram_mask]; + dst = svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask]; + +// pclog(" %02x %02x ", src, dst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK +// pclog("%08x %08x %i dst=%02x\n", src_addr, mystique->dwgreg.ydst_lin + x, mystique->dwgreg.sgn.scanleft, dst); + + svga->vram[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_16: + src = ((uint16_t *)svga->vram)[src_addr & mystique->vram_mask_w]; + dst = ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w]; + +// pclog(" %02x %02x ", src, dst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK +// pclog("%08x %08x %i dst=%02x\n", src_addr, mystique->dwgreg.ydst_lin + x, mystique->dwgreg.sgn.scanleft, dst); + + ((uint16_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_w) >> 11] = changeframecount; + break; + + case MACCESS_PWIDTH_24: + src = *(uint32_t *)&svga->vram[(src_addr * 3) & mystique->vram_mask]; + old_dst = *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask]; + +// pclog(" %02x %02x ", src, old_dst); + dst = bitop(src, old_dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK +// pclog("%08x %08x %i dst=%02x\n", src_addr, mystique->dwgreg.ydst_lin + x, mystique->dwgreg.sgn.scanleft, dst); + + *(uint32_t *)&svga->vram[((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask] = (dst & 0xffffff) | (old_dst & 0xff000000); + svga->changedvram[(((mystique->dwgreg.ydst_lin + x) * 3) & mystique->vram_mask) >> 12] = changeframecount; + break; + + case MACCESS_PWIDTH_32: + src = ((uint32_t *)svga->vram)[src_addr & mystique->vram_mask_l]; + dst = ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l]; + +// pclog(" %02x %02x ", src, dst); + dst = bitop(src, dst, mystique->dwgreg.dwgctrl_running);// & DWGCTRL_BOP_MASK +// pclog("%08x %08x %i dst=%02x\n", src_addr, mystique->dwgreg.ydst_lin + x, mystique->dwgreg.sgn.scanleft, dst); + + ((uint32_t *)svga->vram)[(mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l] = dst; + svga->changedvram[((mystique->dwgreg.ydst_lin + x) & mystique->vram_mask_l) >> 10] = changeframecount; + break; + + default: + fatal("BITBLT RPL BFCOL PWIDTH %x %08x\n", mystique->maccess_running & MACCESS_PWIDTH_MASK, mystique->dwgreg.dwgctrl_running); + } + } + + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) + src_addr = ((src_addr + x_dir) & 7) | (src_addr & ~7); + else if (src_addr == mystique->dwgreg.ar[0]) + { + mystique->dwgreg.ar[0] += mystique->dwgreg.ar[5]; + mystique->dwgreg.ar[3] += mystique->dwgreg.ar[5]; + src_addr = mystique->dwgreg.ar[3]; + } + else + src_addr += x_dir; + + if (x != x_end) + x += x_dir; + else + break; + } + + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_PATTERN) + { + src_addr = old_src_addr; + if (mystique->dwgreg.sgn.sdy) + src_addr = ((src_addr - 32) & 0xe0) | (src_addr & ~0xe0); + else + src_addr = ((src_addr + 32) & 0xe0) | (src_addr & ~0xe0); + } + + if (mystique->dwgreg.sgn.sdy) + mystique->dwgreg.ydst_lin -= (mystique->dwgreg.pitch & PITCH_MASK); + else + mystique->dwgreg.ydst_lin += (mystique->dwgreg.pitch & PITCH_MASK); + } + break; + + default: + fatal("BITBLT DWGCTRL_ATYPE_RPL unknown BLTMOD %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + } + break; + + default: + fatal("Unknown BITBLT atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } + mystique->blitter_complete_refcount++; +} + +static void blit_iload(mystique_t *mystique) +{ +// if (mystique->maccess_running & MACCESS_TLUTLOAD) +// fatal("ILOAD TLUTLOAD\n"); + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_RPL: + case DWGCTRL_ATYPE_RSTR: + case DWGCTRL_ATYPE_BLK: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BFCOL: + case DWGCTRL_BLTMOD_BMONOLEF: + case DWGCTRL_BLTMOD_BMONOWF: + case DWGCTRL_BLTMOD_BU24RGB: +// pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); +// pclog("ytop=%i length=%i\n", mystique->dwgreg.ytop, mystique->dwgreg.length); + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + break; + + default: + fatal("ILOAD DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +static void blit_idump(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_RPL: +// pclog("ar0=%08x ar3=%08x ar5=%08x\n", mystique->dwgreg.ar[0], mystique->dwgreg.ar[3], mystique->dwgreg.ar[5]); +// pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.src_addr = mystique->dwgreg.ar[3]; + mystique->dwgreg.words = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.idump_end_of_line = 0; + mystique->busy = 1; + break; + + default: + fatal("Unknown IDUMP atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +static void blit_iload_scale(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BUYUV: +/* pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); + pclog("ytop=%i length=%i\n", mystique->dwgreg.ytop, mystique->dwgreg.length); + pclog("ar0=%08x\n", mystique->dwgreg.ar[0]); + pclog("ar2=%08x\n", mystique->dwgreg.ar[2]); + pclog("ar3=%08x\n", mystique->dwgreg.ar[3]); + pclog("ar5=%08x\n", mystique->dwgreg.ar[5]); + pclog("ar6=%08x\n", mystique->dwgreg.ar[6]);*/ + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + break; + + default: + fatal("ILOAD_SCALE DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_SCALE atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} +static void blit_iload_high(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BUYUV: +/* pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); + pclog("ytop=%i length=%i\n", mystique->dwgreg.ytop, mystique->dwgreg.length); + pclog("ar0=%08x\n", mystique->dwgreg.ar[0]); + pclog("ar2=%08x\n", mystique->dwgreg.ar[2]); + pclog("ar3=%08x\n", mystique->dwgreg.ar[3]); + pclog("ar5=%08x\n", mystique->dwgreg.ar[5]); + pclog("ar6=%08x\n", mystique->dwgreg.ar[6]);*/ + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + break; + + default: + fatal("ILOAD_HIGH DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_HIGH atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} +static void blit_iload_highv(mystique_t *mystique) +{ + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK) + { + case DWGCTRL_ATYPE_RPL: + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK) + { + case DWGCTRL_BLTMOD_BUYUV: +/* pclog("fxleft=%i fxright=%i\n", mystique->dwgreg.fxleft, mystique->dwgreg.fxright); + pclog("ytop=%i length=%i\n", mystique->dwgreg.ytop, mystique->dwgreg.length); + pclog("ar0=%08x\n", mystique->dwgreg.ar[0]); + pclog("ar2=%08x\n", mystique->dwgreg.ar[2]); + pclog("ar3=%08x\n", mystique->dwgreg.ar[3]); + pclog("ar5=%08x\n", mystique->dwgreg.ar[5]); + pclog("ar6=%08x\n", mystique->dwgreg.ar[6]);*/ + mystique->dwgreg.length_cur = mystique->dwgreg.length; + mystique->dwgreg.xdst = mystique->dwgreg.fxleft; + mystique->dwgreg.iload_rem_data = 0; + mystique->dwgreg.iload_rem_count = 0; + mystique->busy = 1; + mystique->dwgreg.words = 0; + mystique->dwgreg.highv_line = 0; + mystique->dwgreg.lastpix_r = 0; + mystique->dwgreg.lastpix_g = 0; + mystique->dwgreg.lastpix_b = 0; + break; + + default: + fatal("ILOAD_HIGHV DWGCTRL_ATYPE_RPL %08x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_BLTMOD_MASK, mystique->dwgreg.dwgctrl_running); + break; + } + break; + + default: + fatal("Unknown ILOAD_HIGHV atype %03x %08x\n", mystique->dwgreg.dwgctrl_running & DWGCTRL_ATYPE_MASK, mystique->dwgreg.dwgctrl_running); + } +} + +static void mystique_start_blit(mystique_t *mystique) +{ + uint64_t start_time = timer_read(); + uint64_t end_time; + + mystique->dwgreg.dwgctrl_running = mystique->dwgreg.dwgctrl; + mystique->maccess_running = mystique->maccess; +// pclog("start_blit %08x length=%i fxleft=%i fxright=%i %02x %i %i %i ylin=%08x ytop=%08x ybot=%08x\n", mystique->dwgreg.dwgctrl_running, mystique->dwgreg.length, mystique->dwgreg.fxleft, mystique->dwgreg.fxright, mystique->svga.vram[0x5c056], mystique->blitter_submit_refcount, mystique->blitter_submit_dma_refcount, mystique->blitter_complete_refcount, mystique->dwgreg.ydst_lin, mystique->dwgreg.ytop, mystique->dwgreg.ybot); + if (mystique->busy) + fatal("mystique_start_blit: mystique->busy!\n"); + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SOLID) + { + int x, y; + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + mystique->dwgreg.pattern[y][x] = 1; + } + mystique->dwgreg.src[0] = 0xffffffff; + mystique->dwgreg.src[1] = 0xffffffff; + mystique->dwgreg.src[2] = 0xffffffff; + mystique->dwgreg.src[3] = 0xffffffff; + } + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_ARZERO) + { + mystique->dwgreg.ar[0] = 0; + mystique->dwgreg.ar[1] = 0; + mystique->dwgreg.ar[2] = 0; + mystique->dwgreg.ar[4] = 0; + mystique->dwgreg.ar[5] = 0; + mystique->dwgreg.ar[6] = 0; + } + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SGNZERO) + { + mystique->dwgreg.sgn.sdydxl = 0; + mystique->dwgreg.sgn.scanleft = 0; + mystique->dwgreg.sgn.sdxl = 0; + mystique->dwgreg.sgn.sdy = 0; + mystique->dwgreg.sgn.sdxr = 0; + } + if (mystique->dwgreg.dwgctrl_running & DWGCTRL_SHTZERO) + { + mystique->dwgreg.funcnt = 0; + mystique->dwgreg.stylelen = 0; + mystique->dwgreg.xoff = 0; + mystique->dwgreg.yoff = 0; + } + + switch (mystique->dwgreg.dwgctrl_running & DWGCTRL_OPCODE_MASK) + { + case DWGCTRL_OPCODE_LINE_OPEN: + blit_line(mystique, 0); + break; + + case DWGCTRL_OPCODE_AUTOLINE_OPEN: + blit_autoline(mystique, 0); + break; + + case DWGCTRL_OPCODE_AUTOLINE_CLOSE: + blit_autoline(mystique, 1); + break; + + case DWGCTRL_OPCODE_TRAP: + blit_trap(mystique); + break; + + case DWGCTRL_OPCODE_TEXTURE_TRAP: + blit_texture_trap(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGH: + blit_iload_high(mystique); + break; + + case DWGCTRL_OPCODE_BITBLT: + blit_bitblt(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD: + blit_iload(mystique); + break; + + case DWGCTRL_OPCODE_IDUMP: + blit_idump(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_SCALE: + blit_iload_scale(mystique); + break; + + case DWGCTRL_OPCODE_ILOAD_HIGHV: + blit_iload_highv(mystique); + break; + + default: + fatal("mystique_start_blit: unknown blit %08x\n", mystique->dwgreg.dwgctrl_running); + } +// pclog("blit done\n"); + + end_time = timer_read(); + mystique->blitter_time += end_time - start_time; +} + + +static void mystique_hwcursor_draw(svga_t *svga, int displine) +{ + mystique_t *mystique = (mystique_t *)svga->p; + int x; + uint64_t dat[2]; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + + dat[0] = *(uint64_t *)(&svga->vram[svga->hwcursor_latch.addr]); + dat[1] = *(uint64_t *)(&svga->vram[svga->hwcursor_latch.addr + 8]); + svga->hwcursor_latch.addr += 16; + switch (mystique->xcurctrl & XCURCTRL_CURMODE_MASK) + { + case XCURCTRL_CURMODE_XGA: + for (x = 0; x < 64; x ++) + { + if (!(dat[1] & (1ull << 63))) + ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[0] & (1ull << 63)) ? mystique->cursor.col[1] : mystique->cursor.col[0]; + else if (dat[0] & (1ull << 63)) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + break; + } +} + + + + +static uint8_t mystique_pci_read(int func, int addr, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + +// pclog("mystique PCI read %08X\n", addr); + switch (addr) + { + case 0x00: return 0x2b; /*Matrox*/ + case 0x01: return 0x10; + + case 0x02: return 0x1a; /*MGA-1064SG*/ + case 0x03: return 0x05; + + case PCI_REG_COMMAND: + return mystique->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 0 << 1; /*Fast 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; /*Control aperture*/ + case 0x11: return (mystique->ctrl_base >> 8) & 0xc0; + case 0x12: return mystique->ctrl_base >> 16; + case 0x13: return mystique->ctrl_base >> 24; + + case 0x14: return 0x00; /*Linear frame buffer*/ + case 0x16: return (mystique->lfb_base >> 16) & 0x80; + case 0x17: return mystique->lfb_base >> 24; + + case 0x18: return 0x00; /*Pseudo-DMA (ILOAD)*/ + case 0x1a: return (mystique->iload_base >> 16) & 0x80; + case 0x1b: return mystique->iload_base >> 24; + + case 0x30: return mystique->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return mystique->pci_regs[0x32]; + case 0x33: return mystique->pci_regs[0x33]; + + case 0x3c: return mystique->int_line; + case 0x3d: return PCI_INTA; + + case 0x40: return mystique->pci_regs[0x40]; + case 0x41: return mystique->pci_regs[0x41]; + case 0x42: return mystique->pci_regs[0x42]; + case 0x43: return mystique->pci_regs[0x43]; + + case 0x44: return mystique->pci_regs[0x44]; + case 0x45: return mystique->pci_regs[0x45]; + + case 0x48: case 0x49: case 0x4a: case 0x4b: + addr = (mystique->pci_regs[0x44] & 0xfc) | + ((mystique->pci_regs[0x45] & 0x3f) << 8) | + (addr & 3); + return mystique_ctrl_read_b(addr, mystique); + } + return 0; +} + +static void mystique_pci_write(int func, int addr, uint8_t val, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + +// pclog("mystique_pci_write: func=%i addr=%02x val=%02x\n", func, addr, val); + switch (addr) + { + case PCI_REG_COMMAND: + mystique->pci_regs[PCI_REG_COMMAND] = val & 0x23; + mystique_recalc_mapping(mystique); + break; + + case 0x11: + mystique->ctrl_base = (mystique->ctrl_base & 0xffff0000) | ((val & 0xc0) << 8); + mystique_recalc_mapping(mystique); + break; + case 0x12: + mystique->ctrl_base = (mystique->ctrl_base & 0xff00c000) | (val << 16); + mystique_recalc_mapping(mystique); + break; + case 0x13: + mystique->ctrl_base = (mystique->ctrl_base & 0x00ffc000) | (val << 24); + mystique_recalc_mapping(mystique); + break; + + case 0x16: + mystique->lfb_base = (mystique->lfb_base & 0xff000000) | ((val & 0x80) << 16); + mystique_recalc_mapping(mystique); + break; + case 0x17: + mystique->lfb_base = (mystique->lfb_base & 0x00800000) | (val << 24); + mystique_recalc_mapping(mystique); + break; + + case 0x1a: + mystique->iload_base = (mystique->iload_base & 0xff000000) | ((val & 0x80) << 16); + mystique_recalc_mapping(mystique); + break; + case 0x1b: + mystique->iload_base = (mystique->iload_base & 0x00800000) | (val << 24); + mystique_recalc_mapping(mystique); + break; + + case 0x30: case 0x32: case 0x33: + mystique->pci_regs[addr] = val; + if (mystique->pci_regs[0x30] & 0x01) + { + uint32_t addr = (mystique->pci_regs[0x32] << 16) | (mystique->pci_regs[0x33] << 24); + mem_mapping_set_addr(&mystique->bios_rom.mapping, addr, 0x8000); + } + else + mem_mapping_disable(&mystique->bios_rom.mapping); + return; + + case 0x3c: + mystique->int_line = val; + return; + + case 0x40: case 0x41: case 0x42: case 0x43: + mystique->pci_regs[addr] = val; + break; + + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + mystique->pci_regs[addr-0x20] = val; + break; + + case 0x44: case 0x45: + mystique->pci_regs[addr] = val; + break; + + case 0x48: case 0x49: case 0x4a: case 0x4b: + addr = (mystique->pci_regs[0x44] & 0xfc) | + ((mystique->pci_regs[0x45] & 0x3f) << 8) | + (addr & 3); + mystique_ctrl_write_b(addr, val, mystique); + break; + } +} + +void *mystique_init() +{ + int c; + mystique_t *mystique = malloc(sizeof(mystique_t)); + memset(mystique, 0, sizeof(mystique_t)); + + rom_init(&mystique->bios_rom, "MYSTIQUE.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + mystique->vram_size = device_get_config_int("memory"); + mystique->vram_mask = (mystique->vram_size << 20) - 1; + mystique->vram_mask_w = mystique->vram_mask >> 1; + mystique->vram_mask_l = mystique->vram_mask >> 2; + + svga_init(&mystique->svga, mystique, mystique->vram_size << 20, + mystique_recalctimings, + mystique_in, mystique_out, + mystique_hwcursor_draw, + NULL); + + io_sethandler(0x03c0, 0x0020, mystique_in, NULL, NULL, mystique_out, NULL, NULL, mystique); + mem_mapping_add(&mystique->ctrl_mapping, 0, 0, + mystique_ctrl_read_b, NULL, mystique_ctrl_read_l, + mystique_ctrl_write_b, NULL, mystique_ctrl_write_l, + NULL, 0, mystique); + mem_mapping_add(&mystique->lfb_mapping, 0, 0, + svga_read_linear, svga_readw_linear, svga_readl_linear, + svga_write_linear, svga_writew_linear, svga_writel_linear, + NULL, 0, mystique); + mem_mapping_add(&mystique->iload_mapping, 0, 0, + mystique_iload_read_b, NULL, mystique_iload_read_l, + mystique_iload_write_b, NULL, mystique_iload_write_l, + NULL, 0, mystique); + + + mystique->card = pci_add(mystique_pci_read, mystique_pci_write, mystique); + mystique->pci_regs[0x2c] = mystique->bios_rom.rom[0x7ff8]; + mystique->pci_regs[0x2d] = mystique->bios_rom.rom[0x7ff8]; + mystique->pci_regs[0x2e] = mystique->bios_rom.rom[0x7ff8]; + mystique->pci_regs[0x2f] = mystique->bios_rom.rom[0x7ff8]; + + mystique->svga.miscout = 1; + mystique->pci_regs[0x41] = 0x01; /*vgaboot=1*/ + +// timer_add(&mystique->dma.timer, dma_callback, mystique, 1); + + for (c = 0; c < 256; c++) + { + dither5[c][0][0] = c >> 3; + dither5[c][1][1] = (c + 2) >> 3; + dither5[c][1][0] = (c + 4) >> 3; + dither5[c][0][1] = (c + 6) >> 3; + + if (dither5[c][1][1] > 31) + dither5[c][1][1] = 31; + if (dither5[c][1][0] > 31) + dither5[c][1][0] = 31; + if (dither5[c][0][1] > 31) + dither5[c][0][1] = 31; + + dither6[c][0][0] = c >> 2; + dither6[c][1][1] = (c + 1) >> 2; + dither6[c][1][0] = (c + 2) >> 2; + dither6[c][0][1] = (c + 3) >> 2; + + if (dither6[c][1][1] > 63) + dither6[c][1][1] = 63; + if (dither6[c][1][0] > 63) + dither6[c][1][0] = 63; + if (dither6[c][0][1] > 63) + dither6[c][0][1] = 63; + } + + mystique->wake_fifo_thread = thread_create_event(); + mystique->fifo_not_full_event = thread_create_event(); + mystique->fifo_thread = thread_create(fifo_thread, mystique); + mystique->dma.lock = thread_create_mutex(); + + timer_add(&mystique->wake_timer, mystique_wake_timer, (void *)mystique, 0); + timer_add(&mystique->softrap_pending_timer, mystique_softrap_pending_timer, (void *)mystique, 1); + + mystique->status = STATUS_ENDPRDMASTS; + + mystique->svga.vsync_callback = mystique_vsync_callback; + + return mystique; +} + +static int mystique_available() +{ + return rom_present("MYSTIQUE.VBI"); +} + +static void mystique_close(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + thread_kill(mystique->fifo_thread); + thread_destroy_event(mystique->wake_fifo_thread); + thread_destroy_event(mystique->fifo_not_full_event); + thread_destroy_mutex(mystique->dma.lock); + + svga_close(&mystique->svga); + + free(mystique); +} + +static void mystique_speed_changed(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + svga_recalctimings(&mystique->svga); +} + +static void mystique_force_redraw(void *p) +{ + mystique_t *mystique = (mystique_t *)p; + + mystique->svga.fullchange = changeframecount; +} + +static void mystique_add_status_info(char *s, int max_len, void *p) +{ + mystique_t *mystique = (mystique_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - mystique->status_time; + mystique->status_time = new_time; + + if (!status_diff) + status_diff = 1; + + svga_add_status_info(s, max_len, &mystique->svga); + sprintf(temps, "In %s mode\n%f Mpixels/sec\n%f ktraps/sec\n%f%% CPU\n%f%% CPU (real)\n\n", + (mystique->crtcext_regs[3] & CRTCX_R3_MGAMODE) ? "MGA" : "SVGA", + (double)mystique->pixel_count/1000000.0, + (double)mystique->trap_count/1000.0, + ((double)mystique->blitter_time * 100.0) / timer_freq, + ((double)mystique->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + mystique->pixel_count = mystique->trap_count = 0; + mystique->blitter_time = 0; +} + +static device_config_t mystique_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +device_t mystique_device = +{ + "Matrox Mystique", + DEVICE_NOT_WORKING, + mystique_init, + mystique_close, + mystique_available, + mystique_speed_changed, + mystique_force_redraw, + mystique_add_status_info, + mystique_config +}; diff --git a/src/vid_mga.h b/src/vid_mga.h new file mode 100644 index 0000000..278f7be --- /dev/null +++ b/src/vid_mga.h @@ -0,0 +1 @@ +extern device_t mystique_device; diff --git a/src/vid_olivetti_m24.c b/src/vid_olivetti_m24.c index 2cae92c..dc8a2e3 100644 --- a/src/vid_olivetti_m24.c +++ b/src/vid_olivetti_m24.c @@ -33,7 +33,8 @@ typedef struct m24_t uint16_t ma, maback; int dispon; - int dispontime, dispofftime, vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; } m24_t; @@ -100,9 +101,11 @@ uint8_t m24_in(uint16_t addr, void *p) void m24_write(uint32_t addr, uint8_t val, void *p) { m24_t *m24 = (m24_t *)p; + int offset = ((timer_get_remaining_u64(&m24->timer) / CGACONST) * 4) & 0xfc; + 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; + m24->charbuffer[offset] = val; + m24->charbuffer[offset | 1] = val; } uint8_t m24_read(uint32_t addr, void *p) @@ -129,8 +132,8 @@ void m24_recalctimings(m24_t *m24) _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)); + m24->dispontime = (uint64_t)_dispontime; + m24->dispofftime = (uint64_t)_dispofftime; } void m24_poll(void *p) @@ -142,13 +145,13 @@ void m24_poll(void *p) int oldvc; uint8_t chr, attr; uint16_t dat, dat2; - int cols[4]; + uint32_t 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; + timer_advance_u64(&m24->timer, m24->dispofftime); m24->stat |= 1; m24->linepos = 1; oldsc = m24->sc; @@ -167,15 +170,15 @@ void m24_poll(void *p) { 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; + ((uint32_t *)buffer32->line[m24->displine])[c] = cgapal[0]; + if (m24->cgamode & 1) ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 3) + 8] = cgapal[0]; + else ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 4) + 8] = cgapal[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; + ((uint32_t *)buffer32->line[m24->displine])[c] = cgapal[m24->cgacol & 15]; + if (m24->cgamode & 1) ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 3) + 8] = cgapal[m24->cgacol & 15]; + else ((uint32_t *)buffer32->line[m24->displine])[c + (m24->crtc[1] << 4) + 8] = cgapal[m24->cgacol & 15]; } } if (m24->cgamode & 1) @@ -187,25 +190,25 @@ void m24_poll(void *p) drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); if (m24->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; + cols[1] = cgapal[attr & 15]; + cols[0] = cgapal[(attr >> 4) & 7]; if ((m24->blink & 16) && (attr & 0x80) && !drawcursor) cols[1] = cols[0]; } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; + cols[1] = cgapal[attr & 15]; + cols[0] = cgapal[attr >> 4]; } 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; + ((uint32_t *)buffer32->line[m24->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; } 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]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; } m24->ma++; } @@ -219,52 +222,52 @@ void m24_poll(void *p) drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); if (m24->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; + cols[1] = cgapal[attr & 15]; + cols[0] = cgapal[(attr >> 4) & 7]; if ((m24->blink & 16) && (attr & 0x80)) cols[1] = cols[0]; } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; + cols[1] = cgapal[attr & 15]; + cols[0] = cgapal[attr >> 4]; } 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; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; } 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]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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; + cols[0] = cgapal[m24->cgacol & 15]; + col = (m24->cgacol & 16) ? 8 : 0; if (m24->cgamode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; + cols[1] = cgapal[col | 3]; + cols[2] = cgapal[col | 4]; + cols[3] = cgapal[col | 7]; } else if (m24->cgacol & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; + cols[1] = cgapal[col | 3]; + cols[2] = cgapal[col | 5]; + cols[3] = cgapal[col | 7]; } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; + cols[1] = cgapal[col | 2]; + cols[2] = cgapal[col | 4]; + cols[3] = cgapal[col | 6]; } for (x = 0; x < m24->crtc[1]; x++) { @@ -273,8 +276,8 @@ void m24_poll(void *p) 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]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -284,12 +287,14 @@ void m24_poll(void *p) if (m24->ctrl & 1) { dat2 = ((m24->sc & 1) * 0x4000) | (m24->lineff * 0x2000); - cols[0] = 0; cols[1] = /*(m24->cgacol & 15)*/15 + 16; + cols[0] = cgapal[0]; + cols[1] = cgapal[15]; } else { dat2 = (m24->sc & 1) * 0x2000; - cols[0] = 0; cols[1] = (m24->cgacol & 15) + 16; + cols[0] = cgapal[0]; + cols[1] = cgapal[m24->cgacol & 15]; } for (x = 0; x < m24->crtc[1]; x++) { @@ -297,7 +302,7 @@ void m24_poll(void *p) m24->ma++; for (c = 0; c < 16; c++) { - buffer->line[m24->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[m24->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -305,9 +310,9 @@ void m24_poll(void *p) } 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]); + cols[0] = cgapal[((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15)]; + if (m24->cgamode & 1) hline(buffer32, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]); } if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16; @@ -322,7 +327,7 @@ void m24_poll(void *p) else { // pclog("Line poll %i %i %i %i\n", m24_lineff, vc, sc, vadj); - m24->vidtime += m24->dispontime; + timer_advance_u64(&m24->timer, m24->dispontime); if (m24->dispon) m24->stat &= ~1; m24->linepos = 0; m24->lineff ^= 1; @@ -396,7 +401,7 @@ void m24_poll(void *p) updatewindowsize(xsize, ysize + 16); } - video_blit_memtoscreen_8(0, m24->firstline - 8, xsize, (m24->lastline - m24->firstline) + 16); + video_blit_memtoscreen(0, m24->firstline - 8, 0, (m24->lastline - m24->firstline) + 16, xsize, (m24->lastline - m24->firstline) + 16); frames++; video_res_x = xsize - 16; @@ -454,7 +459,7 @@ void *m24_init() m24->vram = malloc(0x8000); - timer_add(m24_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); + timer_add(&m24->timer, m24_poll, m24, 1); 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); return m24; diff --git a/src/vid_oti037.c b/src/vid_oti037.c new file mode 100644 index 0000000..eb06416 --- /dev/null +++ b/src/vid_oti037.c @@ -0,0 +1,246 @@ +/*Oak OTI037 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_oti037.h" +#include "vid_svga.h" + +typedef struct oti037_t +{ + svga_t svga; + + rom_t bios_rom; + + int index; + uint8_t regs[32]; + + uint8_t enable_register; +} oti037_t; + +void oti037_out(uint16_t addr, uint8_t val, void *p) +{ + oti037_t *oti037 = (oti037_t *)p; + svga_t *svga = &oti037->svga; + uint8_t old; + uint8_t idx; + + if (!(oti037->enable_register & 1) && addr != 0x3C3) + return; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; // mono / color addr selection + +// pclog("oti037_out : %04X %02X %02X %i ", addr, val, ram[0x489], ins); +// pclog(" %04X:%04X\n", CS,cpu_state.pc); + switch (addr) + { + case 0x3C3: + oti037->enable_register = val & 1; + return; + case 0x3D4: + svga->crtcreg = val /*& 31*/; // fixme: bios wants to set the test bit? + return; + case 0x3D5: + if (((svga->crtcreg & 31) < 7) && (svga->crtc[0x11] & 0x80)) + return; + if (((svga->crtcreg & 31) == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg & 31]; + svga->crtc[svga->crtcreg & 31] = val; + if (old != val) + { + if ((svga->crtcreg & 31) < 0xE || (svga->crtcreg & 31) > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x3DE: + oti037->index = val /*& 0x1f*/; + return; + case 0x3DF: + idx = oti037->index & 0x1f; + oti037->regs[idx] = val; + switch (idx) + { + case 0xD: + if (val & 0x80) + mem_mapping_disable(&svga->mapping); + else + mem_mapping_enable(&svga->mapping); + break; + case 0x11: + svga->read_bank = (val & 0xf) * 65536; + svga->write_bank = (val >> 4) * 65536; + break; + } + return; + } + svga_out(addr, val, svga); +} + +uint8_t oti037_in(uint16_t addr, void *p) +{ + oti037_t *oti037 = (oti037_t *)p; + svga_t *svga = &oti037->svga; + uint8_t temp; + + if (!(oti037->enable_register & 1) && addr != 0x3C3) + return 0xff; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; // mono / color addr selection + +// if (addr != 0x3da && addr != 0x3ba) pclog("oti037_in : %04X ", addr); + + switch (addr) + { + case 0x3C3: + temp = oti037->enable_register; + break; + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg & 31]; + break; + + case 0x3DA: + svga->attrff = 0; + + /*The OTI-037C BIOS waits for bits 0 and 3 in 0x3da to go low, then reads 0x3da again + and expects the diagnostic bits to equal the current border colour. As I understand + it, the 0x3da active enable status does not include the border time, so this may be + an area where OTI-037C is not entirely VGA compatible.*/ + svga->cgastat &= ~0x30; + /* copy color diagnostic info from the overscan color register */ + switch (svga->attrregs[0x12] & 0x30) + { + case 0x00: /* P0 and P2 */ + if (svga->attrregs[0x11] & 0x01) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x04) + svga->cgastat |= 0x20; + break; + case 0x10: /* P4 and P5 */ + if (svga->attrregs[0x11] & 0x10) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x20) + svga->cgastat |= 0x20; + break; + case 0x20: /* P1 and P3 */ + if (svga->attrregs[0x11] & 0x02) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x08) + svga->cgastat |= 0x20; + break; + case 0x30: /* P6 and P7 */ + if (svga->attrregs[0x11] & 0x40) + svga->cgastat |= 0x10; + if (svga->attrregs[0x11] & 0x80) + svga->cgastat |= 0x20; + break; + } + return svga->cgastat; + + + case 0x3DE: + temp = oti037->index; + break; + case 0x3DF: + if ((oti037->index & 0x1f)==0x10) temp = 0x18; + else temp = oti037->regs[oti037->index & 0x1f]; + break; + + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da && addr != 0x3ba) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); + return temp; +} + +void oti037_recalctimings(svga_t *svga) +{ + oti037_t *oti037 = (oti037_t *)svga->p; + + if (oti037->regs[0x14] & 0x08) svga->ma_latch |= 0x10000; + if (oti037->regs[0x0d] & 0x0c) svga->rowoffset <<= 1; + svga->interlace = oti037->regs[0x14] & 0x80; +} + +void *oti037_common_init(char *bios_fn, int vram_size) +{ + oti037_t *oti037 = malloc(sizeof(oti037_t)); + memset(oti037, 0, sizeof(oti037_t)); + + rom_init(&oti037->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&oti037->svga, oti037, vram_size << 10, + oti037_recalctimings, + oti037_in, oti037_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, oti037_in, NULL, NULL, oti037_out, NULL, NULL, oti037); + + oti037->svga.miscout = 1; + oti037->regs[0] = 0x08; // fixme: bios wants to read this at index 0? this index is undocumented + return oti037; +} + +void *oti037_init() +{ + return oti037_common_init("oti037/bios.bin", 256); +} + +static int oti037_available() +{ + return rom_present("oti037/bios.bin"); +} + +void oti037_close(void *p) +{ + oti037_t *oti037 = (oti037_t *)p; + + svga_close(&oti037->svga); + + free(oti037); +} + +void oti037_speed_changed(void *p) +{ + oti037_t *oti037 = (oti037_t *)p; + + svga_recalctimings(&oti037->svga); +} + +void oti037_force_redraw(void *p) +{ + oti037_t *oti037 = (oti037_t *)p; + + oti037->svga.fullchange = changeframecount; +} + +void oti037_add_status_info(char *s, int max_len, void *p) +{ + oti037_t *oti037 = (oti037_t *)p; + + svga_add_status_info(s, max_len, &oti037->svga); +} + +device_t oti037_device = +{ + "Oak OTI-037", + 0, + oti037_init, + oti037_close, + oti037_available, + oti037_speed_changed, + oti037_force_redraw, + oti037_add_status_info +}; diff --git a/src/vid_oti037.h b/src/vid_oti037.h new file mode 100644 index 0000000..e20e296 --- /dev/null +++ b/src/vid_oti037.h @@ -0,0 +1 @@ +extern device_t oti037_device; diff --git a/src/vid_oti067.c b/src/vid_oti067.c index 6d8b8a6..8494e6d 100644 --- a/src/vid_oti067.c +++ b/src/vid_oti067.c @@ -8,6 +8,7 @@ #include "video.h" #include "vid_oti067.h" #include "vid_svga.h" +#include "acer386sx.h" typedef struct oti067_t { @@ -19,6 +20,7 @@ typedef struct oti067_t uint8_t regs[32]; uint8_t pos; + uint8_t dipswitch_val; uint32_t vram_size; uint32_t vram_mask; @@ -37,9 +39,11 @@ void oti067_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3D4: - svga->crtcreg = val & 31; + svga->crtcreg = val & 0x3f; return; case 0x3D5: + if (svga->crtcreg & 0x20) + return; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -64,13 +68,13 @@ void oti067_out(uint16_t addr, uint8_t val, void *p) switch (oti067->index) { case 0xD: - svga->vrammask = (val & 0xc) ? oti067->vram_mask : 0x3ffff; + svga->vram_display_mask = (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; + svga->vram_display_mask = 0x3ffff; break; case 0x11: svga->read_bank = (val & 0xf) * 65536; @@ -98,14 +102,17 @@ uint8_t oti067_in(uint16_t addr, void *p) temp = svga->crtcreg; break; case 0x3D5: - temp = svga->crtc[svga->crtcreg]; + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg]; break; case 0x3DE: temp = oti067->index | (2 << 5); break; case 0x3DF: - if (oti067->index==0x10) temp = 0x18; + if (oti067->index==0x10) temp = oti067->dipswitch_val; else temp = oti067->regs[oti067->index]; break; @@ -168,28 +175,54 @@ void *oti067_common_init(char *bios_fn, int vram_size) io_sethandler(0x46e8, 0x0001, oti067_pos_in, NULL, NULL, oti067_pos_out, NULL, NULL, oti067); oti067->svga.miscout = 1; + + oti067->dipswitch_val = 0x18; return oti067; } +void oti067_enable_disable(void *p, int enable) +{ + oti067_t *oti067 = (oti067_t *)p; + + mem_mapping_disable(&oti067->bios_rom.mapping); + io_removehandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067); + io_removehandler(0x46e8, 0x0001, oti067_pos_in, NULL, NULL, oti067_pos_out, NULL, NULL, oti067); + mem_mapping_disable(&oti067->svga.mapping); + if (enable) + { + mem_mapping_enable(&oti067->bios_rom.mapping); + 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); + mem_mapping_enable(&oti067->svga.mapping); + } +} + void *oti067_init() { int vram_size = device_get_config_int("memory"); - return oti067_common_init("roms/oti067/bios.bin", vram_size); + return oti067_common_init("oti067/bios.bin", vram_size); } void *oti067_acer386_init() { - oti067_t *oti067 = oti067_common_init("roms/acer386/oti067.bin", 512); + oti067_t *oti067 = oti067_common_init("acer386/oti067.bin", 512); - if (oti067) - oti067->bios_rom.rom[0x5d] = 0x74; - + acer386sx_set_oti067(oti067); + + return oti067; +} + +void *oti067_ama932j_init() +{ + oti067_t *oti067 = oti067_common_init("ama932j/oti067.bin", 512); + + oti067->dipswitch_val |= 0x20; return oti067; } static int oti067_available() { - return rom_present("roms/oti067/bios.bin"); + return rom_present("oti067/bios.bin"); } void oti067_close(void *p) @@ -272,3 +305,14 @@ device_t oti067_acer386_device = oti067_force_redraw, oti067_add_status_info }; +device_t oti067_ama932j_device = +{ + "Oak OTI-067 (AMA-932J)", + 0, + oti067_ama932j_init, + oti067_close, + oti067_available, + oti067_speed_changed, + oti067_force_redraw, + oti067_add_status_info +}; diff --git a/src/vid_oti067.h b/src/vid_oti067.h index 81d4358..8376b38 100644 --- a/src/vid_oti067.h +++ b/src/vid_oti067.h @@ -1,2 +1,5 @@ extern device_t oti067_device; extern device_t oti067_acer386_device; +extern device_t oti067_ama932j_device; + +void oti067_enable_disable(void *p, int enable); diff --git a/src/vid_paradise.c b/src/vid_paradise.c index dc90657..369fb34 100644 --- a/src/vid_paradise.c +++ b/src/vid_paradise.c @@ -1,6 +1,6 @@ /*Paradise VGA emulation - PC2086, PC3086 use PVGA1A + PC2086, PC3086, GO481 use PVGA1A MegaPC uses W90C11A */ #include @@ -14,6 +14,7 @@ #include "vid_svga.h" #include "vid_svga_render.h" #include "vid_unk_ramdac.h" +#include "wd76c10.h" typedef struct paradise_t { @@ -30,10 +31,10 @@ typedef struct paradise_t 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); +uint8_t paradise_in(uint16_t addr, void *p); void paradise_out(uint16_t addr, uint8_t val, void *p) { @@ -100,21 +101,20 @@ void paradise_out(uint16_t addr, uint8_t val, void *p) paradise_remap(paradise); return; } - if (svga->gdcaddr == 0xe) + if (svga->gdcaddr == 0xb) { - svga->gdcreg[0xe] = val; + svga->gdcreg[0xb] = val; paradise_remap(paradise); return; } break; case 0x3D4: - if (paradise->type == PVGA1A) - svga->crtcreg = val & 0x1f; - else - svga->crtcreg = val & 0x3f; + svga->crtcreg = val & 0x3f; return; case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -135,6 +135,16 @@ void paradise_out(uint16_t addr, uint8_t val, void *p) } } break; + + case 0x46e8: + io_removehandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + mem_mapping_disable(¶dise->svga.mapping); + if (val & 8) + { + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + mem_mapping_enable(¶dise->svga.mapping); + } + break; } svga_out(addr, val, svga); } @@ -180,6 +190,8 @@ uint8_t paradise_in(uint16_t addr, void *p) case 0x3D4: return svga->crtcreg; case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return 0xff; if (svga->crtcreg > 0x29 && svga->crtcreg < 0x30 && (svga->crtc[0x29] & 0x88) != 0x80) return 0xff; return svga->crtc[svga->crtcreg]; @@ -199,11 +211,11 @@ void paradise_remap(paradise_t *paradise) 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) + else if (svga->gdcreg[0xb] & 0x08) { if (svga->gdcreg[0x6] & 0xc) { -// pclog("Remap 2\n"); +// 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); @@ -226,7 +238,10 @@ void paradise_remap(paradise_t *paradise) 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]); + paradise->read_bank[1] &= 0x7ffff; + paradise->write_bank[1] &= 0x7ffff; + +// pclog("Remap - %04X %04X %04x %04x\n", paradise->read_bank[0], paradise->write_bank[0], paradise->read_bank[1], paradise->write_bank[1]); } void paradise_recalctimings(svga_t *svga) @@ -236,7 +251,7 @@ void paradise_recalctimings(svga_t *svga) svga->render = svga_render_8bpp_highres; } -void paradise_write(uint32_t addr, uint8_t val, void *p) +static void paradise_write(uint32_t addr, uint8_t val, void *p) { paradise_t *paradise = (paradise_t *)p; // pclog("paradise_write : %05X %02X ", addr, val); @@ -244,8 +259,14 @@ void paradise_write(uint32_t addr, uint8_t val, void *p) // pclog("%08X\n", addr); svga_write_linear(addr, val, ¶dise->svga); } +static void paradise_writew(uint32_t addr, uint16_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; + svga_writew_linear(addr, val, ¶dise->svga); +} -uint8_t paradise_read(uint32_t addr, void *p) +static uint8_t paradise_read(uint32_t addr, void *p) { paradise_t *paradise = (paradise_t *)p; // pclog("paradise_read : %05X ", addr); @@ -253,6 +274,12 @@ uint8_t paradise_read(uint32_t addr, void *p) // pclog("%08X\n", addr); return svga_read_linear(addr, ¶dise->svga); } +static uint16_t paradise_readw(uint32_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; + return svga_readw_linear(addr, ¶dise->svga); +} void *paradise_pvga1a_init() { @@ -268,7 +295,7 @@ void *paradise_pvga1a_init() NULL, NULL); - mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); mem_mapping_set_p(¶dise->svga.mapping, paradise); svga->crtc[0x31] = 'W'; @@ -299,7 +326,7 @@ void *paradise_wd90c11_init() NULL, NULL); - mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); mem_mapping_set_p(¶dise->svga.mapping, paradise); svga->crtc[0x31] = 'W'; @@ -323,7 +350,7 @@ 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); + rom_init(¶dise->bios_rom, "pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } @@ -332,7 +359,7 @@ 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); + rom_init(¶dise->bios_rom, "pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } @@ -343,13 +370,28 @@ static void *paradise_wd90c11_megapc_init() if (paradise) rom_init_interleaved(¶dise->bios_rom, - "roms/megapc/41651-bios lo.u18", - "roms/megapc/211253-bios hi.u19", + "megapc/41651-bios lo.u18", + "megapc/211253-bios hi.u19", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); return paradise; } +static void *paradise_pvga1a_oli_go481_init() +{ + paradise_t *paradise = paradise_pvga1a_init(); + + if (paradise) + rom_init_interleaved(¶dise->bios_rom, + "oli_go481_lo.bin", + "oli_go481_hi.bin", + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x46e8, 0x0001, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + return paradise; +} + void paradise_close(void *p) { paradise_t *paradise = (paradise_t *)p; @@ -380,6 +422,11 @@ void paradise_add_status_info(char *s, int max_len, void *p) svga_add_status_info(s, max_len, ¶dise->svga); } +static int oli_go481_available() +{ + return (rom_present("oli_go481_lo.bin") && rom_present("oli_go481_hi.bin")); +} + device_t paradise_pvga1a_pc2086_device = { "Paradise PVGA1A (Amstrad PC2086)", @@ -413,3 +460,14 @@ device_t paradise_wd90c11_megapc_device = paradise_force_redraw, paradise_add_status_info }; +device_t paradise_pvga1a_oli_go481_device = +{ + "Paradise PVGA1A (Olivetti GO481)", + 0, + paradise_pvga1a_oli_go481_init, + paradise_close, + oli_go481_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; diff --git a/src/vid_paradise.h b/src/vid_paradise.h index e25d5b3..c007f5a 100644 --- a/src/vid_paradise.h +++ b/src/vid_paradise.h @@ -1,3 +1,4 @@ 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_pvga1a_oli_go481_device; diff --git a/src/vid_pc1512.c b/src/vid_pc1512.c index 79ac43d..35ffa20 100644 --- a/src/vid_pc1512.c +++ b/src/vid_pc1512.c @@ -26,6 +26,7 @@ typedef struct pc1512_t uint8_t plane_write, plane_read, border; + int fontbase; int linepos, displine; int sc, vc; int cgadispon; @@ -35,7 +36,8 @@ typedef struct pc1512_t int dispon; int blink; - int dispontime, dispofftime, vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; uint8_t *vram; @@ -56,10 +58,10 @@ static void pc1512_out(uint16_t addr, uint8_t val, void *p) // pclog("PC1512 out %04X %02X %04X:%04X\n",addr,val,CS,pc); switch (addr) { - case 0x3d4: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: pc1512->crtcreg = val & 31; return; - case 0x3d5: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: old = pc1512->crtc[pc1512->crtcreg]; pc1512->crtc[pc1512->crtcreg] = val & crtcmask[pc1512->crtcreg]; if (old != val) @@ -105,7 +107,8 @@ static uint8_t pc1512_in(uint16_t addr, void *p) case 0x3d5: return pc1512->crtc[pc1512->crtcreg]; case 0x3da: - return pc1512->stat; + pc1512->stat ^= 0x01; /*Bit 0 is toggle bit on PC1512*/ + return pc1512->stat ^ 0x01; } return 0xff; } @@ -146,15 +149,15 @@ static uint8_t pc1512_read(uint32_t addr, void *p) static void pc1512_recalctimings(pc1512_t *pc1512) { double _dispontime, _dispofftime, disptime; - disptime = 128; /*Fixed on PC1512*/ + disptime = 114; /*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)); + pc1512->dispontime = (uint64_t)_dispontime; + pc1512->dispofftime = (uint64_t)_dispofftime; } static void pc1512_poll(void *p) @@ -171,8 +174,7 @@ static void pc1512_poll(void *p) if (!pc1512->linepos) { - pc1512->vidtime += pc1512->dispofftime; - pc1512->stat |= 1; + timer_advance_u64(&pc1512->timer, pc1512->dispofftime); pc1512->linepos = 1; oldsc = pc1512->sc; if (pc1512->dispon) @@ -187,15 +189,15 @@ static void pc1512_poll(void *p) { 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; + ((uint32_t *)buffer32->line[pc1512->displine])[c] = cgapal[pc1512->border & 15]; + if (pc1512->cgamode & 1) ((uint32_t *)buffer32->line[pc1512->displine])[c + (pc1512->crtc[1] << 3) + 8] = 0; + else ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[pc1512->displine])[c] = cgapal[pc1512->cgacol & 15]; + if (pc1512->cgamode & 1) ((uint32_t *)buffer32->line[pc1512->displine])[c + (pc1512->crtc[1] << 3) + 8] = cgapal[pc1512->cgacol & 15]; + else ((uint32_t *)buffer32->line[pc1512->displine])[c + (pc1512->crtc[1] << 4) + 8] = cgapal[pc1512->cgacol & 15]; } } if (pc1512->cgamode & 1) @@ -207,25 +209,25 @@ static void pc1512_poll(void *p) drawcursor = ((pc1512->ma == ca) && pc1512->con && pc1512->cursoron); if (pc1512->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; + cols[1] = cgapal[attr & 15]; + cols[0] = cgapal[(attr >> 4) & 7]; if ((pc1512->blink & 16) && (attr & 0x80) && !drawcursor) cols[1] = cols[0]; } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; + cols[1] = cgapal[attr & 15]; + cols[0] = cgapal[attr >> 4]; } 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; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 3) + c + 8] = cols[(fontdat[chr + pc1512->fontbase][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; } 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]; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 3) + c + 8] = cols[(fontdat[chr + pc1512->fontbase][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; } pc1512->ma++; } @@ -239,52 +241,52 @@ static void pc1512_poll(void *p) drawcursor = ((pc1512->ma == ca) && pc1512->con && pc1512->cursoron); if (pc1512->cgamode & 0x20) { - cols[1] = (attr & 15) + 16; - cols[0] = ((attr >> 4) & 7) + 16; + cols[1] = cgapal[attr & 15]; + cols[0] = cgapal[(attr >> 4) & 7]; if ((pc1512->blink & 16) && (attr & 0x80)) cols[1] = cols[0]; } else { - cols[1] = (attr & 15) + 16; - cols[0] = (attr >> 4) + 16; + cols[1] = cgapal[attr & 15]; + cols[0] = cgapal[attr >> 4]; } 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; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + pc1512->fontbase][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; } 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]; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + pc1512->fontbase][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; + cols[0] = cgapal[pc1512->cgacol & 15]; + col = (pc1512->cgacol & 16) ? 8 : 0; if (pc1512->cgamode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; + cols[1] = cgapal[col | 3]; + cols[2] = cgapal[col | 4]; + cols[3] = cgapal[col | 7]; } else if (pc1512->cgacol & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; + cols[1] = cgapal[col | 3]; + cols[2] = cgapal[col | 5]; + cols[3] = cgapal[col | 7]; } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; + cols[1] = cgapal[col | 2]; + cols[2] = cgapal[col | 4]; + cols[3] = cgapal[col | 6]; } for (x = 0; x < 40; x++) { @@ -292,8 +294,8 @@ static void pc1512_poll(void *p) 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]; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -311,7 +313,7 @@ static void pc1512_poll(void *p) 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; + ((uint32_t *)buffer32->line[pc1512->displine])[(x << 4) + c + 8] = cgapal[((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (pc1512->cgacol & 15)]; dat <<= 1; dat2 <<= 1; dat3 <<= 1; @@ -322,9 +324,9 @@ static void pc1512_poll(void *p) } 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]); + cols[0] = cgapal[((pc1512->cgamode & 0x12) == 0x12) ? 0 : (pc1512->cgacol & 15)]; + if (pc1512->cgamode & 1) hline(buffer32, 0, pc1512->displine, (pc1512->crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, pc1512->displine, (pc1512->crtc[1] << 4) + 16, cols[0]); } pc1512->sc = oldsc; @@ -337,11 +339,9 @@ static void pc1512_poll(void *p) } else { - pc1512->vidtime += pc1512->dispontime; + timer_advance_u64(&pc1512->timer, 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) { @@ -402,7 +402,7 @@ static void pc1512_poll(void *p) updatewindowsize(xsize, (ysize << 1) + 16); } - video_blit_memtoscreen_8(0, pc1512->firstline - 4, xsize, (pc1512->lastline - pc1512->firstline) + 8); + video_blit_memtoscreen(0, pc1512->firstline - 4, 0, (pc1512->lastline - pc1512->firstline) + 8, 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); @@ -451,6 +451,7 @@ static void pc1512_poll(void *p) static void *pc1512_init() { + int display_type; pc1512_t *pc1512 = malloc(sizeof(pc1512_t)); memset(pc1512, 0, sizeof(pc1512_t)); @@ -458,10 +459,13 @@ static void *pc1512_init() pc1512->cgacol = 7; pc1512->cgamode = 0x12; - - timer_add(pc1512_poll, &pc1512->vidtime, TIMER_ALWAYS_ENABLED, pc1512); + pc1512->fontbase = (device_get_config_int("codepage") & 3) * 256; + display_type = device_get_config_int("display_type"); + + timer_add(&pc1512->timer, pc1512_poll, pc1512, 1); 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); + cgapal_rebuild(display_type, 0); return pc1512; } @@ -480,6 +484,57 @@ static void pc1512_speed_changed(void *p) pc1512_recalctimings(pc1512); } +device_config_t pc1512_config[] = +{ + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "PC-CM (Colour)", + .value = DISPLAY_RGB + }, + { + .description = "PC-MM (Monochrome)", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + } + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "US English", + .value = 3 + }, + { + .description = "Danish", + .value = 1 + }, + { + .description = "Greek", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 3 + }, + { + .type = -1 + } +}; + + device_t pc1512_device = { "Amstrad PC1512 (video)", @@ -489,5 +544,6 @@ device_t pc1512_device = NULL, pc1512_speed_changed, NULL, - NULL + NULL, + pc1512_config }; diff --git a/src/vid_pc1640.c b/src/vid_pc1640.c index e7327e1..dd92d57 100644 --- a/src/vid_pc1640.c +++ b/src/vid_pc1640.c @@ -23,7 +23,8 @@ typedef struct pc1640_t rom_t bios_rom; int cga_enabled; - int dispontime, dispofftime, vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; } pc1640_t; void pc1640_out(uint16_t addr, uint8_t val, void *p) @@ -33,29 +34,36 @@ void pc1640_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3db: - pc1640->cga_enabled = val & 0x40; - if (pc1640->cga_enabled) + if (pc1640->cga_enabled != (val & 0x40)) { - 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) + pc1640->cga_enabled = val & 0x40; + if (pc1640->cga_enabled) { - 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; + timer_disable(&pc1640->ega.timer); + timer_set_delay_u64(&pc1640->cga.timer, 0); + mem_mapping_enable(&pc1640->cga_mapping); + mem_mapping_disable(&pc1640->ega_mapping); + } + else + { + timer_disable(&pc1640->cga.timer); + timer_set_delay_u64(&pc1640->ega.timer, 0); + 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); @@ -93,23 +101,6 @@ void pc1640_recalctimings(pc1640_t *pc1640) } } -void pc1640_poll(void *p) -{ - pc1640_t *pc1640 = (pc1640_t *)p; - if (pc1640->cga_enabled) - { - pc1640->cga.vidtime = pc1640->vidtime; - cga_poll(&pc1640->cga); - pc1640->vidtime = pc1640->cga.vidtime; - } - else - { - pc1640->ega.vidtime = pc1640->vidtime; - ega_poll(&pc1640->ega); - pc1640->vidtime = pc1640->ega.vidtime; - } -} - void *pc1640_init() { pc1640_t *pc1640 = malloc(sizeof(pc1640_t)); @@ -117,14 +108,14 @@ void *pc1640_init() ega_t *ega = &pc1640->ega; memset(pc1640, 0, sizeof(pc1640_t)); - rom_init(&pc1640->bios_rom, "roms/pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0); + rom_init(&pc1640->bios_rom, "pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0); - ega_init(&pc1640->ega); + ega_init(&pc1640->ega, 9, 0); pc1640->cga.vram = pc1640->ega.vram; pc1640->cga_enabled = 1; cga_init(&pc1640->cga); + timer_disable(&pc1640->ega.timer); - 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); diff --git a/src/vid_pc200.c b/src/vid_pc200.c index 06f511d..e430232 100644 --- a/src/vid_pc200.c +++ b/src/vid_pc200.c @@ -1,23 +1,51 @@ -/*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*/ +/*PC200/PPC video emulation. */ #include #include "ibm.h" #include "device.h" #include "io.h" #include "mem.h" +#include "nmi.h" #include "timer.h" #include "video.h" #include "vid_cga.h" +#include "vid_mda.h" #include "vid_pc200.h" +/* #define PC200LOG(x) pclog x */ +#define PC200LOG(x) + +/* Display type */ +#define PC200_CGA 0 /* CGA monitor */ +#define PC200_MDA 1 /* MDA monitor */ +#define PC200_TV 2 /* Television */ +#define PC200_LCDC 3 /* PPC512 LCD as CGA*/ +#define PC200_LCDM 4 /* PPC512 LCD as MDA*/ + +int pc200_is_mda; + +static uint32_t blue, green; + +static uint32_t lcdcols[256][2][2]; + typedef struct pc200_t { - mem_mapping_t mapping; + mem_mapping_t cga_mapping; + mem_mapping_t mda_mapping; cga_t cga; + mda_t mda; - uint8_t reg_3dd, reg_3de, reg_3df; + pc_timer_t timer; + + uint8_t emulation; /* Which display are we emulating? */ + uint8_t dipswitches; /* DIP switches 1-3 */ + uint8_t crtc_index; /* CRTC index readback + * Bit 7: CGA control port written + * Bit 6: Operation control port written + * Bit 5: CRTC register written + * Bits 0-4: Last CRTC register selected */ + uint8_t operation_ctrl; + uint8_t reg_3df; } pc200_t; static uint8_t crtcmask[32] = @@ -26,24 +54,168 @@ static uint8_t crtcmask[32] = 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/* LCD colour mappings + * + * 0 => solid green + * 1 => blue on green + * 2 => green on blue + * 3 => solid blue + */ +static unsigned char mapping1[256] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +/*00*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/*10*/ 2, 0, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, +/*20*/ 2, 2, 0, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, +/*30*/ 2, 2, 2, 0, 2, 2, 1, 1, 2, 2, 2, 1, 2, 2, 1, 1, +/*40*/ 2, 2, 1, 1, 0, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1, 1, +/*50*/ 2, 2, 1, 1, 2, 0, 1, 1, 2, 2, 1, 1, 2, 1, 1, 1, +/*60*/ 2, 2, 2, 2, 2, 2, 0, 1, 2, 2, 2, 2, 2, 2, 1, 1, +/*70*/ 2, 2, 2, 2, 2, 2, 2, 0, 2, 2, 2, 2, 2, 2, 2, 1, +/*80*/ 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, +/*90*/ 2, 2, 1, 1, 1, 1, 1, 1, 2, 0, 1, 1, 1, 1, 1, 1, +/*A0*/ 2, 2, 2, 1, 2, 2, 1, 1, 2, 2, 0, 1, 2, 2, 1, 1, +/*B0*/ 2, 2, 2, 2, 2, 2, 1, 1, 2, 2, 2, 0, 2, 2, 1, 1, +/*C0*/ 2, 2, 1, 1, 2, 1, 1, 1, 2, 2, 1, 1, 0, 1, 1, 1, +/*D0*/ 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 0, 1, 1, +/*E0*/ 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 0, 1, +/*F0*/ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, +}; + +static unsigned char mapping2[256] = +{ +/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */ +/*00*/ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +/*10*/ 1, 3, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 2, +/*20*/ 1, 1, 3, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, +/*30*/ 1, 1, 1, 3, 1, 1, 2, 2, 1, 1, 1, 2, 1, 1, 2, 2, +/*40*/ 1, 1, 2, 2, 3, 2, 2, 2, 1, 1, 2, 2, 2, 2, 2, 2, +/*50*/ 1, 1, 2, 2, 1, 3, 2, 2, 1, 1, 2, 2, 1, 2, 2, 2, +/*60*/ 1, 1, 1, 1, 1, 1, 3, 2, 1, 1, 1, 1, 1, 1, 2, 2, +/*70*/ 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 2, +/*80*/ 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, +/*90*/ 1, 1, 2, 2, 2, 2, 2, 2, 1, 3, 2, 2, 2, 2, 2, 2, +/*A0*/ 1, 1, 1, 2, 1, 1, 2, 2, 1, 1, 3, 2, 1, 1, 2, 2, +/*B0*/ 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 3, 1, 1, 2, 2, +/*C0*/ 1, 1, 2, 2, 1, 2, 2, 2, 1, 1, 2, 2, 3, 2, 2, 2, +/*D0*/ 1, 1, 2, 2, 1, 1, 2, 2, 1, 1, 2, 2, 1, 3, 2, 2, +/*E0*/ 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, +/*F0*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, +}; + +static void set_lcd_cols(uint8_t mode_reg) +{ + unsigned char *mapping = (mode_reg & 0x80) ? mapping2 : mapping1; + int c; + + for (c = 0; c < 256; c++) + { + switch (mapping[c]) + { + case 0: + lcdcols[c][0][0] = lcdcols[c][1][0] = green; + lcdcols[c][0][1] = lcdcols[c][1][1] = green; + break; + + case 1: + lcdcols[c][0][0] = lcdcols[c][1][0] = + lcdcols[c][1][1] = green; + lcdcols[c][0][1] = blue; + break; + + case 2: + lcdcols[c][0][0] = lcdcols[c][1][0] = + lcdcols[c][1][1] = blue; + lcdcols[c][0][1] = green; + break; + + case 3: + lcdcols[c][0][0] = lcdcols[c][1][0] = blue; + lcdcols[c][0][1] = lcdcols[c][1][1] = blue; + break; + } + } +} + + void pc200_out(uint16_t addr, uint8_t val, void *p) { pc200_t *pc200 = (pc200_t *)p; cga_t *cga = &pc200->cga; + mda_t *mda = &pc200->mda; uint8_t old; - + + PC200LOG(("pc200_out(0x%04x), %02x\n", addr, val)); + +/* MDA writes ============================================================== */ switch (addr) { - case 0x3d5: - if (!(pc200->reg_3de & 0x40) && cga->crtcreg <= 11) + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + + /* Writes banned to CRTC registers 0-11? */ + if (!(pc200->operation_ctrl & 0x40) && mda->crtcreg <= 11) { - if (pc200->reg_3de & 0x80) + pc200->crtc_index = 0x20 | (mda->crtcreg & 0x1f); + if (pc200->operation_ctrl & 0x80) + { + PC200LOG(("NMI raised from CRTC register access: reg=0x%02x val=0x%02x nmi_mask=%d\n", mda->crtcreg & 0x1F, val, nmi_mask)); nmi = 1; - - pc200->reg_3dd = 0x20 | (cga->crtcreg & 0x1f); + } pc200->reg_3df = val; return; } + PC200LOG(("CRTM[%02x]:=%02x\n", mda->crtcreg, val)); + old = mda->crtc[mda->crtcreg]; + mda->crtc[mda->crtcreg] = val & crtcmask[mda->crtcreg]; + if (old != val) + { + if (mda->crtcreg < 0xe || mda->crtcreg > 0x10) + { + fullchange = changeframecount; + mda_recalctimings(mda); + } + } + return; + + case 0x3b8: + old = mda->ctrl; + mda->ctrl = val; + if ((mda->ctrl ^ old) & 3) + { + mda_recalctimings(mda); + } + pc200->crtc_index &= 0x1F; + pc200->crtc_index |= 0x80; + if (pc200->operation_ctrl & 0x80) + { + PC200LOG(("NMI raised from mode control access: val=0x%02x nmi_mask=%d\n", val, nmi_mask)); + nmi = 1; + } + return; + + +/* CGA writes ============================================================== */ + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + + /* Writes banned to CRTC registers 0-11? */ + if (!(pc200->operation_ctrl & 0x40) && cga->crtcreg <= 11) + { + pc200->crtc_index = 0x20 | (cga->crtcreg & 0x1f); + if (pc200->operation_ctrl & 0x80) + { + PC200LOG(("NMI raised from CRTC register access: reg=0x%02x val=0x%02x nmi_mask=%d\n", cga->crtcreg & 0x1F, val, nmi_mask)); + nmi = 1; + } + pc200->reg_3df = val; + return; + } + PC200LOG(("CRTC[%02x]:=%02x\n", cga->crtcreg, val)); old = cga->crtc[cga->crtcreg]; cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; if (old != val) @@ -60,60 +232,656 @@ void pc200_out(uint16_t addr, uint8_t val, void *p) 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; + { + cga_recalctimings(cga); + } + pc200->crtc_index &= 0x1F; + pc200->crtc_index |= 0x80; + if (pc200->operation_ctrl & 0x80) + { + PC200LOG(("NMI raised from mode control access: val=0x%02x nmi_mask=%d\n", val, nmi_mask)); + nmi = 1; + } + else set_lcd_cols(val); return; +/* PC200 control port writes ============================================== */ case 0x3de: - pc200->reg_3de = val; - pc200->reg_3dd = 0x1f; - if (val & 0x80) - pc200->reg_3dd |= 0x40; + pc200->crtc_index = 0x1f; +/* NMI only seems to be triggered if the value being written has the high + * bit set (enable NMI). So it only protects writes to this port if you + * let it? */ + if (val & 0x80) + { + PC200LOG(("NMI raised from operation control access: val=0x%02x nmi_mask=%d\n", val, nmi_mask)); + pc200->operation_ctrl = val; + pc200->crtc_index |= 0x40; + nmi = 1; + return; + } + timer_disable(&pc200->cga.timer); + timer_disable(&pc200->mda.timer); + timer_disable(&pc200->timer); + pc200->operation_ctrl = val; + /* Bits 0 and 1 control emulation and output mode */ + if (val & 1) /* Monitor */ + { + pc200->emulation = (val & 2) ? PC200_MDA : PC200_CGA; + } + else if (romset == ROM_PPC512) + { + pc200->emulation = (val & 2) ? PC200_LCDM : PC200_LCDC; + } + else + { + pc200->emulation = PC200_TV; + + } + PC200LOG(("Video emulation set to %d\n", pc200->emulation)); + if (pc200->emulation == PC200_CGA || pc200->emulation == PC200_TV) + timer_advance_u64(&pc200->cga.timer, 1); + else if (pc200->emulation == PC200_MDA) + timer_advance_u64(&pc200->mda.timer, 1); + else + timer_advance_u64(&pc200->timer, 1); + + /* Bit 2 disables the IDA. We don't support dynamic enabling + * and disabling of the IDA (instead, PCEM disconnects the + * IDA from the bus altogether) so don't implement this */ + + /* Enable the appropriate memory ranges depending whether + * the IDA is configured as MDA or CGA */ + if (pc200->emulation == PC200_MDA || + pc200->emulation == PC200_LCDM) + { + mem_mapping_disable(&pc200->cga_mapping); + mem_mapping_enable(&pc200->mda_mapping); + } + else + { + mem_mapping_disable(&pc200->mda_mapping); + mem_mapping_enable(&pc200->cga_mapping); + } return; } - cga_out(addr, val, cga); + if (addr >= 0x3D0 && addr <= 0x3DF) + { + cga_out(addr, val, cga); + } + if (addr >= 0x3B0 && addr <= 0x3BB) + { + mda_out(addr, val, mda); + } } uint8_t pc200_in(uint16_t addr, void *p) { pc200_t *pc200 = (pc200_t *)p; cga_t *cga = &pc200->cga; + mda_t *mda = &pc200->mda; uint8_t temp; + PC200LOG(("pc200_in(0x%04x)\n", addr)); switch (addr) { + case 0x3B8: + PC200LOG((" = %02x\n", mda->ctrl)); + return mda->ctrl; + case 0x3D8: + PC200LOG((" = %02x\n", cga->cgamode)); return cga->cgamode; case 0x3DD: - temp = pc200->reg_3dd; - pc200->reg_3dd &= 0x1f; - nmi = 0; + temp = pc200->crtc_index; /* Read NMI reason */ + pc200->crtc_index &= 0x1f; /* Reset NMI reason */ + nmi = 0; /* And reset NMI flag */ + PC200LOG((" = %02x\n", temp)); return temp; case 0x3DE: - return (pc200->reg_3de & 0xc7) | 0x10; /*External CGA*/ - + PC200LOG((" = %02x\n", ((pc200->operation_ctrl & 0xc7) | pc200->dipswitches))); + return ((pc200->operation_ctrl & 0xc7) | pc200->dipswitches); + case 0x3DF: return pc200->reg_3df; } - return cga_in(addr, cga); + if (addr >= 0x3D0 && addr <= 0x3DF) + { + return cga_in(addr, cga); + } + if (addr >= 0x3B0 && addr <= 0x3BB) + { + return mda_in(addr, mda); + } + return 0xFF; +} + +void lcd_draw_char_80(pc200_t *pc200, uint32_t *buffer, uint8_t chr, + uint8_t attr, int drawcursor, int blink, int sc, + int mode160, uint8_t control) +{ + int c; + uint8_t bits = fontdat[chr + pc200->cga.fontbase][sc]; + uint8_t bright = 0; + uint16_t mask; + + if (attr & 8) /* bright */ + { +/* The brightness algorithm appears to be: replace any bit sequence 011 + * with 001 (assuming an extra 0 to the left of the byte). + */ + bright = bits; + for (c = 0, mask = 0x100; c < 7; c++, mask >>= 1) + { + if (((bits & mask) == 0) && + ((bits & (mask >> 1)) != 0) && + ((bits & (mask >> 2)) != 0)) + { + bright &= ~(mask >> 1); + } + } + bits = bright; + } + + if (drawcursor) bits ^= 0xFF; + + for (c = 0, mask = 0x80; c < 8; c++, mask >>= 1) + { + if (mode160) + buffer[c] = (attr & mask) ? blue : green; + else if (control & 0x20) /* blinking */ + buffer[c] = lcdcols[attr & 0x7F][blink][(bits & mask) ? 1 : 0]; + else + buffer[c] = lcdcols[attr][blink][(bits & mask) ? 1 : 0]; + } +} + + +void lcd_draw_char_40(pc200_t *pc200, uint32_t *buffer, uint8_t chr, + uint8_t attr, int drawcursor, int blink, int sc, + uint8_t control) +{ + int c; + uint8_t bits = fontdat[chr + pc200->cga.fontbase][sc]; + uint8_t mask = 0x80; + + if (attr & 8) /* bright */ + { + bits = bits & (bits >> 1); + } + if (drawcursor) bits ^= 0xFF; + + for (c = 0; c < 8; c++, mask >>= 1) + { + if (control & 0x20) + { + buffer[c*2] = buffer[c*2+1] = + lcdcols[attr & 0x7F][blink][(bits & mask) ? 1 : 0]; + } + else + { + buffer[c*2] = buffer[c*2+1] = + lcdcols[attr][blink][(bits & mask) ? 1 : 0]; + } + } +} + +void lcdm_poll(pc200_t *pc200) +{ + mda_t *mda = &pc200->mda; + uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x; + int oldvc; + uint8_t chr, attr; + int oldsc; + int blink; + if (!mda->linepos) + { + timer_advance_u64(&pc200->timer, 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; + video_wait_for_buffer(); + } + mda->lastline = mda->displine; + for (x = 0; x < mda->crtc[1]; x++) + { + chr = mda->vram[(mda->ma << 1) & 0xfff]; + attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; + drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + + lcd_draw_char_80(pc200, &((uint32_t *)(buffer32->line[mda->displine]))[x * 8], chr, attr, drawcursor, blink, mda->sc, 0, mda->ctrl); + mda->ma++; + } + } + 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 + { + timer_advance_u64(&pc200->timer, 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] * 8; + 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 << 1); + } + + video_blit_memtoscreen(0, mda->firstline, 0, ysize, xsize, ysize); + + 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 lcdc_poll(pc200_t *pc200) +{ + cga_t *cga = &pc200->cga; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int oldsc; + uint16_t ca; + int blink; + + ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + + if (!cga->linepos) + { + timer_advance_u64(&pc200->timer, 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; + video_wait_for_buffer(); +// printf("Firstline %i\n",firstline); + } + cga->lastline = cga->displine; + + 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); + blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + lcd_draw_char_80(pc200, &((uint32_t *)(buffer32->line[cga->displine]))[x * 8], chr, attr, drawcursor, blink, cga->sc, cga->cgamode & 0x40, cga->cgamode); + 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); + blink = ((cga->cgablink & 16) && (cga->cgamode & 0x20) && (attr & 0x80) && !drawcursor); + lcd_draw_char_40(pc200, &((uint32_t *)(buffer32->line[cga->displine]))[x * 16], chr, attr, drawcursor, blink, cga->sc, cga->cgamode); + cga->ma++; + } + } + else /* Graphics mode */ + { + 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++) + { + ((uint32_t *)buffer32->line[cga->displine])[(x << 4) + c] = (dat & 0x8000) ? blue : green; + dat <<= 1; + } + } + } + } + else + { + if (cga->cgamode & 1) hline(buffer32, 0, cga->displine, (cga->crtc[1] << 3), green); + else hline(buffer32, 0, cga->displine, (cga->crtc[1] << 4), green); + } + + if (cga->cgamode & 1) x = (cga->crtc[1] << 3); + else x = (cga->crtc[1] << 4); + + cga->sc = oldsc; + if (cga->vc == cga->crtc[7] && !cga->sc) + cga->cgastat |= 8; + cga->displine++; + if (cga->displine >= 360) + cga->displine = 0; + } + else + { + timer_advance_u64(&pc200->timer, 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 = 16; + if (cga->crtc[7]) + { + if (cga->cgamode & 1) x = (cga->crtc[1] << 3); + else x = (cga->crtc[1] << 4); + 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)); + } + + video_blit_memtoscreen(0, cga->firstline, 0, (cga->lastline - cga->firstline), xsize, (cga->lastline - cga->firstline)); + frames++; + + 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 pc200_poll(void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + + switch (pc200->emulation) + { +// case PC200_CGA: +// case PC200_TV: +// pc200->cga.vidtime = pc200->vidtime; +// cga_poll(&pc200->cga); +// pc200->vidtime = pc200->cga.vidtime; +// return; + +// case PC200_MDA: +// pc200->mda.vidtime = pc200->vidtime; +// mda_poll(&pc200->mda); +// pc200->vidtime = pc200->mda.vidtime; +// return; + + case PC200_LCDM: + lcdm_poll(pc200); + return; + case PC200_LCDC: + lcdc_poll(pc200); + return; + } } void *pc200_init() { + int display_type, contrast; + pc200_t *pc200 = malloc(sizeof(pc200_t)); - cga_t *cga = &pc200->cga; + memset(pc200, 0, sizeof(pc200_t)); - pc200->cga.vram = malloc(0x4000); + pc200->emulation = device_get_config_int("video_emulation"); + display_type = device_get_config_int("display_type"); + contrast = device_get_config_int("contrast"); + + /* Default to CGA */ + pc200->dipswitches = 0x10; + + /* DIP switches for PC200. Switches 2,3 give video emulation. + * Switch 1 is 'swap floppy drives' (not implemented) */ + if (romset == ROM_PC200) switch (pc200->emulation) + { + case PC200_CGA: pc200->dipswitches = 0x10; break; + case PC200_MDA: pc200->dipswitches = 0x30; break; + case PC200_TV: pc200->dipswitches = 0x00; break; + /* The other combination is 'IDA disabled' (0x20) - see + * amstrad.c */ + } + /* DIP switches for PPC512. Switch 1 is CRT/LCD. Switch 2 + * is MDA / CGA. Switch 3 disables IDA, not implemented. */ + else switch (pc200->emulation) + { + case PC200_CGA: pc200->dipswitches = 0x08; break; + case PC200_MDA: pc200->dipswitches = 0x18; break; + case PC200_LCDC: pc200->dipswitches = 0x00; break; + case PC200_LCDM: pc200->dipswitches = 0x10; break; + } + /* Flag whether the card is behaving like a CGA or an MDA, so that + * DIP switches are reported correctly */ + pc200_is_mda = (pc200->emulation == PC200_MDA || + pc200->emulation == PC200_LCDM); + PC200LOG(("pc200: DIP switches = %02x\n", pc200->dipswitches)); + + pc200->cga.vram = pc200->mda.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); + mda_init(&pc200->mda); + + /* Attribute 8 is white on black (on a real MDA it's black on black) */ + mda_setcol(0x08, 0, 1, 15); + mda_setcol(0x88, 0, 1, 15); + /* Attribute 64 is black on black (on a real MDA it's white on black) */ + mda_setcol(0x40, 0, 1, 0); + mda_setcol(0xC0, 0, 1, 0); + + pc200->cga.fontbase = (device_get_config_int("codepage") & 3) * 256; + +// pclog("pc200=%p pc200->timer=%p pc200->cga=%p pc200->mda=%p pc200->mda->timer=%p\n", pc200, &pc200->timer, &pc200->cga, &pc200->mda, &pc200->mda->timer); + timer_add(&pc200->timer, pc200_poll, pc200, 1); + mem_mapping_add(&pc200->mda_mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, 0, &pc200->mda); + mem_mapping_add(&pc200->cga_mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, &pc200->cga); io_sethandler(0x03d0, 0x0010, pc200_in, NULL, NULL, pc200_out, NULL, NULL, pc200); + io_sethandler(0x03b0, 0x000c, pc200_in, NULL, NULL, pc200_out, NULL, NULL, pc200); + + green = makecol(0x1C, 0x71, 0x31); + blue = makecol(0x0f, 0x21, 0x3f); + cgapal_rebuild(display_type, contrast); + set_lcd_cols(0); + + timer_disable(&pc200->cga.timer); + timer_disable(&pc200->mda.timer); + timer_disable(&pc200->timer); + if (pc200->emulation == PC200_CGA || pc200->emulation == PC200_TV) + timer_enable(&pc200->cga.timer); + else if (pc200->emulation == PC200_MDA) + timer_enable(&pc200->mda.timer); + else + timer_enable(&pc200->timer); + return pc200; } @@ -130,8 +898,198 @@ void pc200_speed_changed(void *p) pc200_t *pc200 = (pc200_t *)p; cga_recalctimings(&pc200->cga); + mda_recalctimings(&pc200->mda); } +device_config_t pc200_config[] = +{ + { + .name = "video_emulation", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "CGA monitor", + .value = PC200_CGA, + }, + { + .description = "MDA monitor", + .value = PC200_MDA, + }, + { + .description = "Television", + .value = PC200_TV, + }, + { + .description = "" + } + }, + .default_int = PC200_CGA, + }, + { + .name = "display_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "RGB", + .value = DISPLAY_RGB + }, + { + .description = "RGB (no brown)", + .value = DISPLAY_RGB_NO_BROWN + }, + { + .description = "Green Monochrome", + .value = DISPLAY_GREEN + }, + { + .description = "Amber Monochrome", + .value = DISPLAY_AMBER + }, + { + .description = "White Monochrome", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + }, + .default_int = DISPLAY_RGB + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "US English", + .value = 3 + }, + { + .description = "Portugese", + .value = 2 + }, + { + .description = "Norwegian", + .value = 1 + }, + { + .description = "Greek", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 3 + }, + { + .type = -1 + } +}; + + +device_config_t ppc512_config[] = +{ + { + .name = "video_emulation", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "CGA monitor", + .value = PC200_CGA, + }, + { + .description = "MDA monitor", + .value = PC200_MDA, + }, + { + .description = "LCD (CGA mode)", + .value = PC200_LCDC, + }, + { + .description = "LCD (MDA mode)", + .value = PC200_LCDM, + }, + { + .description = "" + } + }, + .default_int = PC200_LCDC, + }, + { + .name = "display_type", + .description = "External monitor", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "RGB", + .value = DISPLAY_RGB + }, + { + .description = "RGB (no brown)", + .value = DISPLAY_RGB_NO_BROWN + }, + { + .description = "Green Monochrome", + .value = DISPLAY_GREEN + }, + { + .description = "Amber Monochrome", + .value = DISPLAY_AMBER + }, + { + .description = "White Monochrome", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + }, + .default_int = DISPLAY_RGB + }, + { + .name = "codepage", + .description = "Hardware font", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "US English", + .value = 3 + }, + { + .description = "Portugese", + .value = 2 + }, + { + .description = "Norwegian", + .value = 1 + }, + { + .description = "Greek", + .value = 0 + }, + { + .description = "" + } + }, + .default_int = 3 + }, + { + .type = -1 + } +}; + + + device_t pc200_device = { "Amstrad PC200 (video)", @@ -141,5 +1099,20 @@ device_t pc200_device = NULL, pc200_speed_changed, NULL, - NULL + NULL, + pc200_config }; + +device_t ppc512_device = +{ + "Amstrad PPC512 (video)", + 0, + pc200_init, + pc200_close, + NULL, + pc200_speed_changed, + NULL, + NULL, + ppc512_config +}; + diff --git a/src/vid_pc200.h b/src/vid_pc200.h index 4b43090..f59de48 100644 --- a/src/vid_pc200.h +++ b/src/vid_pc200.h @@ -1 +1,4 @@ extern device_t pc200_device; +extern device_t ppc512_device; + +extern int pc200_is_mda; diff --git a/src/vid_pcjr.c b/src/vid_pcjr.c index 0e6b47d..5a8fb7c 100644 --- a/src/vid_pcjr.c +++ b/src/vid_pcjr.c @@ -36,7 +36,8 @@ typedef struct pcjr_t int vsynctime, vadj; uint16_t ma, maback; - int dispontime, dispofftime, vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; int composite; @@ -168,8 +169,8 @@ void pcjr_recalctimings(pcjr_t *pcjr) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - pcjr->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - pcjr->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + pcjr->dispontime = (uint64_t)_dispontime; + pcjr->dispofftime = (uint64_t)_dispofftime; } void pcjr_poll(void *p) @@ -189,7 +190,7 @@ void pcjr_poll(void *p) { // cgapal[0]=pcjr->col&15; // printf("Firstline %i Lastline %i pcjr->displine %i\n",firstline,lastline,pcjr->displine); - pcjr->vidtime += pcjr->dispofftime; + timer_advance_u64(&pcjr->timer, pcjr->dispofftime); pcjr->stat &= ~1; pcjr->linepos = 1; oldsc = pcjr->sc; @@ -206,12 +207,12 @@ void pcjr_poll(void *p) video_wait_for_buffer(); } pcjr->lastline = pcjr->displine; - cols[0] = (pcjr->array[2] & 0xf) + 16; + cols[0] = pcjr->array[2] & 0xf; 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]; + ((uint32_t *)buffer32->line[pcjr->displine])[c] = cols[0]; + if (pcjr->array[0] & 1) ((uint32_t *)buffer32->line[pcjr->displine])[c + (pcjr->crtc[1] << 3) + 8] = cols[0]; + else ((uint32_t *)buffer32->line[pcjr->displine])[c + (pcjr->crtc[1] << 4) + 8] = cols[0]; } switch (pcjr->addr_mode) @@ -235,14 +236,14 @@ void pcjr_poll(void *p) 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; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 8] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 9] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 10] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 11] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 12] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 13] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 14] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 15] = pcjr->array[(dat & pcjr->array[1]) + 16]; } break; case 0x12: /*160x200x16*/ @@ -251,22 +252,22 @@ void pcjr_poll(void *p) 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; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 8] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 9] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 10] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 11] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 12] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 13] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 14] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 15] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 16] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 17] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 18] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 19] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 20] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 21] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 22] = + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + 23] = pcjr->array[(dat & pcjr->array[1]) + 16]; } break; case 0x03: /*640x200x4*/ @@ -279,7 +280,7 @@ void pcjr_poll(void *p) { chr = (dat >> 7) & 1; chr |= ((dat >> 14) & 2); - buffer->line[pcjr->displine][(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16]; dat <<= 1; } } @@ -292,31 +293,31 @@ void pcjr_poll(void *p) 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; + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16]; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 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; + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16]; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16]; } if (pcjr->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[0]; + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 3) + c + 8] ^= 15; } pcjr->ma++; } @@ -329,41 +330,41 @@ void pcjr_poll(void *p) 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; + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16]; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 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; + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16]; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 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]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->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; + cols[0] = pcjr->array[0 + 16]; + cols[1] = pcjr->array[1 + 16]; + cols[2] = pcjr->array[2 + 16]; + cols[3] = pcjr->array[3 + 16]; for (x = 0; x < pcjr->crtc[1]; x++) { dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | @@ -371,15 +372,15 @@ void pcjr_poll(void *p) 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]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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; + cols[0] = pcjr->array[0 + 16]; + cols[1] = pcjr->array[1 + 16]; for (x = 0; x < pcjr->crtc[1]; x++) { dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | @@ -387,7 +388,7 @@ void pcjr_poll(void *p) pcjr->ma++; for (c = 0; c < 16; c++) { - buffer->line[pcjr->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[pcjr->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -398,15 +399,15 @@ void pcjr_poll(void *p) { 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); + if (pcjr->array[0] & 1) hline(buffer32, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, pcjr->array[2] & 0xf); + else hline(buffer32, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, pcjr->array[2] & 0xf); } 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]); + cols[0] = pcjr->array[0 + 16]; + if (pcjr->array[0] & 1) hline(buffer32, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); } } if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; @@ -414,10 +415,15 @@ void pcjr_poll(void *p) if (pcjr->composite) { for (c = 0; c < x; c++) - buffer32->line[pcjr->displine][c] = buffer->line[pcjr->displine][c] & 0xf; + buffer32->line[pcjr->displine][c] = ((uint32_t *)buffer32->line[pcjr->displine])[c] & 0xf; Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[pcjr->displine]); } + else + { + for (c = 0; c < x; c++) + ((uint32_t *)buffer32->line[pcjr->displine])[c] = cgapal[((uint32_t *)buffer32->line[pcjr->displine])[c] & 0xf]; + } pcjr->sc = oldsc; if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) { @@ -430,7 +436,7 @@ void pcjr_poll(void *p) } else { - pcjr->vidtime += pcjr->dispontime; + timer_advance_u64(&pcjr->timer, pcjr->dispontime); if (pcjr->dispon) pcjr->stat |= 1; pcjr->linepos = 0; @@ -514,10 +520,7 @@ void pcjr_poll(void *p) // printf("Blit %i %i\n",firstline,lastline); //printf("Xsize is %i\n",xsize); - if (pcjr->composite) - 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); + video_blit_memtoscreen(0, pcjr->firstline-4, 0, (pcjr->lastline - pcjr->firstline) + 8, xsize, (pcjr->lastline - pcjr->firstline) + 8); frames++; video_res_x = xsize - 16; @@ -550,7 +553,7 @@ static void *pcjr_video_init() pcjr->memctrl = -1; - timer_add(pcjr_poll, &pcjr->vidtime, TIMER_ALWAYS_ENABLED, pcjr); + timer_add(&pcjr->timer, pcjr_poll, pcjr, 1); 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); return pcjr; diff --git a/src/vid_pgc.c b/src/vid_pgc.c new file mode 100644 index 0000000..5f61dfa --- /dev/null +++ b/src/vid_pgc.c @@ -0,0 +1,2477 @@ +/*PGC emulation*/ +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "thread.h" +#include "video.h" +#include "vid_pgc.h" +#include + +/* This implements just enough of the Professional Graphics Controller to + * act as a basis for the Vermont Microsystems IM-1024. + * + * PGC features implemented include: + * > The CGA-compatible display modes + * > Switching to and from native mode + * > Communicating with the host PC + * + * Numerous features are implemented partially or not at all, such as: + * > 2D drawing + * > 3D drawing + * > Command lists + * Some of these are marked TODO. + * + * The PGC has two display modes: CGA (in which it appears in the normal CGA + * memory and I/O ranges) and native (in which all functions are accessed + * through reads and writes to 1k of memory at 0xC6000). The PGC's 8088 + * processor monitors this buffer and executes instructions left there + * for it. We simulate this behaviour with a separate thread. + */ + +#define PGC_CGA_WIDTH 640 +#define PGC_CGA_HEIGHT 400 + +static int pgc_parse_command(pgc_core_t *pgc, const pgc_command_t **pcmd); +int pgc_clist_byte(pgc_core_t *pgc, uint8_t *val); + + + + +static const char *pgc_err_msgs[] = +{ + "Range \r", + "Integer \r", + "Memory \r", + "Overflow\r", + "Digit \r", + "Opcode \r", + "Running \r", + "Stack \r", + "Too long\r", + "Area \r", + "Missing \r" +}; + +#define HWORD(u) ((u) >> 16) +#define LWORD(u) ((u) & 0xFFFF) + + +/* Initial palettes */ +uint32_t init_palette[6][256] = +{ +#include "pgc_palettes.h" +}; + + + +/* When idle, the PGC drawing thread sleeps. pgc_wake() awakens it - but + * not immediately. Like the Voodoo, it has a short delay so that writes + * can be batched */ +#define WAKE_DELAY (TIMER_USEC * 500) +void pgc_wake(pgc_core_t *pgc) +{ + if (!timer_is_enabled(&pgc->wake_timer)) + { + timer_set_delay_u64(&pgc->wake_timer, WAKE_DELAY); + } +} + + +/* When the wake timer expires, that's when the drawing thread is actually + * woken */ +static void pgc_wake_timer(void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + + PGCLOG(("pgc: Waking up\n")); + thread_set_event(pgc->pgc_wake_thread); +} + +/* This is called by the drawing thread when it's waiting for the host + * to put more input in its input FIFO, or drain output from its output + * FIFO. */ +void pgc_sleep(pgc_core_t *pgc) +{ + + PGCLOG(("pgc: Sleeping on %d %d %d 0x%02x 0x%02x\n", + pgc->waiting_input_fifo, + pgc->waiting_output_fifo, + pgc->waiting_error_fifo, + pgc->mapram[0x300], pgc->mapram[0x301])); + /* Race condition: If host wrote to the PGC during the pclog() that + * won't be noticed */ + if (pgc->waiting_input_fifo && pgc->mapram[0x300] != pgc->mapram[0x301]) + { + pgc->waiting_input_fifo = 0; + return; + } + /* Same if they read */ + if (pgc->waiting_output_fifo && pgc->mapram[0x302] != (uint8_t)(pgc->mapram[0x303] - 1)) + { + pgc->waiting_output_fifo = 0; + return; + } + thread_wait_event(pgc->pgc_wake_thread, -1); + thread_reset_event(pgc->pgc_wake_thread); + +} + +/* Switch between CGA mode (DISPLAY 1) and native mode (DISPLAY 0) */ +void pgc_setdisplay(pgc_core_t *pgc, int cga) +{ + PGCLOG(("pgc_setdisplay(%d): cga_selected=%d cga_enabled=%d\n", + cga, pgc->cga_selected, pgc->cga_enabled)); + if (pgc->cga_selected != (pgc->cga_enabled && cga)) + { + pgc->cga_selected = (pgc->cga_enabled && cga); + + if (pgc->cga_selected) + { + mem_mapping_enable(&pgc->cga_mapping); + pgc->screenw = PGC_CGA_WIDTH; + pgc->screenh = PGC_CGA_HEIGHT; + } + else + { + mem_mapping_disable(&pgc->cga_mapping); + pgc->screenw = pgc->visw; + pgc->screenh = pgc->vish; + } + pgc_recalctimings(pgc); + } +} + + + + + +/* Convert coordinates based on the current window / viewport to raster + * coordinates. */ +void pgc_dto_raster(pgc_core_t *pgc, double *x, double *y) +{ +/* double x0 = *x, y0 = *y; */ + + *x += (pgc->vp_x1 - pgc->win_x1); + *y += (pgc->vp_y1 - pgc->win_y1); + +/* PGCLOG(("Coords to raster: (%f, %f) -> (%f, %f)\n", x0, y0, *x, *y)); */ +} + + +/* Overloads that take ints */ +void pgc_sto_raster(pgc_core_t *pgc, int16_t *x, int16_t *y) +{ + double xd = *x, yd = *y; + + pgc_dto_raster(pgc, &xd, &yd); + *x = (int16_t)xd; + *y = (int16_t)yd; +} + +void pgc_ito_raster(pgc_core_t *pgc, int32_t *x, int32_t *y) +{ + double xd = *x, yd = *y; + + pgc_dto_raster(pgc, &xd, &yd); + *x = (int32_t)xd; + *y = (int32_t)yd; +} + + +/* Add a byte to a command list. We allow command lists to be + * arbitrarily large */ +int pgc_commandlist_append(pgc_commandlist_t *list, uint8_t v) +{ + if (list->listmax == 0 || list->list == NULL) + { + list->list = malloc(4096); + if (!list->list) + { + PGCLOG(("Out of memory initialising command list\n")); + return 0; + } + list->listmax = 4096; + } + while (list->wrptr >= list->listmax) + { + uint8_t *buf = realloc(list->list, 2 * list->listmax); + if (!buf) + { + PGCLOG(("Out of memory growing command list\n")); + return 0; + } + list->list = buf; + list->listmax *= 2; + } + list->list[list->wrptr++] = v; + return 1; +} + +/* Beginning of a command list. Parse commands up to the next CLEND, + * storing them (in hex form) in the named command list. */ +static void hndl_clbeg(pgc_core_t *pgc) +{ + uint8_t param; + pgc_commandlist_t cl; + const pgc_command_t *cmd; + + memset(&cl, 0, sizeof(cl)); + if (!pgc_param_byte(pgc, ¶m)) return; + + PGCLOG(("CLBEG(%d)\n", param)); + while (1) + { + if (!pgc_parse_command(pgc, &cmd)) + { + /* PGC has been reset */ + return; + } + if (!cmd) + { + pgc_error(pgc, PGC_ERROR_OPCODE); + return; + } + else if (pgc->hex_command == 0x71) /* CLEND */ + { + pgc->clist[param] = cl; + return; + } + else + { + if (!pgc_commandlist_append(&cl, pgc->hex_command)) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + return; + } + if (cmd->parser) + { + if (!(*cmd->parser)(pgc, &cl, cmd->p)) + { + return; + } + } + } + } +} + +static void hndl_clend(pgc_core_t *pgc) +{ + /* Shouldn't happen outside a CLBEG */ +} + +/* Execute a command list. If one was already executing, remember it so + * we can return to it afterwards. */ +static void hndl_clrun(pgc_core_t *pgc) +{ + uint8_t param; + pgc_commandlist_t *clprev = pgc->clcur; + + if (!pgc_param_byte(pgc, ¶m)) return; + + pgc->clcur = &pgc->clist[param]; + pgc->clcur->rdptr = 0; + pgc->clcur->repeat = 1; + pgc->clcur->chain = clprev; +} + +/* Execute a command list multiple times. */ +static void hndl_cloop(pgc_core_t *pgc) +{ + uint8_t param; + int16_t repeat; + pgc_commandlist_t *clprev = pgc->clcur; + + if (!pgc_param_byte(pgc, ¶m)) return; + if (!pgc_param_word(pgc, &repeat)) return; + + pgc->clcur = &pgc->clist[param]; + pgc->clcur->rdptr = 0; + pgc->clcur->repeat = repeat; + pgc->clcur->chain = clprev; +} + + +/* Read back a command list */ +static void hndl_clread(pgc_core_t *pgc) +{ + uint8_t param; + int n; + + if (!pgc_param_byte(pgc, ¶m)) return; + + for (n = 0; n < pgc->clist[param].wrptr; n++) + { + if (!pgc_result_byte(pgc, pgc->clist[param].list[n])) + return; + } +} + + +/* Delete a command list */ +static void hndl_cldel(pgc_core_t *pgc) +{ + uint8_t param; + + if (!pgc_param_byte(pgc, ¶m)) return; + memset(&pgc->clist[param], 0, sizeof(pgc_commandlist_t)); +} + + + +/* Clear the screen to a specified colour */ +static void hndl_clears(pgc_core_t *pgc) +{ + uint8_t param; + int y; + + if (!pgc_param_byte(pgc, ¶m)) return; + + for (y = 0; y < pgc->screenh; y++) + memset(pgc->vram + y * pgc->maxw, param, pgc->screenw); +} + +/* Select drawing colour */ +static void hndl_color(pgc_core_t *pgc) +{ + uint8_t param; + + if (!pgc_param_byte(pgc, ¶m)) return; + + pgc->colour = param; + PGCLOG(("COLOR(%d)\n", param)); +} + + +/* Set drawing mode. + * + * 0 => Draw + * 1 => Invert + * 2 => XOR (IM-1024) + * 3 => AND (IM-1024) + * + */ +static void hndl_linfun(pgc_core_t *pgc) +{ + uint8_t param; + + if (!pgc_param_byte(pgc, ¶m)) return; + + /* TODO: Not range-checked. Strictly speaking we should limit to 0-1 + * for the PGC and 0-3 for the IM-1024. */ + pgc->draw_mode = param; + PGCLOG(("LINFUN(%d)\n", param)); +} + +/* Set the line drawing pattern */ +static void hndl_linpat(pgc_core_t *pgc) +{ + uint16_t param; + + if (!pgc_param_word(pgc, (int16_t *)¶m)) return; + + pgc->line_pattern = param; + PGCLOG(("LINPAT(0x%04x)\n", param)); +} + +/* Set the polygon fill mode (0=hollow, 1=filled, 2=fast fill) */ +static void hndl_prmfil(pgc_core_t *pgc) +{ + uint8_t param; + + if (!pgc_param_byte(pgc, ¶m)) return; + + PGCLOG(("PRMFIL(%d)\n", param)); + if (param < 3) + { + pgc->fill_mode = param; + } + else + { + pgc_error(pgc, PGC_ERROR_RANGE); + } +} + + +/* Set the 2D drawing position */ +static void hndl_move(pgc_core_t *pgc) +{ + int32_t x = 0, y = 0; + + if (!pgc_param_coord(pgc, &x)) return; + if (!pgc_param_coord(pgc, &y)) return; + + pgc->x = x; + pgc->y = y; + PGCLOG(("MOVE %x.%04x,%x.%04x\n", HWORD(x), LWORD(x), HWORD(y), LWORD(y))); +} + +/* Set the 3D drawing position */ +static void hndl_move3(pgc_core_t *pgc) +{ + int32_t x = 0, y = 0, z = 0; + + if (!pgc_param_coord(pgc, &x)) return; + if (!pgc_param_coord(pgc, &y)) return; + if (!pgc_param_coord(pgc, &z)) return; + + pgc->x = x; + pgc->y = y; + pgc->z = z; +} + +/* Relative move (2D) */ +static void hndl_mover(pgc_core_t *pgc) +{ + int32_t x = 0, y = 0; + + if (!pgc_param_coord(pgc, &x)) return; + if (!pgc_param_coord(pgc, &y)) return; + + pgc->x += x; + pgc->y += y; +} + +/* Relative move (3D) */ +static void hndl_mover3(pgc_core_t *pgc) +{ + int32_t x = 0, y = 0, z = 0; + + if (!pgc_param_coord(pgc, &x)) return; + if (!pgc_param_coord(pgc, &y)) return; + if (!pgc_param_coord(pgc, &z)) return; + + pgc->x += x; + pgc->y += y; + pgc->z += z; +} + + + +/* Draw a line (using PGC fixed-point coordinates) */ +uint16_t pgc_draw_line(pgc_core_t *pgc, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint16_t linemask) +{ + + PGCLOG(("pgc_draw_line: (%d,%d) to (%d,%d)\n", x0 >> 16, y0 >> 16, + x1 >> 16, y1 >> 16)); + /* Convert from PGC fixed-point to device coordinates */ + x0 >>= 16; + x1 >>= 16; + y0 >>= 16; + y1 >>= 16; + + pgc_ito_raster(pgc, &x0, &y0); + pgc_ito_raster(pgc, &x1, &y1); + + return pgc_draw_line_r(pgc, x0, y0, x1, y1, linemask); +} + +/* Draw a line (using raster coordinates) + Bresenham's Algorithm from + * + * The line pattern mask to use is passed in. The return value is the line + * pattern mask rotated by the number of points drawn. + */ +uint16_t pgc_draw_line_r(pgc_core_t *pgc, int32_t x0, int32_t y0, int32_t x1, int32_t y1, uint16_t linemask) +{ + int32_t dx, dy, sx, sy, err, e2; + + dx = abs(x1 - x0); + dy = abs(y1 - y0); + sx = (x0 < x1) ? 1 : -1; + sy = (y0 < y1) ? 1 : -1; + err = (dx > dy ? dx : -dy) / 2; + + for(;;) + { + if (linemask & 0x8000) + { + pgc_plot(pgc, x0, y0); + linemask = (linemask << 1) | 1; + } + else + { + linemask = (linemask << 1); + } + if (x0 == x1 && y0 == y1) break; + e2 = err; + if (e2 > -dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } + return linemask; +} + +/* Draw a horizontal line in the current fill pattern + * (using raster coordinates) */ +void pgc_fill_line_r(pgc_core_t *pgc, int32_t x0, int32_t x1, int32_t y0) +{ + int32_t x; + int32_t mask = 0x8000 >> (x0 & 0x0F); + + if (x0 > x1) { x = x1; x1 = x0; x0 = x; } + + for (x = x0; x <= x1; x++) + { + if (pgc->fill_pattern[y0 & 0x0F] & mask) + pgc_plot(pgc, x, y0); + mask = mask >> 1; + if (mask == 0) mask = 0x8000; + } +} + +/* For sorting polygon nodes */ +static int compare_double(const void *a, const void *b) +{ + const double *da = (const double *)a; + const double *db = (const double *)b; + + if (*da > *db) return 1; + if (*da < *db) return -1; + return 0; +} + +/* Draw a filled polygon (using PGC fixed-point coordinates) */ +void pgc_fill_polygon(pgc_core_t *pgc, + unsigned corners, int32_t *x, int32_t *y) +{ + double *nodex; + double *dx; + double *dy; + unsigned n, nodes, i, j; + double ymin, ymax, ypos; + + PGCLOG(("pgc_fill_polygon(%d corners)\n", corners)); + + if (corners < 2) return; /* Degenerate polygon */ + nodex = malloc(corners * sizeof(double)); + dx = malloc(corners * sizeof(double)); + dy = malloc(corners * sizeof(double)); + if (!nodex || !dx || !dy) return; + + ymin = ymax = y[0] / 65536.0; + for (n = 0; n < corners; n++) + { + /* Convert from PGC fixed-point to native floating-point */ + dx[n] = x[n] / 65536.0; + dy[n] = y[n] / 65536.0; + + if (dy[n] < ymin) ymin = dy[n]; + if (dy[n] > ymax) ymax = dy[n]; + } + /* Polygon fill. Based on */ + /* For each row, work out where the polygon lines intersect with + * that row. */ + for (ypos = ymin; ypos <= ymax; ypos++) + { + nodes = 0; + j = corners - 1; + for (i = 0; i < corners; i++) + { + if ((dy[i] < ypos && dy[j] >= ypos) + || (dy[j] < ypos && dy[i] >= ypos)) /* Line crosses */ + { + nodex[nodes++] = dx[i] + (ypos-dy[i])/(dy[j]-dy[i]) * (dx[j] - dx[i]); + } + j = i; + } + + /* Sort the intersections */ + if (nodes) qsort(nodex, nodes, sizeof(double), compare_double); +/* + PGCLOG(("pgc_fill_polygon ypos=%f nodes=%d ", ypos, nodes)); + for (i = 0; i < nodes; i++) + { + PGCLOG(("%f;", nodex[i])); + } + PGCLOG(("\n")); +*/ + /* And fill between them */ + for (i = 0; i < nodes; i += 2) + { + int16_t x1 = nodex[i], x2 = nodex[i + 1], + y1 = ypos, y2 = ypos; + pgc_sto_raster(pgc, &x1, &y1); + pgc_sto_raster(pgc, &x2, &y2); +/* PGCLOG(("pgc_fill_polygon raster %d,%d to %d,%d\n", + x1, y1, x2, y2)); */ + pgc_fill_line_r(pgc, x1, x2, y1); + } + } + free(nodex); + free(dx); + free(dy); +} + + + +/* Draw a filled ellipse (using PGC fixed-point coordinates) */ +void pgc_draw_ellipse(pgc_core_t *pgc, int32_t x, int32_t y) +{ + /* Convert from PGC fixed-point to native floating-point */ + double h = y / 65536.0; + double w = x / 65536.0; + double y0 = pgc->y / 65536.0; + double x0 = pgc->x / 65536.0; + double ypos = 0.0, xpos = 0.0; + double x1; + double xlast = 0.0; + int16_t linemask = pgc->line_pattern; + + pgc_dto_raster(pgc, &x0, &y0); + PGCLOG(("Ellipse: Colour=%d Drawmode=%d fill=%d\n", pgc->colour, + pgc->draw_mode, pgc->fill_mode)); + for (ypos = 0; ypos <= h; ypos++) + { + if (ypos == 0) + { + if (pgc->fill_mode) + { + pgc_fill_line_r(pgc, x0 - w, x0 + w, y0); + } + if (linemask & 0x8000) + { + pgc_plot(pgc, x0 + w, y0); + pgc_plot(pgc, x0 - w, y0); + linemask = (linemask << 1) | 1; + } + else + { + linemask = linemask << 1; + } + xlast = w; + } + else + { + x1 = sqrt((h * h) - (ypos * ypos)) * w / h; + + if (pgc->fill_mode) + { + pgc_fill_line_r(pgc, x0 - x1, x0 + x1, y0 + ypos); + pgc_fill_line_r(pgc, x0 - x1, x0 + x1, y0 - ypos); + } + + /* Draw border */ + for (xpos = xlast; xpos >= x1; xpos--) + { + if (linemask & 0x8000) + { + pgc_plot(pgc, x0 + xpos, y0 + ypos); + pgc_plot(pgc, x0 - xpos, y0 + ypos); + pgc_plot(pgc, x0 + xpos, y0 - ypos); + pgc_plot(pgc, x0 - xpos, y0 - ypos); + linemask = (linemask << 1) | 1; + } + else + { + linemask = linemask << 1; + } + + } + xlast = x1; + } + } +} + +/* Handle the ELIPSE (sic) command */ +static void hndl_ellipse(pgc_core_t *pgc) +{ + int32_t x = 0, y = 0; + + if (!pgc_param_coord(pgc, &x)) return; + if (!pgc_param_coord(pgc, &y)) return; + + pgc_draw_ellipse(pgc, x, y); +} + + + + +/* Handle the POLY command */ +static void hndl_poly(pgc_core_t *pgc) +{ + uint8_t count; + int32_t x[256]; + int32_t y[256]; + int32_t n; + + if (!pgc_param_byte(pgc, &count)) return; + + for (n = 0; n < count; n++) + { + if (!pgc_param_coord(pgc, &x[n])) return; + if (!pgc_param_coord(pgc, &y[n])) return; + } + PGCLOG(("POLY (%d)\n", count)); +} + +/* Parse but don't execute a POLY command (for adding to a command list) */ +static int parse_poly(pgc_core_t *pgc, pgc_commandlist_t *cl, int c) +{ + uint8_t count; + + PGCLOG(("parse_poly\n")); + if (!pgc_param_byte(pgc, &count)) return 0; + PGCLOG(("parse_poly: count=%02x\n", count)); + + if (!pgc_commandlist_append(cl, count)) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + return 0; + } + PGCLOG(("parse_poly: parse %d coords\n", 2 * count)); + return pgc_parse_coords(pgc, cl, 2 * count); +} + + +/* Parse but don't execute a command with a fixed number of byte parameters */ +int pgc_parse_bytes(pgc_core_t *pgc, pgc_commandlist_t *cl, int count) +{ + uint8_t *param = malloc(count); + int n; + + if (!param) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + return 0; + } + for (n = 0; n < count; n++) + { + if (!pgc_param_byte(pgc, ¶m[n])) + { + free(param); + return 0; + } + } + for (n = 0; n < count; n++) + { + if (!pgc_commandlist_append(cl, param[n])) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + free(param); + return 0; + } + } + free(param); + return 1; +} + + +/* Parse but don't execute a command with a fixed number of word parameters */ +int pgc_parse_words(pgc_core_t *pgc, pgc_commandlist_t *cl, int count) +{ + int16_t *param = malloc(count * sizeof(int16_t)); + int n; + + if (!param) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + return 0; + } + for (n = 0; n < count; n++) + { + if (!pgc_param_word(pgc, ¶m[n])) return 0; + } + for (n = 0; n < count; n++) + { + if (!pgc_commandlist_append(cl, param[n] & 0xFF) || + !pgc_commandlist_append(cl, param[n] >> 8)) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + free(param); + return 0; + } + } + return 1; +} + + + +/* Parse but don't execute a command with a fixed number of coord parameters */ +int pgc_parse_coords(pgc_core_t *pgc, pgc_commandlist_t *cl, int count) +{ + int32_t *param = malloc(count * sizeof(int32_t)); + int n; + + if (!param) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + return 0; + } + for (n = 0; n < count; n++) + { + if (!pgc_param_coord(pgc, ¶m[n])) return 0; + } +/* Here's how the real PGC serialises coords: + * + * 100.5 -> 64 00 00 80 ie 0064.8000 + * 100.3 -> 64 00 CD 4C ie 0064.4CCD + * + */ + for (n = 0; n < count; n++) + { + /* Serialise integer part */ + if (!pgc_commandlist_append(cl, (param[n] >> 16) & 0xFF) || + !pgc_commandlist_append(cl, (param[n] >> 24) & 0xFF) || + /* Serialise fraction part */ + !pgc_commandlist_append(cl, (param[n] ) & 0xFF) || + !pgc_commandlist_append(cl, (param[n] >> 8) & 0xFF)) + { + pgc_error(pgc, PGC_ERROR_OVERFLOW); + free(param); + return 0; + } + } + return 1; +} + + + +/* Handle the DISPLAY command */ +static void hndl_display(pgc_core_t *pgc) +{ + uint8_t param; + + if (!pgc_param_byte(pgc, ¶m)) return; + + PGCLOG(("DISPLAY(%d)\n", param)); + if (param > 1) + { + pgc_error(pgc, PGC_ERROR_RANGE); + } + else + { + pgc_setdisplay(pgc, param); + } +} + + +/* Handle the IMAGEW command (memory to screen blit) */ +static void hndl_imagew(pgc_core_t *pgc) +{ + int16_t row, col1, col2; + uint8_t v1, v2; + + if (!pgc_param_word(pgc, &row)) return; + if (!pgc_param_word(pgc, &col1)) return; + if (!pgc_param_word(pgc, &col2)) return; + + if (row >= pgc->screenh || col1 >= pgc->maxw || col2 >= pgc->maxw) + { + pgc_error(pgc, PGC_ERROR_RANGE); + return; + } + + /* In ASCII mode, what is written is a stream of bytes */ + if (pgc->ascii_mode) + { + while (col1 <= col2) + { + if (!pgc_param_byte(pgc, &v1)) return; + pgc_write_pixel(pgc, col1, row, v1); + ++col1; + } + return; + } + else /* In hex mode, it's RLE compressed */ + { + while (col1 <= col2) + { + if (!pgc_param_byte(pgc, &v1)) return; + + if (v1 & 0x80) /* Literal run */ + { + v1 -= 0x7F; + while (col1 <= col2 && v1 != 0) + { + if (!pgc_param_byte(pgc, &v2)) return; + pgc_write_pixel(pgc, col1, row, v2); + ++col1; + --v1; + } + } + else /* Repeated run */ + { + if (!pgc_param_byte(pgc, &v2)) return; + + ++v1; + while (col1 <= col2 && v1 != 0) + { + pgc_write_pixel(pgc, col1, row, v2); + ++col1; + --v1; + } + } + } + } +} + + +/* Select one of the built-in palettes */ +static void pgc_init_lut(pgc_core_t *pgc, int param) +{ + if (param >= 0 && param < 6) + { + memcpy(pgc->palette, init_palette[param], sizeof(pgc->palette)); + } + else if (param == 0xFF) + { + memcpy(pgc->palette, pgc->userpal, sizeof(pgc->palette)); + } + else + { + pgc_error(pgc, PGC_ERROR_RANGE); + } +} + +/* Save the current palette */ +static void hndl_lutsav(pgc_core_t *pgc) +{ + memcpy(pgc->userpal, pgc->palette, sizeof(pgc->palette)); +} + + +/* Handle LUTINT (select palette) */ +static void hndl_lutint(pgc_core_t *pgc) +{ + uint8_t param; + + if (!pgc_param_byte(pgc, ¶m)) return; + + pgc_init_lut(pgc, param); +} + + +/* Handle LUTRD (read palette register) */ +static void hndl_lutrd(pgc_core_t *pgc) +{ + uint8_t param; + uint32_t col; + + if (!pgc_param_byte(pgc, ¶m)) return; + + col = pgc->palette[param]; + + pgc_result_byte(pgc, (col >> 20) & 0x0F); + pgc_result_byte(pgc, (col >> 12) & 0x0F); + pgc_result_byte(pgc, (col >> 4) & 0x0F); +} + +/* Handle LUT (write palette register) */ +static void hndl_lut(pgc_core_t *pgc) +{ + uint8_t param[4]; + int n; + + for (n = 0; n < 4; n++) + { + if (!pgc_param_byte(pgc, ¶m[n])) return; + if (n > 0 && param[n] > 15) + { + pgc_error(pgc, PGC_ERROR_RANGE); + param[n] &= 0x0F; + } + } + pgc->palette[param[0]] = makecol((param[1] * 0x11), + (param[2] * 0x11), + (param[3] * 0x11)); +} + +/* LUT8RD and LUT8 are extensions implemented by several PGC clones, so + * here are functions that implement them even though they aren't + * used by the PGC */ +void pgc_hndl_lut8rd(pgc_core_t *pgc) +{ + uint8_t param; + uint32_t col; + + if (!pgc_param_byte(pgc, ¶m)) return; + + col = pgc->palette[param]; + + pgc_result_byte(pgc, (col >> 16) & 0xFF); + pgc_result_byte(pgc, (col >> 8) & 0xFF); + pgc_result_byte(pgc, col & 0xFF); +} + +void pgc_hndl_lut8(pgc_core_t *pgc) +{ + uint8_t param[4]; + int n; + + for (n = 0; n < 4; n++) + { + if (!pgc_param_byte(pgc, ¶m[n])) return; + } + pgc->palette[param[0]] = makecol((param[1]), (param[2]), (param[3])); +} + + +/* Handle AREAPT (set 16x16 fill pattern) */ +static void hndl_areapt(pgc_core_t *pgc) +{ + int16_t pattern[16]; + int n; + + for (n = 0; n < 16; n++) + { + if (!pgc_param_word(pgc, &pattern[n])) return; + } + memcpy(pgc->fill_pattern, pattern, sizeof(pgc->fill_pattern)); + PGCLOG(("AREAPT(%04x %04x %04x %04x...)\n", + pattern[0] & 0xFFFF, pattern[1] & 0xFFFF, + pattern[2] & 0xFFFF, pattern[3] & 0xFFFF)); +} + + +/* Handle CA (select ASCII mode) */ +static void hndl_ca(pgc_core_t *pgc) +{ + pgc->ascii_mode = 1; +} + +/* Handle CX (select hex mode) */ +static void hndl_cx(pgc_core_t *pgc) +{ + pgc->ascii_mode = 0; +} + +/* CA and CX remain valid in hex mode; they are handled as command 0x43 ('C') + * with a one-byte parameter */ +static void hndl_c(pgc_core_t *pgc) +{ + uint8_t param; + + if (!pgc->inputbyte(pgc, ¶m)) return; + + if (param == 'A') pgc->ascii_mode = 1; + if (param == 'X') pgc->ascii_mode = 0; +} + +/* RESETF resets the PGC */ +static void hndl_resetf(pgc_core_t *pgc) +{ + pgc_reset(pgc); +} + + + +/* TJUST sets text justify settings */ +static void hndl_tjust(pgc_core_t *pgc) +{ + uint8_t param[2]; + + if (!pgc->inputbyte(pgc, ¶m[0])) return; + if (!pgc->inputbyte(pgc, ¶m[1])) return; + + if (param[0] >= 1 && param[0] <= 3 && + param[1] >= 1 && param[1] <= 3) + { + pgc->tjust_h = param[0]; + pgc->tjust_v = param[1]; + } + else + { + pgc_error(pgc, PGC_ERROR_RANGE); + } +} + +/* TSIZE controls text horizontal spacing */ +static void hndl_tsize(pgc_core_t *pgc) +{ + int32_t param = 0; + + if (!pgc_param_coord(pgc, ¶m)) return; + + pgc->tsize = param; + PGCLOG(("TSIZE %d\n", param)); +} + + +/* VWPORT sets up the viewport (roughly, the clip rectangle) in raster + * coordinates, measured from the bottom left of the screen */ +static void hndl_vwport(pgc_core_t *pgc) +{ + int16_t x1, x2, y1, y2; + + if (!pgc_param_word(pgc, &x1)) return; + if (!pgc_param_word(pgc, &x2)) return; + if (!pgc_param_word(pgc, &y1)) return; + if (!pgc_param_word(pgc, &y2)) return; + + PGCLOG(("VWPORT %d,%d,%d,%d\n", x1,x2,y1,y2)); + pgc->vp_x1 = x1; + pgc->vp_x2 = x2; + pgc->vp_y1 = y1; + pgc->vp_y2 = y2; +} + +/* WINDOW defines the coordinate system in use */ +static void hndl_window(pgc_core_t *pgc) +{ + int16_t x1, x2, y1, y2; + + if (!pgc_param_word(pgc, &x1)) return; + if (!pgc_param_word(pgc, &x2)) return; + if (!pgc_param_word(pgc, &y1)) return; + if (!pgc_param_word(pgc, &y2)) return; + + PGCLOG(("WINDOW %d,%d,%d,%d\n", x1,x2,y1,y2)); + pgc->win_x1 = x1; + pgc->win_x2 = x2; + pgc->win_y1 = y1; + pgc->win_y2 = y2; +} + + + +/* The list of commands implemented by this mini-PGC. In order to support + * the original PGC and clones, we support two lists; core commands (listed + * below) and subclass commands (listed in the clone). + * + * Each row has five parameters: + * ASCII-mode command + * Hex-mode command + * Function that executes this command + * Function that parses this command when building a command list + * Parameter for the parse function + * + * TODO: This list omits numerous commands present in a genuine PGC + * (ARC, AREA, AREABC, BUFFER, CIRCLE etc etc). + * TODO: Some commands don't have a parse function (for example, IMAGEW) + * + * The following ASCII entries have special meaning: + * ~~~~~~ command is valid only in hex mode + * ****** end of subclass command list, now process core command list + * @@@@@@ end of core command list + * + */ +static const pgc_command_t pgc_core_commands[] = +{ + { "AREAPT", 0xE7, hndl_areapt, pgc_parse_words, 16 }, + { "AP", 0xE7, hndl_areapt, pgc_parse_words, 16 }, + { "~~~~~~", 0x43, hndl_c }, /* Handle CA / CX in hex mode */ + { "CA", 0xD2, hndl_ca }, + { "CLBEG", 0x70, hndl_clbeg }, + { "CB", 0x70, hndl_clbeg }, + { "CLDEL", 0x74, hndl_cldel, pgc_parse_bytes, 1 }, + { "CD", 0x74, hndl_cldel, pgc_parse_bytes, 1 }, + { "CLEND", 0x71, hndl_clend }, + { "CLRUN", 0x72, hndl_clrun, pgc_parse_bytes, 1 }, + { "CR", 0x72, hndl_clrun, pgc_parse_bytes, 1 }, + { "CLRD", 0x75, hndl_clread, pgc_parse_bytes, 1 }, + { "CRD", 0x75, hndl_clread, pgc_parse_bytes, 1 }, + { "CLOOP", 0x73, hndl_cloop }, + { "CL", 0x73, hndl_cloop }, + { "CLEARS", 0x0F, hndl_clears, pgc_parse_bytes, 1 }, + { "CLS", 0x0F, hndl_clears, pgc_parse_bytes, 1 }, + { "COLOR", 0x06, hndl_color, pgc_parse_bytes, 1 }, + { "C", 0x06, hndl_color, pgc_parse_bytes, 1 }, + { "CX", 0xD1, hndl_cx }, + { "DISPLA", 0xD0, hndl_display, pgc_parse_bytes, 1 }, + { "DI", 0xD0, hndl_display, pgc_parse_bytes, 1 }, + { "ELIPSE", 0x39, hndl_ellipse, pgc_parse_coords, 2 }, + { "EL", 0x39, hndl_ellipse, pgc_parse_coords, 2 }, + { "IMAGEW", 0xD9, hndl_imagew }, + { "IW", 0xD9, hndl_imagew }, + { "LINFUN", 0xEB, hndl_linfun, pgc_parse_bytes, 1 }, + { "LF", 0xEB, hndl_linfun, pgc_parse_bytes, 1 }, + { "LINPAT", 0xEA, hndl_linpat, pgc_parse_words, 1 }, + { "LP", 0xEA, hndl_linpat, pgc_parse_words, 1 }, + { "LUTINT", 0xEC, hndl_lutint, pgc_parse_bytes, 1 }, + { "LI", 0xEC, hndl_lutint, pgc_parse_bytes, 1 }, + { "LUTRD", 0x50, hndl_lutrd, pgc_parse_bytes, 1 }, + { "LUTSAV", 0xED, hndl_lutsav, NULL, 0 }, + { "LUT", 0xEE, hndl_lut, pgc_parse_bytes, 4 }, + { "MOVE", 0x10, hndl_move, pgc_parse_coords, 2 }, + { "M", 0x10, hndl_move, pgc_parse_coords, 2 }, + { "MOVE3", 0x12, hndl_move3, pgc_parse_coords, 3 }, + { "M3", 0x12, hndl_move3, pgc_parse_coords, 3 }, + { "MOVER", 0x11, hndl_mover, pgc_parse_coords, 2 }, + { "MR", 0x11, hndl_mover, pgc_parse_coords, 2 }, + { "MOVER3", 0x13, hndl_mover3, pgc_parse_coords, 3 }, + { "MR3", 0x13, hndl_mover3, pgc_parse_coords, 3 }, + { "PRMFIL", 0xE9, hndl_prmfil, pgc_parse_bytes, 1 }, + { "PF", 0xE9, hndl_prmfil, pgc_parse_bytes, 1 }, + { "POLY", 0x30, hndl_poly, parse_poly }, + { "P", 0x30, hndl_poly, parse_poly }, + { "RESETF", 0x04, hndl_resetf, NULL, 0 }, + { "RF", 0x04, hndl_resetf, NULL, 0 }, + { "TJUST", 0x85, hndl_tjust, pgc_parse_bytes, 2 }, + { "TJ", 0x85, hndl_tjust, pgc_parse_bytes, 2 }, + { "TSIZE", 0x81, hndl_tsize, pgc_parse_coords, 1 }, + { "TS", 0x81, hndl_tsize, pgc_parse_coords, 1 }, + { "VWPORT", 0xB2, hndl_vwport, pgc_parse_words, 4 }, + { "VWP", 0xB2, hndl_vwport, pgc_parse_words, 4 }, + { "WINDOW", 0xB3, hndl_window, pgc_parse_words, 4 }, + { "WI", 0xB3, hndl_window, pgc_parse_words, 4 }, + + { "@@@@@@", 0x00, NULL } +}; + + +/* Writes to CGA registers are copied into the transfer memory buffer */ +void pgc_out(uint16_t addr, uint8_t val, void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + + switch(addr) + { + case 0x3D0: case 0x3D2: case 0x3D4: case 0x3D6: + pgc->mapram[0x3D0] = val; break; + case 0x3D1: case 0x3D3: case 0x3D5: case 0x3D7: + if (pgc->mapram[0x3D0] < 18) + { + pgc->mapram[0x3E0 + pgc->mapram[0x3D0]] = val; + } + break; + case 0x3D8: pgc->mapram[0x3D8] = val; break; + case 0x3D9: pgc->mapram[0x3D9] = val; break; + } + +} + +/* Read back the CGA registers */ +uint8_t pgc_in(uint16_t addr, void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + + switch(addr) + { + case 0x3D0: case 0x3D2: case 0x3D4: case 0x3D6: + return pgc->mapram[0x3D0]; + case 0x3D1: case 0x3D3: case 0x3D5: case 0x3D7: + if (pgc->mapram[0x3D0] < 18) + { + return pgc->mapram[0x3E0 + pgc->mapram[0x3D0]]; + } + return 0xFF; + + case 0x3D8: return pgc->mapram[0x3D8]; + case 0x3D9: return pgc->mapram[0x3D9]; + case 0x3DA: return pgc->mapram[0x3DA]; + } + return 0xFF; +} + +/* Memory write to the transfer buffer */ +void pgc_write(uint32_t addr, uint8_t val, void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + + /* It seems variable whether the PGC maps 1k or 2k at 0xC6000. + * Map 2k here in case a clone requires it */ + if (addr >= 0xC6000 && addr < 0xC6800) + { + addr &= 0x7FF; + + /* If one of the FIFOs has been updated, this may cause + * the drawing thread to be woken */ + + if (pgc->mapram[addr] != val) + { + pgc->mapram[addr] = val; + switch (addr) + { + case 0x300: /* Input write pointer */ + if (pgc->waiting_input_fifo && + pgc->mapram[0x300] != pgc->mapram[0x301]) + { + pgc->waiting_input_fifo = 0; + pgc_wake(pgc); + } + break; + + case 0x303: /* Output read pointer */ + if (pgc->waiting_output_fifo && + pgc->mapram[0x302] != (uint8_t)(pgc->mapram[0x303] - 1)) + { + pgc->waiting_output_fifo = 0; + pgc_wake(pgc); + } + break; + + case 0x305: /* Error read pointer */ + if (pgc->waiting_error_fifo && + pgc->mapram[0x304] != (uint8_t)(pgc->mapram[0x305] - 1)) + { + pgc->waiting_error_fifo = 0; + pgc_wake(pgc); + } + break; + + case 0x306: /* Cold start flag */ + /* XXX This should be in IM-1024 specific code */ + pgc->mapram[0x306] = 0; + break; + + case 0x030C: /* Display type */ + pgc_setdisplay(p, pgc->mapram[0x30C]); + pgc->mapram[0x30D] = pgc->mapram[0x30C]; + break; + + + case 0x3FF: /* Reboot the PGC + (handled on core thread) */ + pgc_wake(pgc); + break; + } // end switch (addr) + } + } + if (addr >= 0xB8000 && addr < 0xBC000 && pgc->cga_selected) + { + addr &= 0x3FFF; + pgc->cga_vram[addr] = val; + } +} + + +uint8_t pgc_read(uint32_t addr, void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + + if (addr >= 0xC6000 && addr < 0xC6800) + { + addr &= 0x7FF; + + return pgc->mapram[addr]; + } + if (addr >= 0xB8000 && addr < 0xBC000 && pgc->cga_selected) + { + addr &= 0x3FFF; + return pgc->cga_vram[addr]; + } + return 0xFF; +} + +/* Called by the drawing thread to read the next byte from the input + * buffer. If no byte available will sleep until one is. Returns 0 if + * a PGC reset has been triggered by a write to 0xC63FF */ +int pgc_input_byte(pgc_core_t *pgc, uint8_t *result) +{ + /* If input buffer empty, wait for it to fill */ + while (pgc->mapram[0x300] == pgc->mapram[0x301]) + { + pgc->waiting_input_fifo = 1; + pgc_sleep(pgc); + } + if (pgc->mapram[0x3FF]) /* Reset triggered */ + { + pgc_reset(pgc); + return 0; + } + + *result = pgc->mapram[pgc->mapram[0x301]]; + ++pgc->mapram[0x301]; + return 1; +} + +/* Called by the drawing thread to write a byte to the output buffer. + * If buffer is full will sleep until it is not. Returns 0 if + * a PGC reset has been triggered by a write to 0xC63FF */ +int pgc_output_byte(pgc_core_t *pgc, uint8_t val) +{ + /* If output buffer full, wait for it to empty */ + while (pgc->mapram[0x302] == (uint8_t)(pgc->mapram[0x303] - 1)) + { + PGCLOG(("Output buffer state: %02x %02x Sleeping\n", + pgc->mapram[0x302], pgc->mapram[0x303])); + pgc->waiting_output_fifo = 1; + pgc_sleep(pgc); + } + if (pgc->mapram[0x3FF]) /* Reset triggered */ + { + pgc_reset(pgc); + return 0; + } + pgc->mapram[0x100 + pgc->mapram[0x302]] = val; + ++pgc->mapram[0x302]; +/* + PGCLOG(("Output %02x: new state: %02x %02x\n", val, + pgc->mapram[0x302], pgc->mapram[0x303])); */ + return 1; +} + +/* Helper to write an entire string to the output buffer */ +int pgc_output_string(pgc_core_t *pgc, const char *s) +{ + while (*s) + { + if (!pgc_output_byte(pgc, *s)) return 0; + ++s; + } + return 1; +} + +/* As pgc_output_byte, for the error buffer */ +int pgc_error_byte(pgc_core_t *pgc, uint8_t val) +{ + /* If error buffer full, wait for it to empty */ + while (pgc->mapram[0x304] == pgc->mapram[0x305] - 1) + { + pgc->waiting_error_fifo = 1; + pgc_sleep(pgc); + } + if (pgc->mapram[0x3FF]) /* Reset triggered */ + { + pgc_reset(pgc); + return 0; + } + pgc->mapram[0x200 + pgc->mapram[0x304]] = val; + ++pgc->mapram[0x304]; + return 1; +} + +/* As pgc_output_string, for the error buffer */ +int pgc_error_string(pgc_core_t *pgc, const char *s) +{ + while (*s) + { + if (!pgc_error_byte(pgc, *s)) return 0; + ++s; + } + return 1; +} + + +/* Report an error, either in ASCII or in hex */ +int pgc_error(pgc_core_t *pgc, int err) +{ + if (pgc->mapram[0x307]) /* Errors enabled? */ + { + if (pgc->ascii_mode) + { + if (err >= PGC_ERROR_RANGE && err <= PGC_ERROR_MISSING) + return pgc_error_string(pgc, pgc_err_msgs[err]); + return pgc_error_string(pgc, "Unknown error\r"); + } + else + { + return pgc_error_byte(pgc, err); + } + } + return 1; +} + + +static inline int is_whitespace(char ch) +{ + return (ch != 0 && strchr(" \r\n\t,;()+-", ch) != NULL); +} + + +/* Read a byte and interpret as ASCII: ignore control characters other than + * CR, LF or tab. */ +int pgc_input_char(pgc_core_t *pgc, char *result) +{ + uint8_t ch; + + while (1) + { + if (!pgc->inputbyte(pgc, &ch)) return 0; + + ch &= 0x7F; + if (ch == '\r' || ch == '\n' || ch == '\t' || ch >= ' ') + { + *result = toupper(ch); + return 1; + } + } +} + + +/* Parameter passed is not a number: abort */ +static int err_digit(pgc_core_t *pgc) +{ + uint8_t asc; + + do /* Swallow everything until the next separator */ + { + if (!pgc->inputbyte(pgc, &asc)) return 0; + } + while (!is_whitespace(asc)); + pgc_error(pgc, PGC_ERROR_DIGIT); + return 0; +} + + +typedef enum parse_state_t +{ + PS_MAIN, + PS_FRACTION, + PS_EXPONENT +} parse_state_t; + +/* Read in a PGC coordinate, either as hex (4 bytes) or ASCII (xxxx.yyyyEeee) + * Returns 0 if PGC reset detected while the value is being read */ +int pgc_param_coord(pgc_core_t *pgc, int32_t *value) +{ + uint8_t asc; + int sign = 1; + int esign = 1; + int n; + uint16_t dp = 1; + uint16_t integer = 0; + uint16_t frac = 0; + uint16_t exponent = 0; + uint32_t res; + parse_state_t state = PS_MAIN; + uint8_t encoded[4]; + + /* If there is a command list running, pull the bytes out of that + * command list */ + if (pgc->clcur) + { + for (n = 0; n < 4; n++) + { + if (!pgc_clist_byte(pgc, &encoded[n])) return 0; + } + integer = (((int16_t)encoded[1]) << 8) | encoded[0]; + frac = (((int16_t)encoded[3]) << 8) | encoded[2]; + + *value = (((int32_t)integer) << 16) | frac; + return 1; + } + /* If in hex mode, read in the encoded integer and fraction parts + * from the hex stream */ + if (!pgc->ascii_mode) + { + for (n = 0; n < 4; n++) + { + if (!pgc->inputbyte(pgc, &encoded[n])) return 0; + } + integer = (((int16_t)encoded[1]) << 8) | encoded[0]; + frac = (((int16_t)encoded[3]) << 8) | encoded[2]; + + *value = (((int32_t)integer) << 16) | frac; + return 1; + } + /* Parsing an ASCII value */ + + /* Skip separators */ + do + { + if (!pgc->inputbyte(pgc, &asc)) return 0; + if (asc == '-') sign = -1; + } + while (is_whitespace(asc)); + + /* There had better be a digit next */ + if (!isdigit(asc)) + { + pgc_error(pgc, PGC_ERROR_MISSING); + return 0; + } + do + { + switch (asc) + { +/* Decimal point is acceptable in 'main' state (start of fraction) + * not otherwise */ + case '.': + if (state == PS_MAIN) + { + if (!pgc->inputbyte(pgc, &asc)) return 0; + state = PS_FRACTION; + continue; + } + else + { + pgc_error(pgc, PGC_ERROR_MISSING); + return err_digit(pgc); + } + break; + /* Scientific notation */ + case 'd': case 'D': case 'e': case 'E': + esign = 1; + if (!pgc->inputbyte(pgc, &asc)) return 0; + if (asc == '-') + { + sign = -1; + if (!pgc->inputbyte(pgc, &asc)) return 0; + } + state = PS_EXPONENT; + continue; + /* Should be a number or a separator */ + default: + if (is_whitespace(asc)) break; + if (!isdigit(asc)) + { + pgc_error(pgc, PGC_ERROR_MISSING); + return err_digit(pgc); + } + asc -= '0'; /* asc is digit */ + switch (state) + { + case PS_MAIN: + integer = (integer * 10)+asc; + if (integer & 0x8000) /* Overflow */ + { + pgc_error(pgc, PGC_ERROR_RANGE); + integer = 0x7FFF; + } + break; + case PS_FRACTION: + frac = (frac * 10)+asc; + dp *= 10; + break; + case PS_EXPONENT: + exponent = (exponent * 10)+asc; + break; + } + + } + if (!pgc->inputbyte(pgc, &asc)) return 0; + } + while (!is_whitespace(asc)); + + + res = (frac << 16) / dp; + PGCLOG(("integer=%u frac=%u exponent=%u dp=%d res=0x%08x\n", + integer, frac, exponent, dp, res)); + + res = (res & 0xFFFF) | (integer << 16); + if (exponent) + { + for (n = 0; n < exponent; n++) + { + if (esign > 0) res *= 10; + else res /= 10; + } + } + *value = sign*res; + + return 1; +} + +/* Pull the next byte from the current command list */ +int pgc_clist_byte(pgc_core_t *pgc, uint8_t *val) +{ + if (pgc->clcur == NULL) return 0; + + if (pgc->clcur->rdptr < pgc->clcur->wrptr) + { + *val = pgc->clcur->list[pgc->clcur->rdptr++]; + } + else + { + *val = 0; + } + /* If we've reached the end, reset to the beginning and + * (if repeating) run the repeat */ + if (pgc->clcur->rdptr >= pgc->clcur->wrptr) + { + pgc->clcur->rdptr = 0; + --pgc->clcur->repeat; + if (pgc->clcur->repeat == 0) + { + pgc->clcur = pgc->clcur->chain; + } + } + return 1; +} + + +/* Read in a byte, either as hex (1 byte) or ASCII (decimal). + * Returns 0 if PGC reset detected while the value is being read */ +int pgc_param_byte(pgc_core_t *pgc, uint8_t *val) +{ + int32_t c; + + if (pgc->clcur) return pgc_clist_byte(pgc, val); + + if (!pgc->ascii_mode) return pgc->inputbyte(pgc, val); + + if (!pgc_param_coord(pgc, &c)) return 0; + c = (c >> 16); /* Drop fractional part */ + + if (c > 255) + { + pgc_error(pgc, PGC_ERROR_RANGE); + return 0; + } + *val = (uint8_t)c; + return 1; +} + +/* Read in a word, either as hex (2 bytes) or ASCII (decimal). + * Returns 0 if PGC reset detected while the value is being read */ +int pgc_param_word(pgc_core_t *pgc, int16_t *val) +{ + int32_t c; + + if (pgc->clcur) + { + uint8_t lo, hi; + + if (!pgc_clist_byte(pgc, &lo)) return 0; + if (!pgc_clist_byte(pgc, &hi)) return 0; + *val = (((int16_t)hi) << 8) | lo; + return 1; + } + + if (!pgc->ascii_mode) + { + uint8_t lo, hi; + + if (!pgc->inputbyte(pgc, &lo)) return 0; + if (!pgc->inputbyte(pgc, &hi)) return 0; + *val = (((int16_t)hi) << 8) | lo; + return 1; + } + + if (!pgc_param_coord(pgc, &c)) return 0; + + c = (c >> 16); + if (c > 0x7FFF || c < -0x7FFF) + { + pgc_error(pgc, PGC_ERROR_RANGE); + return 0; + } + *val = (int16_t)c; + return 1; +} + + +/* Output a byte, either as hex or ASCII depending on the mode */ +int pgc_result_byte(pgc_core_t *pgc, uint8_t val) +{ + char buf[20]; + + if (!pgc->ascii_mode) return pgc_output_byte(pgc, val); + + if (pgc->result_count) + { + if (!pgc_output_byte(pgc, ',')) return 0; + } + sprintf(buf, "%d", val); + ++pgc->result_count; + return pgc_output_string(pgc, buf); +} + + +/* Output a word, either as hex or ASCII depending on the mode */ +int pgc_result_word(pgc_core_t *pgc, int16_t val) +{ + char buf[20]; + + if (!pgc->ascii_mode) + { + if (!pgc_output_byte(pgc, val & 0xFF)) return 0; + return pgc_output_byte(pgc, val >> 8); + } + + if (pgc->result_count) + { + if (!pgc_output_byte(pgc, ',')) return 0; + } + sprintf(buf, "%d", val); + ++pgc->result_count; + return pgc_output_string(pgc, buf); +} + + +/* Write a screen pixel (x and y are raster coordinates, ink is the + * value to write) */ +void pgc_write_pixel(pgc_core_t *pgc, uint16_t x, uint16_t y, uint8_t ink) +{ + uint8_t *vram; + + /* Suppress out-of-range writes; clip to viewport */ + if (x < pgc->vp_x1 || x > pgc->vp_x2 || x >= pgc->maxw || + y < pgc->vp_y1 || y > pgc->vp_y2 || y >= pgc->maxh) + { + PGCLOG(("pgc_write_pixel clipped: (%d,%d) " + "vp_x1=%d vp_y1=%d vp_x2=%d vp_y2=%d " + "ink=0x%02x\n", x, y, + pgc->vp_x1, pgc->vp_y1, + pgc->vp_x2, pgc->vp_y2, ink)); + return; + } + vram = pgc_vram_addr(pgc, x, y); + if (vram) *vram = ink; +} + +/* Read a screen pixel (x and y are raster coordinates) */ +uint8_t pgc_read_pixel(pgc_core_t *pgc, uint16_t x, uint16_t y) +{ + uint8_t *vram; + + /* Suppress out-of-range reads */ + if (x >= pgc->maxw || y >= pgc->maxh) + { + return 0; + } + vram = pgc_vram_addr(pgc, x, y); + if (vram) return *vram; + return 0; +} + + + + +/* Plot a point in the current colour and draw mode. Raster coordinates. */ +void pgc_plot(pgc_core_t *pgc, uint16_t x, uint16_t y) +{ + uint8_t *vram; + + /* Only allow plotting within the current viewport. */ + if (x < pgc->vp_x1 || x > pgc->vp_x2 || x >= pgc->maxw || + y < pgc->vp_y1 || y > pgc->vp_y2 || y >= pgc->maxh) + { + PGCLOG(("pgc_plot clipped: (%d,%d) %d <= x <= %d; %d <= y <= %d; " + "mode=%d ink=0x%02x\n", x, y, + pgc->vp_x1, pgc->vp_x2, pgc->vp_y1, pgc->vp_y2, + pgc->draw_mode, pgc->colour)); + return; + } + vram = pgc_vram_addr(pgc, x, y); + if (!vram) return; + + /* TODO: Does not implement the PGC plane mask (set by MASK) */ + switch (pgc->draw_mode) + { + default: + case 0: *vram = pgc->colour; break; /* Write */ + case 1: *vram ^= 0xFF; break; /* Invert */ + case 2: *vram ^= pgc->colour; break; /* XOR colour */ + case 3: *vram &= pgc->colour; break; /* AND */ + } +} + + +/* Given raster coordinates, find the matching address in PGC video RAM */ +uint8_t *pgc_vram_addr(pgc_core_t *pgc, int16_t x, int16_t y) +{ + int offset; + +/* We work from the bottom left-hand corner */ + if (y < 0 || y >= pgc->maxh || x < 0 || x >= pgc->maxw) return NULL; + + offset = (pgc->maxh - 1 -y) * (pgc->maxw) + x; +// PGCLOG(("pgc_vram_addr x=%d y=%d offset=%d\n", x, y, offset); + + if (offset < 0 || offset >= (pgc->maxw * pgc->maxh)) + { + return NULL; + } + return &pgc->vram[offset]; +} + + + +/* Read in the next command, either as hex (1 byte) or ASCII (up to 6 + * characters) */ +int pgc_read_command(pgc_core_t *pgc) +{ + if (pgc->clcur) + { + return pgc_clist_byte(pgc, &pgc->hex_command); + } + else if (pgc->ascii_mode) + { + char ch; + int count = 0; + + while (count < 7) + { + if (!pgc_input_char(pgc, &ch)) return 0; + if (is_whitespace(ch)) + { + /* Pad to 6 characters */ + while (count < 6) + pgc->asc_command[count++] = ' '; + pgc->asc_command[6] = 0; + return 1; + } + pgc->asc_command[count++] = toupper(ch); + } + return 1; + } + else + { + return pgc->inputbyte(pgc, &pgc->hex_command); + } +} + + +/* Read in the next command and parse it */ +static int pgc_parse_command(pgc_core_t *pgc, const pgc_command_t **pcmd) +{ + const pgc_command_t *cmd; + char match[7]; + + *pcmd = NULL; + pgc->hex_command = 0; + memset(pgc->asc_command, ' ', 6); + pgc->asc_command[6] = 0; + if (!pgc_read_command(pgc)) + { + /* PGC has been reset */ + return 0; + } +/* Scan the list of valid commands. pgc->pgc_commands may be a subclass + * list (terminated with '*') or the core list (terminated with '@') */ + for (cmd = pgc->pgc_commands; cmd->ascii[0] != '@'; cmd++) + { + /* End of subclass command list, chain to core */ + if (cmd->ascii[0] == '*') cmd = pgc_core_commands; + + /* If in ASCII mode match on the ASCII command */ + if (pgc->ascii_mode && !pgc->clcur) + { + sprintf(match, "%-6.6s", cmd->ascii); + if (!strncmp(match, pgc->asc_command, 6)) + { + *pcmd = cmd; + pgc->hex_command = cmd->hex; + break; + } + } + else /* Otherwise match on the hex command */ + { + if (cmd->hex == pgc->hex_command) + { + sprintf(pgc->asc_command, "%-6.6s", + cmd->ascii); + *pcmd = cmd; + break; + } + } + } + return 1; +} + + +/* The PGC drawing thread main loop. Read in commands and execute them ad + * infinitum */ +void pgc_core_thread(void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + const pgc_command_t *cmd; + + PGCLOG(("pgc_core_thread begins")); + while (1) + { + if (!pgc_parse_command(pgc, &cmd)) + { + /* PGC has been reset */ + continue; + } + PGCLOG(("PGC command: [%02x] '%s' found=%d\n", + pgc->hex_command, pgc->asc_command, (cmd != NULL))); + + if (cmd) + { + pgc->result_count = 0; + (*cmd->handler)(pgc); + } + else + { + pgc_error(pgc, PGC_ERROR_OPCODE); + } + } +} + +void pgc_recalctimings(pgc_core_t *pgc) +{ + double disptime, _dispontime, _dispofftime; + double pixel_clock = (cpuclock * (double)(1ull << 32)) / (pgc->cga_selected ? 25175000.0 : pgc->native_pixel_clock); + + /* Use a fixed 640 columns, like the T3100e */ + disptime = pgc->screenw + 11; + _dispontime = pgc->screenw * pixel_clock; + _dispofftime = (disptime - pgc->screenw) * pixel_clock; + pgc->dispontime = (uint64_t)_dispontime; + pgc->dispofftime = (uint64_t)_dispofftime; +} + +/* Draw the display in CGA (640x400) text mode */ +void pgc_cga_text(pgc_core_t *pgc, int w) +{ + int x, c; + uint8_t chr, attr; + int drawcursor = 0; + uint32_t cols[2]; + int pitch = (pgc->mapram[0x3E9] + 1) * 2; + uint16_t sc = (pgc->displine & 0x0F) % pitch; + uint16_t ma = (pgc->mapram[0x3ED] | (pgc->mapram[0x3EC] << 8)) & 0x3fff; + uint16_t ca = (pgc->mapram[0x3EF] | (pgc->mapram[0x3EE] << 8)) & 0x3fff; + uint8_t *addr; + int cw = (w == 80) ? 8 : 16; + + addr = &pgc->cga_vram[((ma << 1) + (((pgc->displine / pitch)*w)) * 2) & 0x3ffe]; + ma += (pgc->displine / pitch) * w; + + for (x = 0; x < w; x++) + { + chr = addr[0]; + attr = addr[1]; + addr += 2; + + /* Cursor enabled? */ + if (ma == ca && (pgc->cgablink & 8) && + (pgc->mapram[0x3EA] & 0x60) != 0x20) + { + drawcursor = ((pgc->mapram[0x3EA] & 0x1F) <= (sc >> 1)) + && ((pgc->mapram[0x3EB] & 0x1F) >= (sc >> 1)); + } + else drawcursor = 0; + if (pgc->mapram[0x3D8] & 0x20) + { + cols[1] = attr & 15; + cols[0] = (attr >> 4) & 7; + if ((pgc->cgablink & 8) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = attr & 15; + cols[0] = attr >> 4; + } + if (drawcursor) + { + for (c = 0; c < cw; c++) + { + if (w == 80) + ((uint32_t *)buffer32->line[pgc->displine & 2047])[(x << 3) + c] = cols[(fontdatm[chr + pgc->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + else + ((uint32_t *)buffer32->line[pgc->displine & 2047])[(x << 4) + c] = cols[(fontdatm[chr + pgc->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + } + } + else + { + for (c = 0; c < cw; c++) + { + if (w == 80) + ((uint32_t *)buffer32->line[pgc->displine & 2047])[(x << 3) + c] = cols[(fontdatm[chr + pgc->fontbase][sc] & (1 << (c ^ 7))) ? 1 : 0]; + else + ((uint32_t *)buffer32->line[pgc->displine & 2047])[(x << 4) + c] = cols[(fontdatm[chr + pgc->fontbase][sc] & (1 << ((c >> 1) ^ 7))) ? 1 : 0]; + } + } + ma++; + } +} + + +/* Draw the display in CGA (320x200) graphics mode */ +void pgc_cga_gfx40(pgc_core_t *pgc) +{ + int x, c; + uint32_t cols[4]; + int col; + uint16_t ma = (pgc->mapram[0x3ED] | (pgc->mapram[0x3EC] << 8)) & 0x3fff; + uint8_t *addr; + uint16_t dat; + + cols[0] = pgc->mapram[0x3D9] & 15; + col = (pgc->mapram[0x3D9] & 16) ? 8 : 0; + + if (pgc->mapram[0x3D8] & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (pgc->mapram[0x3D9] & 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++) + { + addr = &pgc->cga_vram[(ma + 2 * x + 80 * (pgc->displine >> 2) + 0x2000 * ((pgc->displine >> 1) & 1)) & 0x3FFF]; + dat = (addr[0] << 8) | addr[1]; + pgc->ma++; + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[pgc->displine & 2047])[(x << 4) + (c << 1)] = + ((uint32_t *)buffer32->line[pgc->displine & 2047])[(x << 4) + (c << 1) + 1] = cols[dat >> 14]; + dat <<= 2; + } + } +} + + +/* Draw the display in CGA (640x200) graphics mode */ +void pgc_cga_gfx80(pgc_core_t *pgc) +{ + int x, c; + uint32_t cols[2]; + uint16_t ma = (pgc->mapram[0x3ED] | (pgc->mapram[0x3EC] << 8)) & 0x3fff; + uint8_t *addr; + uint16_t dat; + + cols[0] = 0; + cols[1] = pgc->mapram[0x3D9] & 15; + + for (x = 0; x < 40; x++) + { + addr = &pgc->cga_vram[(ma + 2 * x + 80 * (pgc->displine >> 2) + 0x2000 * ((pgc->displine >> 1) & 1)) & 0x3FFF]; + dat = (addr[0] << 8) | addr[1]; + pgc->ma++; + for (c = 0; c < 16; c++) + { + ((uint32_t *)buffer32->line[pgc->displine & 2047])[(x << 4) + c] = cols[dat >> 15]; + dat <<= 1; + } + } +} + + + +/* Draw the screen in CGA mode. Based on the simplified WY700 renderer + * rather than the original CGA, since the PGC doesn't have a real 6845 */ +void pgc_cga_poll(pgc_core_t *pgc) +{ + int c; + uint32_t cols[2]; + + if (!pgc->linepos) + { + timer_advance_u64(&pgc->timer, pgc->dispofftime); + pgc->mapram[0x3DA] |= 1; + pgc->linepos = 1; + if (pgc->cgadispon) + { + if (pgc->displine == 0) + { + video_wait_for_buffer(); + } + + if ((pgc->mapram[0x3D8] & 0x12) == 0x12) + { + pgc_cga_gfx80(pgc); + } + else if (pgc->mapram[0x3D8] & 0x02) + { + pgc_cga_gfx40(pgc); + } + else if (pgc->mapram[0x3D8] & 0x01) + { + pgc_cga_text(pgc, 80); + } + else + { + pgc_cga_text(pgc, 40); + } + } + else + { + cols[0] = ((pgc->mapram[0x3D8] & 0x12) == 0x12) ? 0 : (pgc->mapram[0x3D9] & 15); + hline(buffer32, 0, pgc->displine & 2047, PGC_CGA_WIDTH, cols[0]); + } + + for (c = 0; c < PGC_CGA_WIDTH; c++) + ((uint32_t *)buffer32->line[pgc->displine & 2047])[c] = cgapal[((uint32_t *)buffer32->line[pgc->displine & 2047])[c] & 0xf]; + + pgc->displine++; + if (pgc->displine == PGC_CGA_HEIGHT) + { + pgc->mapram[0x3DA] |= 8; + pgc->cgadispon = 0; + } + if (pgc->displine == PGC_CGA_HEIGHT + 32) + { + pgc->mapram[0x3DA] &= ~8; + pgc->cgadispon = 1; + pgc->displine = 0; + } + } + else + { + if (pgc->cgadispon) + { + pgc->mapram[0x3DA] &= ~1; + } + timer_advance_u64(&pgc->timer, pgc->dispontime); + pgc->linepos = 0; + + if (pgc->displine == PGC_CGA_HEIGHT) + { + if (PGC_CGA_WIDTH != xsize || PGC_CGA_HEIGHT != ysize) + { + xsize = PGC_CGA_WIDTH; + ysize = PGC_CGA_HEIGHT; + updatewindowsize(xsize, ysize); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + frames++; + + /* We have a fixed 640x400 screen for + * CGA modes */ + video_res_x = PGC_CGA_WIDTH; + video_res_y = PGC_CGA_HEIGHT; + switch (pgc->mapram[0x3D8] & 0x12) + { + case 0x12: video_bpp = 1; break; + case 0x02: video_bpp = 2; break; + default: video_bpp = 0; break; + } + pgc->cgablink++; + } + } +} + + + +/* Draw the screen in CGA or native mode. */ +void pgc_poll(void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + int x, y; + + if (pgc->cga_selected) + { + pgc_cga_poll(pgc); + return; + } +/* Not CGA, so must be native mode */ + if (!pgc->linepos) + { + timer_advance_u64(&pgc->timer, pgc->dispofftime); + pgc->mapram[0x3DA] |= 1; + pgc->linepos = 1; + if (pgc->cgadispon && pgc->displine < pgc->maxh) + { + if (pgc->displine == 0) + { + video_wait_for_buffer(); + } + /* Don't know why pan needs to be multiplied by -2, but + * the IM1024 driver uses PAN -112 for an offset of + * 224. */ + y = pgc->displine - 2 * pgc->pan_y; + for (x = 0; x < pgc->screenw; x++) + { + if (x + pgc->pan_x < pgc->maxw) + { + ((uint32_t *)buffer32->line[pgc->displine & 2047])[x] = pgc->palette[pgc->vram[y * pgc->maxw + x]]; + } + else + { + ((uint32_t *)buffer32->line[pgc->displine & 2047])[x] = pgc->palette[0]; + } + } + } + else + { + hline(buffer32, 0, pgc->displine & 2047, pgc->screenw, pgc->palette[0]); + } + pgc->displine++; + if (pgc->displine == pgc->screenh) + { + pgc->mapram[0x3DA] |= 8; + pgc->cgadispon = 0; + } + if (pgc->displine == pgc->screenh + 32) + { + pgc->mapram[0x3DA] &= ~8; + pgc->cgadispon = 1; + pgc->displine = 0; + } + } + else + { + if (pgc->cgadispon) + { + pgc->mapram[0x3DA] &= ~1; + } + timer_advance_u64(&pgc->timer, pgc->dispontime); + pgc->linepos = 0; + + if (pgc->displine == pgc->screenh) + { + if (pgc->screenw != xsize || pgc->screenh != ysize) + { + xsize = pgc->screenw; + ysize = pgc->screenh; + updatewindowsize(xsize, ysize); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + frames++; + + video_res_x = pgc->screenw; + video_res_y = pgc->screenh; + video_bpp = 8; + pgc->cgablink++; + } + } +} + + +/* Initialise RAM and registers to default values */ +void pgc_reset(pgc_core_t *pgc) +{ + int n; + + memset(pgc->mapram, 0, sizeof(pgc->mapram)); +/* There is no point in emulating the 'CGA disable' jumper as this is only + * appropriate for a dual-head system, not emulated by PCEM */ + pgc->mapram[0x30B] = pgc->cga_enabled = 1; + pgc->mapram[0x3F8] = 0x03; /* Minor version */ + pgc->mapram[0x3F9] = 0x01; /* Minor version */ + pgc->mapram[0x3FB] = 0xA5; /* } */ + pgc->mapram[0x3FC] = 0x5A; /* PGC self-test passed */ + pgc->mapram[0x3FD] = 0x55; /* } */ + pgc->mapram[0x3FE] = 0x5A; /* } */ + + pgc->ascii_mode = 1; /* Start off in ASCII mode */ + pgc->line_pattern = 0xFFFF; + memset(pgc->fill_pattern, 0xFF, sizeof(pgc->fill_pattern)); + pgc->colour = 0xFF; + pgc->tjust_h = 1; + pgc->tjust_v = 1; + + /* Reset panning */ + pgc->pan_x = 0; + pgc->pan_y = 0; + + /* Reset clipping */ + pgc->vp_x1 = 0; + pgc->vp_y1 = 0; + pgc->vp_x2 = pgc->visw - 1; + pgc->vp_y2 = pgc->vish - 1; + + /* Empty command lists */ + for (n = 0; n < 256; n++) + { + pgc->clist[n].wrptr = 0; + pgc->clist[n].rdptr = 0; + pgc->clist[n].repeat = 0; + pgc->clist[n].chain = 0; + } + pgc->clcur = NULL; + /* Select CGA display */ + pgc->cga_selected = -1; + pgc_setdisplay(pgc, pgc->cga_enabled); + pgc->mapram[0x30C] = pgc->cga_enabled; + pgc->mapram[0x30D] = pgc->cga_enabled; + /* Default palette is 0 */ + pgc_init_lut(pgc, 0); + hndl_lutsav(pgc); +} + + +/* Initialisation code common to the PGC and its subclasses. + * + * Pass the 'input byte' function in since this is overridden in + * the IM-1024, and needs to be set before the drawing thread is + * launched */ +void pgc_core_init(pgc_core_t *pgc, int maxw, int maxh, int visw, int vish, + int (*inpbyte)(struct pgc_core_t *pgc, uint8_t *result), double native_pixel_clock) +{ + int n; + + mem_mapping_add(&pgc->mapping, 0xC6000, 0x800, + pgc_read, NULL, NULL, + pgc_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, pgc); + mem_mapping_add(&pgc->cga_mapping, 0xB8000, 0x8000, + pgc_read, NULL, NULL, + pgc_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, pgc); + io_sethandler(0x3D0, 0x0010, pgc_in, NULL, NULL, pgc_out, NULL, NULL, + pgc); + + pgc->maxw = maxw; + pgc->maxh = maxh; + pgc->visw = visw; + pgc->vish = vish; + pgc->vram = malloc(maxw * maxh); + pgc->cga_vram = malloc(0x4000); + pgc->clist = calloc(256, sizeof(pgc_commandlist_t)); + pgc->clcur = NULL; + pgc->native_pixel_clock = native_pixel_clock; + + memset(pgc->vram, 0, maxw * maxh); + memset(pgc->cga_vram, 0, 0x4000); + /* Empty command lists */ + for (n = 0; n < 256; n++) + { + pgc->clist[n].list = NULL; + pgc->clist[n].listmax = 0; + pgc->clist[n].wrptr = 0; + pgc->clist[n].rdptr = 0; + pgc->clist[n].repeat = 0; + pgc->clist[n].chain = NULL; + } + + pgc_reset(pgc); + pgc->inputbyte = inpbyte; + pgc->pgc_commands = pgc_core_commands; + pgc->pgc_wake_thread = thread_create_event(); + pgc->pgc_thread = thread_create(pgc_core_thread, pgc); + + timer_add(&pgc->timer, pgc_poll, (void *)pgc, 1); + + timer_add(&pgc->wake_timer, pgc_wake_timer, (void *)pgc, 0); +} + + +/* Initialisation code specific to the PGC */ +void *pgc_standalone_init() +{ + pgc_core_t *pgc = malloc(sizeof(pgc_core_t)); + memset(pgc, 0, sizeof(pgc_core_t)); + + /* Framebuffer and screen are both 640x480 */ + pgc_core_init(pgc, 640, 480, 640, 480, pgc_input_byte, 25175000.0); + return pgc; +} + + +void pgc_close(void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + + thread_kill(pgc->pgc_thread); + thread_destroy_event(pgc->pgc_wake_thread); + + if (pgc->cga_vram) + { + free(pgc->cga_vram); + } + if (pgc->vram) + { + free(pgc->vram); + } + free(pgc); +} + +void pgc_speed_changed(void *p) +{ + pgc_core_t *pgc = (pgc_core_t *)p; + + pgc_recalctimings(pgc); +} + + +device_config_t pgc_config[] = +{ + { + .type = -1 + } +}; + +device_t pgc_device = +{ + "PGC", + 0, + pgc_standalone_init, + pgc_close, + NULL, + pgc_speed_changed, + NULL, + NULL, + pgc_config +}; + diff --git a/src/vid_pgc.h b/src/vid_pgc.h new file mode 100644 index 0000000..621f4a3 --- /dev/null +++ b/src/vid_pgc.h @@ -0,0 +1,164 @@ +#include "timer.h" + +struct pgc_core_t; + +typedef struct pgc_commandlist_t +{ + uint8_t *list; + uint32_t listmax; + uint32_t wrptr; + uint32_t rdptr; + uint32_t repeat; + struct pgc_commandlist_t *chain; +} pgc_commandlist_t; + +int pgc_commandlist_append(pgc_commandlist_t *list, uint8_t v); + +typedef struct pgc_command_t +{ + char ascii[6]; + uint8_t hex; + void (*handler)(struct pgc_core_t *pgc); + int (*parser) (struct pgc_core_t *pgc, pgc_commandlist_t *cl, + int p); + int p; +} pgc_command_t; + + +typedef struct pgc_core_t +{ + mem_mapping_t mapping; + mem_mapping_t cga_mapping; + + pgc_commandlist_t *clist; + pgc_commandlist_t *clcur; + uint8_t mapram[2048]; /* Host <--> PGC communication buffer */ + uint8_t *cga_vram; + uint8_t *vram; + char asc_command[7]; + uint8_t hex_command; + uint32_t palette[256]; + uint32_t userpal[256]; + uint32_t maxw, maxh; /* Maximum framebuffer size */ + uint32_t visw, vish; /* Maximum screen size */ + uint32_t screenw, screenh; + int16_t pan_x, pan_y; + uint16_t win_x1, win_x2, win_y1, win_y2; + uint16_t vp_x1, vp_x2, vp_y1, vp_y2; + int16_t fill_pattern[16]; + int16_t line_pattern; + uint8_t draw_mode; + uint8_t fill_mode; + uint8_t colour; + uint8_t tjust_h; /* Horizontal alignment 1=left 2=centre 3=right*/ + uint8_t tjust_v; /* Vertical alignment 1=bottom 2=centre 3=top*/ + int32_t tsize; /* Horizontal spacing */ + + int32_t x, y, z;/* Drawing position */ + + const pgc_command_t *pgc_commands; + thread_t *pgc_thread; + event_t *pgc_wake_thread; + pc_timer_t wake_timer; +// int wake_timer; + + int waiting_input_fifo; + int waiting_output_fifo; + int waiting_error_fifo; + int cga_enabled; + int cga_selected; + int ascii_mode; + int result_count; + + int fontbase; + int linepos, displine; + int vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int oddeven; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; +// int vidtime; + double native_pixel_clock; + + int drawcursor; + + int (*inputbyte)(struct pgc_core_t *pgc, uint8_t *result); + +} pgc_core_t; + +void pgc_init(pgc_core_t *pgc); +void pgc_out(uint16_t addr, uint8_t val, void *p); +uint8_t pgc_in(uint16_t addr, void *p); +void pgc_write(uint32_t addr, uint8_t val, void *p); +uint8_t pgc_read(uint32_t addr, void *p); +void pgc_recalctimings(pgc_core_t *pgc); +void pgc_poll(void *p); +void pgc_reset(pgc_core_t *pgc); +void pgc_wake(pgc_core_t *pgc); +/* Plot a pixel (raster coordinates, current ink) */ +void pgc_plot(pgc_core_t *pgc, uint16_t x, uint16_t y); +void pgc_write_pixel(pgc_core_t *pgc, uint16_t x, uint16_t y, uint8_t ink); +uint8_t pgc_read_pixel(pgc_core_t *pgc, uint16_t x, uint16_t y); +uint8_t *pgc_vram_addr(pgc_core_t *pgc, int16_t x, int16_t y); +/* Draw line (window coordinates) */ +uint16_t pgc_draw_line(pgc_core_t *pgc, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint16_t linemask); +/* Draw line (raster coordinates) */ +uint16_t pgc_draw_line_r(pgc_core_t *pgc, int32_t x1, int32_t y1, int32_t x2, int32_t y2, uint16_t linemask); +void pgc_draw_ellipse(pgc_core_t *pgc, int32_t x, int32_t y); +void pgc_fill_polygon(pgc_core_t *pgc, unsigned corners, int32_t *x, int32_t *y); +/* Horizontal line in fill pattern (raster coordinates) */ +void pgc_fill_line_r(pgc_core_t *pgc, int32_t x0, int32_t x1, int32_t y); + +/* Convert to raster coordinates */ +void pgc_sto_raster(pgc_core_t *pgc, int16_t *x, int16_t *y); +void pgc_ito_raster(pgc_core_t *pgc, int32_t *x, int32_t *y); +void pgc_dto_raster(pgc_core_t *pgc, double *x, double *y); + +/* Read/write to the PGC's FIFOs */ +int pgc_input_byte(pgc_core_t *pgc, uint8_t *val); +int pgc_output_byte(pgc_core_t *pgc, uint8_t val); +int pgc_output_string(pgc_core_t *pgc, const char *val); +int pgc_error_byte(pgc_core_t *pgc, uint8_t val); +int pgc_error_string(pgc_core_t *pgc, const char *val); + +int pgc_param_byte(pgc_core_t *pgc, uint8_t *val); +int pgc_param_word(pgc_core_t *pgc, int16_t *val); +int pgc_param_coord(pgc_core_t *pgc, int32_t *val); +int pgc_result_byte(pgc_core_t *pgc, uint8_t val); +int pgc_result_word(pgc_core_t *pgc, int16_t val); +int pgc_result_coord(pgc_core_t *pgc, int32_t val); + +void pgc_sleep(pgc_core_t *pgc); +int pgc_error(pgc_core_t *pgc, int err); +void pgc_core_init(pgc_core_t *pgc, int maxw, int maxh, int visw, int vish, + int (*inpbyte)(struct pgc_core_t *pgc, uint8_t *result), double native_pixel_clock); +void pgc_speed_changed(void *p); +void pgc_close(void *p); + +void pgc_hndl_lut8(pgc_core_t *pgc); +void pgc_hndl_lut8rd(pgc_core_t *pgc); + +int pgc_parse_bytes(pgc_core_t *pgc, pgc_commandlist_t *cl, int p); +int pgc_parse_words(pgc_core_t *pgc, pgc_commandlist_t *cl, int p); +int pgc_parse_coords(pgc_core_t *pgc, pgc_commandlist_t *cl, int p); + +extern device_t pgc_device; + +#define PGC_ERROR_RANGE 0x01 +#define PGC_ERROR_INTEGER 0x02 +#define PGC_ERROR_MEMORY 0x03 +#define PGC_ERROR_OVERFLOW 0x04 +#define PGC_ERROR_DIGIT 0x05 +#define PGC_ERROR_OPCODE 0x06 +#define PGC_ERROR_RUNNING 0x07 +#define PGC_ERROR_STACK 0x08 +#define PGC_ERROR_TOOLONG 0x09 +#define PGC_ERROR_AREA 0x0A +#define PGC_ERROR_MISSING 0x0B + +/* #define PGCLOG(x) pclog x */ +#define PGCLOG(x) diff --git a/src/vid_ps1_svga.c b/src/vid_ps1_svga.c index 731bd94..8c8564f 100644 --- a/src/vid_ps1_svga.c +++ b/src/vid_ps1_svga.c @@ -42,9 +42,11 @@ void ps1_m2121_svga_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3D4: - svga->crtcreg = val & 0x1f; + svga->crtcreg = val & 0x3f; return; case 0x3D5: + if (svga->crtcreg & 0x20) + return; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -104,7 +106,10 @@ uint8_t ps1_m2121_svga_in(uint16_t addr, void *p) temp = svga->crtcreg; break; case 0x3D5: - temp = svga->crtc[svga->crtcreg]; + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg]; break; case 0x2108: diff --git a/src/vid_s3.c b/src/vid_s3.c index f0ce975..65adde4 100644 --- a/src/vid_s3.c +++ b/src/vid_s3.c @@ -76,11 +76,14 @@ typedef struct s3_t uint8_t id, id_ext, id_ext_pci; + uint8_t int_line; + int packed_mmio; uint32_t linear_base, linear_size; uint8_t pci_regs[256]; + int card; uint32_t vram_mask; @@ -92,12 +95,13 @@ typedef struct s3_t uint8_t subsys_cntl; uint8_t setup_md; uint8_t advfunc_cntl; - uint16_t cur_y; - uint16_t cur_x; - int16_t desty_axstp; + uint16_t cur_y, cur_y2; + uint16_t cur_x, cur_x2; + uint16_t x2; + int16_t desty_axstp, desty_axstp2; int16_t destx_distp; - int16_t err_term; - int16_t maj_axis_pcnt; + int16_t err_term, err_term2; + int16_t maj_axis_pcnt, maj_axis_pcnt2; uint16_t cmd; uint16_t short_stroke; uint32_t bkgd_color; @@ -116,6 +120,12 @@ typedef struct s3_t int dx, dy; uint32_t src, dest, pattern; int pix_trans_count; + + int poly_cx, poly_cx2; + int poly_cy, poly_cy2; + int point_1_updated, point_2_updated; + int poly_dx1, poly_dx2; + int poly_x; uint32_t dat_buf; int dat_count; @@ -131,8 +141,21 @@ typedef struct s3_t int blitter_busy; uint64_t blitter_time; uint64_t status_time; + + uint8_t subsys_cntl, subsys_stat; + + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; + + volatile int force_busy; } s3_t; +#define INT_VSY (1 << 0) +#define INT_GE_BSY (1 << 1) +#define INT_FIFO_OVR (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_MASK 0xf + void s3_updatemapping(); void s3_accel_write(uint32_t addr, uint8_t val, void *p); @@ -154,6 +177,14 @@ static void s3_wait_fifo_idle(s3_t *s3) } } +static void s3_update_irqs(s3_t *s3) +{ + if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) + pci_set_irq(s3->card, PCI_INTA); + else + pci_clear_irq(s3->card, PCI_INTA); +} + 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) \ @@ -170,34 +201,78 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) { case 0x82e8: s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; + s3->accel.poly_cy = s3->accel.cur_y; break; case 0x82e9: s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy = s3->accel.cur_y; + break; + case 0x82ea: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xf00) | val; + s3->accel.poly_cy2 = s3->accel.cur_y2; + break; + case 0x82eb: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy2 = s3->accel.cur_y2; break; case 0x86e8: s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; + s3->accel.poly_cx = s3->accel.cur_x << 20; + s3->accel.poly_x = s3->accel.poly_cx >> 20; break; case 0x86e9: s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + break; + case 0x86ea: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xf00) | val; + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; + break; + case 0x86eb: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; break; case 0x8ae8: s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; + s3->accel.point_1_updated = 1; break; case 0x8ae9: s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) - s3->accel.desty_axstp |= ~0x3fff; + s3->accel.desty_axstp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8aea: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0x3f00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8aeb: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp2 |= ~0x3fff; + s3->accel.point_2_updated = 1; break; case 0x8ee8: s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; + s3->accel.point_1_updated = 1; break; case 0x8ee9: s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); if (val & 0x20) - s3->accel.destx_distp |= ~0x3fff; + s3->accel.destx_distp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8eea: + s3->accel.x2 = (s3->accel.x2 & 0xf00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8eeb: + s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0xf) << 8); + s3->accel.point_2_updated = 1; break; case 0x92e8: @@ -208,6 +283,14 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (val & 0x20) s3->accel.err_term |= ~0x3fff; break; + case 0x92ea: + s3->accel.err_term2 = (s3->accel.err_term2 & 0x3f00) | val; + break; + case 0x92eb: + s3->accel.err_term2 = (s3->accel.err_term2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term2 |= ~0x3fff; + break; case 0x96e8: s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; @@ -217,6 +300,14 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) if (val & 0x08) s3->accel.maj_axis_pcnt |= ~0x0fff; break; + case 0x96ea: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xf00) | val; + break; + case 0x96eb: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt2 |= ~0x0fff; + break; case 0x9ae8: s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; @@ -252,10 +343,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xa2ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + } break; case 0xa2eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xa6e8: @@ -275,10 +381,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xa6ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + } break; case 0xa6eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xaae8: @@ -298,10 +419,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xaaea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + } break; case 0xaaeb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xaee8: @@ -321,10 +457,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xaeea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + } break; case 0xaeeb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xb2e8: @@ -344,10 +495,25 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) case 0xb2ea: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + } break; case 0xb2eb: if (s3->accel.multifunc[0xe] & 0x200) s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } break; case 0xb6e8: @@ -391,7 +557,14 @@ static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t 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)) + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x600 && (s3->accel.cmd & 0x100) && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + } + else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 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); @@ -407,11 +580,24 @@ static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) 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); + val = (val >> 8) | (val << 8); + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, val | (val << 16), 0, s3); + else + s3_accel_start(16, 1, val | (val << 16), 0, s3); } else - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } } } @@ -422,38 +608,49 @@ static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) { 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) + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); s3_accel_start(32, 1, val, 0, s3); + } else if ((s3->accel.cmd & 0x600) == 0x200) { - s3_accel_start(16, 1, val >> 16, 0, s3); + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); s3_accel_start(16, 1, val, 0, s3); + s3_accel_start(16, 1, val >> 16, 0, s3); } - else if (!(s3->accel.cmd & 0x600)) + else { - s3_accel_start(8, 1, val >> 24, 0, s3); + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 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) + if (s3->accel.cmd & 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); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); } - else if (!(s3->accel.cmd & 0x600)) + else { - 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); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); } } } @@ -581,10 +778,23 @@ static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) { if (s3->accel.cmd & 0x1000) val = (val >> 8) | (val << 8); - s3_accel_start(16, 1, val | (val << 16), 0, s3); + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, val | (val << 16), 0, s3); + else + s3_accel_start(16, 1, val | (val << 16), 0, s3); } else - s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } } } } @@ -605,38 +815,49 @@ static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) { 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) + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); s3_accel_start(32, 1, val, 0, s3); + } else if ((s3->accel.cmd & 0x600) == 0x200) { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(16, 1, val, 0, s3); s3_accel_start(16, 1, val >> 16, 0, s3); - s3_accel_start(16, 1, val, 0, s3); } - else if (!(s3->accel.cmd & 0x600)) + else { - s3_accel_start(8, 1, val >> 24, 0, s3); + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 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) + if (s3->accel.cmd & 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, s3); s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); } - else if (!(s3->accel.cmd & 0x600)) + else { - s3_accel_start(1, 1, 0xffffffff, val, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 8, s3); + s3_accel_start(1, 1, 0xffffffff, val, s3); s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); - s3_accel_start(1, 1, 0xffffffff, val >> 24, s3); } } } @@ -691,9 +912,19 @@ static void fifo_thread(void *param) s3->blitter_time += end_time - start_time; } s3->blitter_busy = 0; + s3->subsys_stat |= INT_FIFO_EMP; + s3_update_irqs(s3); } } +static void s3_vblank_start(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + + s3->subsys_stat |= INT_VSY; + s3_update_irqs(s3); +} + 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]; @@ -749,7 +980,15 @@ void s3_out(uint16_t addr, uint8_t val, void *p) 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); + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + svga_out(addr, val, svga); + else + { + if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2)) + sdac_ramdac_out((addr & 3) | 4, val, &s3->ramdac, svga); + else + sdac_ramdac_out(addr & 3, val, &s3->ramdac, svga); + } return; case 0x3D4: @@ -760,16 +999,21 @@ void s3_out(uint16_t addr, uint8_t val, void *p) 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 >= 0x20 && svga->crtcreg != 0x38 && svga->crtcreg != 0x39 && (svga->crtc[0x38] & 0xcc) != 0x48) + { + if (!((svga->crtc[0x39] & 0xe0) == 0xa0 && svga->crtcreg >= 0x40 && svga->crtcreg <= 0x6d)) + 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); + svga->force_dword_mode = val & 0x08; break; case 0x32: - svga->vrammask = (val & 0x40) ? 0x3ffff : s3->vram_mask; + svga->vram_display_mask = (val & 0x40) ? 0x3ffff : s3->vram_mask; break; case 0x50: @@ -826,6 +1070,37 @@ void s3_out(uint16_t addr, uint8_t val, void *p) if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) svga->hwcursor.x <<= 1; break; + + case 0x4a: + switch (s3->hwc_col_stack_pos) + { + case 0: + s3->hwc_fg_col = (s3->hwc_fg_col & 0xffff00) | val; + break; + case 1: + s3->hwc_fg_col = (s3->hwc_fg_col & 0xff00ff) | (val << 8); + break; + case 2: + s3->hwc_fg_col = (s3->hwc_fg_col & 0x00ffff) | (val << 16); + break; + } + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + break; + case 0x4b: + switch (s3->hwc_col_stack_pos) + { + case 0: + s3->hwc_bg_col = (s3->hwc_bg_col & 0xffff00) | val; + break; + case 1: + s3->hwc_bg_col = (s3->hwc_bg_col & 0xff00ff) | (val << 8); + break; + case 2: + s3->hwc_bg_col = (s3->hwc_bg_col & 0x00ffff) | (val << 16); + break; + } + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + break; case 0x53: case 0x58: case 0x59: case 0x5a: @@ -884,7 +1159,11 @@ uint8_t s3_in(uint16_t addr, void *p) 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); + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + return svga_in(addr, svga); + if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2)) + return sdac_ramdac_in((addr & 3) | 4, &s3->ramdac, svga); + return sdac_ramdac_in(addr & 3, &s3->ramdac, svga); case 0x3d4: return svga->crtcreg; @@ -898,6 +1177,7 @@ uint8_t s3_in(uint16_t addr, void *p) 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 0x45: s3->hwc_col_stack_pos = 0; break; 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; @@ -911,6 +1191,10 @@ void s3_recalctimings(svga_t *svga) { s3_t *s3 = (s3_t *)svga->p; svga->hdisp = svga->hdisp_old; + int clk_sel = (svga->miscout >> 2) & 3; + + if (clk_sel == 3 && s3->chip == S3_VISION864) + clk_sel = svga->crtc[0x42] & 0xf; // pclog("%i %i\n", svga->hdisp, svga->hdisp_time); // pclog("recalctimings\n"); @@ -931,7 +1215,7 @@ void s3_recalctimings(svga_t *svga) 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); + svga->clock = (cpuclock * (float)(1ull << 32)) / s3->getclock(clk_sel, s3->getclock_p); switch (svga->crtc[0x67] >> 4) { @@ -985,7 +1269,14 @@ void s3_updatemapping(s3_t *s3) } // pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); - switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + /*Banked framebuffer*/ + if (svga->crtc[0x31] & 0x08) /*Enhanced mode mappings*/ + { + /*Enhanced mapping forces 64kb at 0xa0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } + else switch (svga->gdcreg[6] & 0xc) /*VGA mapping*/ { case 0x0: /*128k at A0000*/ mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); @@ -1085,9 +1376,12 @@ void s3_accel_out(uint16_t port, uint8_t val, void *p) else switch (port) { case 0x42e8: + s3->subsys_stat &= ~val; + s3_update_irqs(s3); break; case 0x42e9: - s3->accel.subsys_cntl = val; + s3->subsys_cntl = val; + s3_update_irqs(s3); break; case 0x46e8: s3->accel.setup_md = val; @@ -1120,9 +1414,9 @@ uint8_t s3_accel_in(uint16_t port, void *p) switch (port) { case 0x42e8: - return 0; + return s3->subsys_stat; case 0x42e9: - return 0; + return s3->subsys_cntl; case 0x82e8: s3_wait_fifo_idle(s3); @@ -1176,10 +1470,11 @@ uint8_t s3_accel_in(uint16_t port, void *p) if (!s3->blitter_busy) wake_fifo_thread(s3); temp = 0; - if (!FIFO_EMPTY) + if (!FIFO_EMPTY || s3->force_busy) temp |= 0x02; /*Hardware busy*/ else temp |= 0x04; /*FIFO empty*/ + s3->force_busy = 0; if (FIFO_FULL) temp |= 0xf8; /*FIFO full*/ return temp; @@ -1327,45 +1622,116 @@ uint8_t s3_accel_read(uint32_t addr, void *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)]; +static void polygon_setup(s3_t *s3) +{ + if (s3->accel.point_1_updated) + { + int start_x = s3->accel.poly_cx; + int start_y = s3->accel.poly_cy; + int end_x = s3->accel.destx_distp << 20; + int end_y = s3->accel.desty_axstp; + + if (end_y - start_y) + s3->accel.poly_dx1 = (end_x - start_x) / (end_y - start_y); + else + s3->accel.poly_dx1 = 0; + + s3->accel.point_1_updated = 0; -#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; \ + if (end_y == s3->accel.poly_cy) + { + s3->accel.poly_cx = end_x; + s3->accel.poly_x = end_x >> 20; + } + } + if (s3->accel.point_2_updated) + { + int start_x = s3->accel.poly_cx2; + int start_y = s3->accel.poly_cy2; + int end_x = s3->accel.x2 << 20; + int end_y = s3->accel.desty_axstp2; + + if (end_y - start_y) + s3->accel.poly_dx2 = (end_x - start_x) / (end_y - start_y); + else + s3->accel.poly_dx2 = 0; + + s3->accel.point_2_updated = 0; + + if (end_y == s3->accel.poly_cy) + s3->accel.poly_cx2 = end_x; + } +} + +/*Remap address for chain-4/doubleword style layout*/ +static inline uint32_t dword_remap(uint32_t in_addr) +{ + return ((in_addr << 2) & 0x3fff0) | + ((in_addr >> 14) & 0xc) | + (in_addr & ~0x3fffc); +} +static inline uint32_t dword_remap_w(uint32_t in_addr) +{ + return ((in_addr << 2) & 0x1fff8) | + ((in_addr >> 14) & 0x6) | + (in_addr & ~0x1fffe); +} +static inline uint32_t dword_remap_l(uint32_t in_addr) +{ + return ((in_addr << 2) & 0xfffc) | + ((in_addr >> 14) & 0x3) | + (in_addr & ~0xffff); +} + +#define READ_SRC(addr, dat) if (s3->bpp == 0) dat = svga->vram[ dword_remap(addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[dword_remap_w(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[dword_remap_l(addr) & (s3->vram_mask >> 2)]; \ + if (vram_mask) \ + dat = ((dat & rd_mask) == rd_mask); + +#define READ_DST(addr, dat) if (s3->bpp == 0) dat = svga->vram[ dword_remap(addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[dword_remap_w(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[dword_remap_l(addr) & (s3->vram_mask >> 2)]; + +#define MIX { \ + uint32_t old_dest_dat = dest_dat; \ + 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; \ + } \ + dest_dat = (dest_dat & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ } #define WRITE(addr) if (s3->bpp == 0) \ { \ - svga->vram[(addr) & s3->vram_mask] = dest_dat; \ - svga->changedvram[((addr) & s3->vram_mask) >> 12] = changeframecount; \ + svga->vram[dword_remap(addr) & s3->vram_mask] = dest_dat; \ + svga->changedvram[(dword_remap(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; \ + vram_w[dword_remap_w(addr) & (s3->vram_mask >> 1)] = dest_dat; \ + svga->changedvram[(dword_remap_w(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; \ + vram_l[dword_remap_l(addr) & (s3->vram_mask >> 2)] = dest_dat; \ + svga->changedvram[(dword_remap_l(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) @@ -1383,6 +1749,33 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat uint32_t *vram_l = (uint32_t *)svga->vram; uint32_t compare = s3->accel.color_cmp; int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; + uint32_t rd_mask = s3->accel.rd_mask; + int cmd = s3->accel.cmd >> 13; + uint32_t srcbase, dstbase; + + if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) + cmd |= 8; + + if ((s3->accel.multifunc[13] >> 4) & 7) + srcbase = 0x100000 * ((s3->accel.multifunc[13] >> 4) & 3); + else + srcbase = 0x100000 * ((s3->accel.multifunc[14] >> 2) & 3); + if ((s3->accel.multifunc[13] >> 0) & 7) + dstbase = 0x100000 * ((s3->accel.multifunc[13] >> 0) & 3); + else + dstbase = 0x100000 * ((s3->accel.multifunc[14] >> 0) & 3); + if (s3->bpp == 1) + { + srcbase >>= 1; + dstbase >>= 1; + } + else if (s3->bpp == 3) + { + srcbase >>= 2; + dstbase >>= 2; + } + + s3->force_busy = 1; //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); @@ -1407,18 +1800,23 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->bpp == 1) count >>= 1; if (s3->bpp == 3) count >>= 2; } + + if (s3->bpp == 0) + rd_mask &= 0xff; + else if (s3->bpp == 1) + rd_mask &= 0xffff; 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; + case 0x600: mix_mask = (s3->chip == S3_TRIO32) ? 0x80 : 0x80000000; break; } if (s3->bpp == 0) compare &= 0xff; if (s3->bpp == 1) compare &= 0xffff; - switch (s3->accel.cmd >> 13) + switch (cmd) { case 1: /*Draw line*/ if (!cpu_input) /*!cpu_input is trigger to start operation*/ @@ -1439,8 +1837,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { 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) + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -1454,7 +1852,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); MIX @@ -1489,8 +1887,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { 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) + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -1504,7 +1902,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + READ_DST((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); @@ -1574,7 +1972,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat 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; + s3->accel.dest = dstbase + 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); } @@ -1587,8 +1985,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat 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) + if ((s3->accel.cx & 0xfff) >= clip_l && (s3->accel.cx & 0xfff) <= clip_r && + (s3->accel.cy & 0xfff) >= clip_t && (s3->accel.cy & 0xfff) <= clip_b) { switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { @@ -1602,7 +2000,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (compare_mode == 3 && src_dat == compare) || compare_mode < 2) { - READ(s3->accel.dest + s3->accel.cx, dest_dat); + READ_DST(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); @@ -1634,7 +2032,7 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat if (s3->accel.cmd & 0x80) s3->accel.cy++; else s3->accel.cy--; - s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.dest = dstbase + s3->accel.cy * s3->width; s3->accel.sy--; if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; @@ -1664,8 +2062,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat 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; + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + 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); } @@ -1684,12 +2082,13 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { while (1) { - if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && - s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + if ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) { - READ(s3->accel.src + s3->accel.cx, src_dat); - - dest_dat = src_dat; + READ_SRC(s3->accel.src + s3->accel.cx, src_dat); + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + + dest_dat = (src_dat & s3->accel.wrt_mask) | (dest_dat & ~s3->accel.wrt_mask); WRITE(s3->accel.dest + s3->accel.dx); } @@ -1706,17 +2105,13 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.cy++; s3->accel.dy++; - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + 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; - } } } } @@ -1724,12 +2119,13 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat { 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 ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) { if (vram_mask) { - READ(s3->accel.src + s3->accel.cx, mix_dat) + READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; } switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) @@ -1737,14 +2133,14 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat 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; + case 3: READ_SRC(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); + READ_DST(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); @@ -1797,18 +2193,14 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dy--; } - s3->accel.src = s3->accel.cy * s3->width; - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.cy * s3->width; + s3->accel.dest = dstbase + 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; - } } } } @@ -1835,12 +2227,12 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat // 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.dest = dstbase + 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); + s3->accel.src = srcbase + 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(); @@ -1855,12 +2247,12 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat 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 ((s3->accel.dx & 0xfff) >= clip_l && (s3->accel.dx & 0xfff) <= clip_r && + (s3->accel.dy & 0xfff) >= clip_t && (s3->accel.dy & 0xfff) <= clip_b) { if (vram_mask) { - READ(s3->accel.src + s3->accel.cx, mix_dat) + READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) mix_dat = mix_dat ? mix_mask : 0; } switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) @@ -1868,14 +2260,14 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat 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; + case 3: READ_SRC(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); + READ_DST(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); @@ -1928,8 +2320,8 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat s3->accel.dy--; } - s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); - s3->accel.dest = s3->accel.dy * s3->width; + s3->accel.src = srcbase + s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.dest = dstbase + s3->accel.dy * s3->width; s3->accel.sy--; @@ -1939,30 +2331,226 @@ void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } } break; + + case 3: /*Polygon Fill Solid (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.dest = dstbase + y * s3->width; + + while (x_count-- && count--) + { + if ((s3->accel.poly_x & 0xfff) >= clip_l && (s3->accel.poly_x & 0xfff) <= clip_r && + (s3->accel.poly_cy & 0xfff) >= clip_t && (s3->accel.poly_cy & 0xfff) <= clip_b) + { + switch (frgd_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; /*Nor supported?*/ break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; + + case 11: /*Polygon Fill Pattern (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.src = srcbase + s3->accel.pattern + ((y & 7) * s3->width); + s3->accel.dest = dstbase + y * s3->width; + + while (x_count-- && count--) + { + int pat_x = s3->accel.poly_x & 7; + + if ((s3->accel.poly_x & 0xfff) >= clip_l && (s3->accel.poly_x & 0xfff) <= clip_r && + (s3->accel.poly_cy & 0xfff) >= clip_t && (s3->accel.poly_cy & 0xfff) <= clip_b) + { + if (vram_mask) + { + READ_SRC(s3->accel.src + pat_x, 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_SRC(s3->accel.src + pat_x, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + mix_dat <<= 1; + mix_dat |= 1; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; } } void s3_hwcursor_draw(svga_t *svga, int displine) { + s3_t *s3 = (s3_t *)svga->p; int x; uint16_t dat[2]; int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - + uint32_t fg = 0, bg = 0; + + switch (svga->bpp) + { + case 15: + fg = video_15to32[s3->hwc_fg_col & 0xffff]; + bg = video_15to32[s3->hwc_bg_col & 0xffff]; + break; + + case 16: + fg = video_16to32[s3->hwc_fg_col & 0xffff]; + bg = video_16to32[s3->hwc_bg_col & 0xffff]; + break; + + case 24: case 32: + fg = s3->hwc_fg_col; + bg = s3->hwc_bg_col; + break; + + default: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + fg = svga->pallook[s3->hwc_fg_col & 0xff]; + bg = svga->pallook[s3->hwc_bg_col & 0xff]; + } + else + { + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; + } + break; + } + 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]; + uint32_t remapped_addr = dword_remap(svga->hwcursor_latch.addr); + + dat[0] = (svga->vram[remapped_addr] << 8) | svga->vram[remapped_addr + 1]; + dat[1] = (svga->vram[remapped_addr + 2] << 8) | svga->vram[remapped_addr + 3]; for (xx = 0; xx < 16; xx++) { if (offset >= svga->hwcursor_latch.x) { if (!(dat[0] & 0x8000)) - ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? 0xffffff : 0; + ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? fg : bg; else if (dat[1] & 0x8000) ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; // pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); @@ -2014,12 +2602,24 @@ static void s3_io_set(s3_t *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); + if (s3->chip == S3_TRIO64) + { + io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + else + { + 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); @@ -2067,6 +2667,9 @@ uint8_t s3_pci_read(int func, int addr, void *p) case 0x31: return 0x00; case 0x32: return s3->pci_regs[0x32]; case 0x33: return s3->pci_regs[0x33]; + + case 0x3c: return s3->int_line; + case 0x3d: return PCI_INTA; } return 0; } @@ -2079,7 +2682,7 @@ void s3_pci_write(int func, int addr, uint8_t val, void *p) switch (addr) { case PCI_REG_COMMAND: - s3->pci_regs[PCI_REG_COMMAND] = val & 0x27; + s3->pci_regs[PCI_REG_COMMAND] = val & 0x23; if (val & PCI_COMMAND_IO) s3_io_set(s3); else @@ -2110,6 +2713,10 @@ void s3_pci_write(int func, int addr, uint8_t val, void *p) mem_mapping_disable(&s3->bios_rom.mapping); } return; + + case 0x3c: + s3->int_line = val; + return; } } @@ -2156,15 +2763,42 @@ static void *s3_init(char *bios_fn, int chip) s3_hwcursor_draw, NULL); + svga->decode_mask = (4 << 20) - 1; + switch (vram) + { + case 0: /*512kb*/ + svga->vram_mask = (1 << 19) - 1; + svga->vram_max = 2 << 20; + break; + case 1: /*1MB*/ + /*VRAM in first MB, mirrored in 2nd MB, 3rd and 4th MBs are open bus*/ + /*This works with the #9 9FX BIOS, and matches how my real Trio64 behaves, + but does not work with the Phoenix EDO BIOS. Possibly an FPM/EDO difference?*/ + svga->vram_mask = (1 << 20) - 1; + svga->vram_max = 2 << 20; + break; + case 2: default: /*2MB*/ + /*VRAM in first 2 MB, 3rd and 4th MBs are open bus*/ + svga->vram_mask = (2 << 20) - 1; + svga->vram_max = 2 << 20; + break; + case 4: /*4MB*/ + svga->vram_mask = (4 << 20) - 1; + svga->vram_max = 4 << 20; + break; + } + 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); + + svga->vblank_start = s3_vblank_start; s3_io_set(s3); - pci_add(s3_pci_read, s3_pci_write, s3); + s3->card = pci_add(s3_pci_read, s3_pci_write, s3); s3->pci_regs[0x04] = 7; @@ -2177,13 +2811,15 @@ static void *s3_init(char *bios_fn, int chip) s3->wake_fifo_thread = thread_create_event(); s3->fifo_not_full_event = thread_create_event(); s3->fifo_thread = thread_create(fifo_thread, s3); + + s3->int_line = 0; return s3; } void *s3_bahamas64_init() { - s3_t *s3 = s3_init("roms/bahamas64.bin", S3_VISION864); + s3_t *s3 = s3_init("bahamas64.bin", S3_VISION864); s3->id = 0xc0; /*Vision864P*/ s3->id_ext = s3->id_ext_pci = 0xc0; @@ -2191,18 +2827,19 @@ void *s3_bahamas64_init() s3->getclock = sdac_getclock; s3->getclock_p = &s3->ramdac; + sdac_init(&s3->ramdac); return s3; } int s3_bahamas64_available() { - return rom_present("roms/bahamas64.bin"); + return rom_present("bahamas64.bin"); } void *s3_9fx_init() { - s3_t *s3 = s3_init("roms/s3_764.bin", S3_TRIO64); + s3_t *s3 = s3_init("s3_764.bin", S3_TRIO64); s3->id = 0xe1; /*Trio64*/ s3->id_ext = s3->id_ext_pci = 0x11; @@ -2216,12 +2853,12 @@ void *s3_9fx_init() int s3_9fx_available() { - return rom_present("roms/s3_764.bin"); + return rom_present("s3_764.bin"); } void *s3_phoenix_trio32_init() { - s3_t *s3 = s3_init("roms/86c732p.bin", S3_TRIO32); + s3_t *s3 = s3_init("86c732p.bin", S3_TRIO32); s3->id = 0xe1; /*Trio32*/ s3->id_ext = 0x10; @@ -2236,16 +2873,18 @@ void *s3_phoenix_trio32_init() int s3_phoenix_trio32_available() { - return rom_present("roms/86c732p.bin"); + return rom_present("86c732p.bin"); } void *s3_phoenix_trio64_init() { - s3_t *s3 = s3_init("roms/86c764x1.bin", S3_TRIO64); + s3_t *s3 = s3_init("86c764x1.bin", S3_TRIO64); s3->id = 0xe1; /*Trio64*/ s3->id_ext = s3->id_ext_pci = 0x11; s3->packed_mmio = 1; + if (device_get_config_int("memory") == 1) + s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ s3->getclock = s3_trio64_getclock; s3->getclock_p = s3; @@ -2255,7 +2894,7 @@ void *s3_phoenix_trio64_init() int s3_phoenix_trio64_available() { - return rom_present("roms/86c764x1.bin"); + return rom_present("86c764x1.bin"); } void s3_close(void *p) @@ -2319,11 +2958,10 @@ static device_config_t s3_bahamas64_config[] = .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)*/ + /*Vision864 also supports 4 and 8 MB, however the Paradise + BIOS is buggy (VESA modes don't work correctly), and UNIVBE and + OS/2 Warp misdetect the VRAM size. Bahamas 64 only supports + up to 2 MB on the board anyway. */ { .description = "" } @@ -2402,10 +3040,6 @@ static device_config_t s3_phoenix_trio64_config[] = .type = CONFIG_SELECTION, .selection = { - { - .description = "512 KB", - .value = 0 - }, { .description = "1 MB", .value = 1 diff --git a/src/vid_s3_virge.c b/src/vid_s3_virge.c index cb30cee..428669b 100644 --- a/src/vid_s3_virge.c +++ b/src/vid_s3_virge.c @@ -8,6 +8,7 @@ #include "rom.h" #include "thread.h" #include "video.h" +#include "vid_ddc.h" #include "vid_s3_virge.h" #include "vid_svga.h" #include "vid_svga_render.h" @@ -119,14 +120,13 @@ typedef struct virge_t 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 card; int is_375; @@ -141,8 +141,8 @@ typedef struct virge_t event_t *wake_main_thread; event_t *not_full_event; - uint32_t hwcursor_col[2]; - int hwcursor_col_pos; + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; struct { @@ -234,6 +234,10 @@ typedef struct virge_t event_t *fifo_not_full_event; int virge_busy; + + uint8_t subsys_stat, subsys_cntl; + + uint8_t serialport; } virge_t; static inline void wake_fifo_thread(virge_t *virge) @@ -298,6 +302,26 @@ enum CMD_SET_COMMAND_NOP = (15 << 27) }; +#define INT_VSY (1 << 0) +#define INT_S3D_DONE (1 << 1) +#define INT_FIFO_OVF (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_3DF_EMP (1 << 6) +#define INT_MASK 0xff + +#define SERIAL_PORT_SCW (1 << 0) +#define SERIAL_PORT_SDW (1 << 1) +#define SERIAL_PORT_SCR (1 << 2) +#define SERIAL_PORT_SDR (1 << 3) + +static void s3_virge_update_irqs(virge_t *virge) +{ + if ((virge->svga.crtc[0x32] & 0x10) && (virge->subsys_stat & virge->subsys_cntl & INT_MASK)) + pci_set_irq(virge->card, PCI_INTA); + else + pci_clear_irq(virge->card, PCI_INTA); +} + static void s3_virge_out(uint16_t addr, uint8_t val, void *p) { virge_t *virge = (virge_t *)p; @@ -351,22 +375,9 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) 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); + s3_virge_update_irqs(virge); 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; @@ -407,16 +418,34 @@ static void s3_virge_out(uint16_t addr, uint8_t val, void *p) 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; + switch (virge->hwc_col_stack_pos) + { + case 0: + virge->hwc_fg_col = (virge->hwc_fg_col & 0xffff00) | val; + break; + case 1: + virge->hwc_fg_col = (virge->hwc_fg_col & 0xff00ff) | (val << 8); + break; + case 2: + virge->hwc_fg_col = (virge->hwc_fg_col & 0x00ffff) | (val << 16); + break; + } + virge->hwc_col_stack_pos = (virge->hwc_col_stack_pos + 1) & 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; + switch (virge->hwc_col_stack_pos) + { + case 0: + virge->hwc_bg_col = (virge->hwc_bg_col & 0xffff00) | val; + break; + case 1: + virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8); + break; + case 2: + virge->hwc_bg_col = (virge->hwc_bg_col & 0x00ffff) | (val << 16); + break; + } + virge->hwc_col_stack_pos = (virge->hwc_col_stack_pos + 1) & 3; break; case 0x53: @@ -495,7 +524,7 @@ static uint8_t s3_virge_in(uint16_t addr, void *p) 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 0x45: virge->hwc_col_stack_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; @@ -564,7 +593,7 @@ static void s3_virge_recalctimings(svga_t *svga) { svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ } - svga->vrammask = (svga->crtc[0x32] & 0x40) ? 0x3ffff : ((virge->memory_size << 20) - 1); + svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (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*/ @@ -612,7 +641,7 @@ static void s3_virge_recalctimings(svga_t *svga) svga->render = svga_render_32bpp_highres; break; } - svga->vrammask = (virge->memory_size << 20) - 1; + svga->vram_display_mask = (virge->memory_size << 20) - 1; } if (((svga->miscout >> 2) & 3) == 3) @@ -622,7 +651,7 @@ static void s3_virge_recalctimings(svga_t *svga) int m = svga->seqregs[0x13] & 0x7f; double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; - svga->clock = cpuclock / freq; + svga->clock = (cpuclock * (float)(1ull << 32)) / freq; } } @@ -717,6 +746,14 @@ static void s3_virge_updatemapping(virge_t *virge) } +static void s3_virge_vblank_start(svga_t *svga) +{ + virge_t *virge = (virge_t *)svga->p; + + virge->subsys_stat |= INT_VSY; + s3_virge_update_irqs(virge); +} + static void s3_virge_wait_fifo_idle(virge_t *virge) { while (!FIFO_EMPTY) @@ -757,6 +794,14 @@ static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: return s3_virge_in(addr & 0x3ff, p); + + case 0xff20: case 0xff21: + ret = virge->serialport & ~(SERIAL_PORT_SCR | SERIAL_PORT_SDR); + if ((virge->serialport & SERIAL_PORT_SCW) && ddc_read_clock()) + ret |= SERIAL_PORT_SCR; + if ((virge->serialport & SERIAL_PORT_SDW) && ddc_read_data()) + ret |= SERIAL_PORT_SDR; + return ret; } return 0xff; } @@ -851,6 +896,7 @@ static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) ret = (0x10 << 8); else ret = (0x10 << 8) | (1 << 13); + ret |= virge->subsys_stat; if (!virge->virge_busy) wake_fifo_thread(virge); // pclog("Read status %04x %i\n", ret, virge->s3d_busy); @@ -1270,6 +1316,8 @@ static void fifo_thread(void *param) virge_time += end_time - start_time; } virge->virge_busy = 0; + virge->subsys_stat |= INT_FIFO_EMP | INT_3DF_EMP; + s3_virge_update_irqs(virge); } } @@ -1323,9 +1371,12 @@ static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: s3_virge_out(addr & 0x3ff, val, p); break; - } - + case 0xff20: + virge->serialport = val; + ddc_i2c_change((val & SERIAL_PORT_SCW) ? 1 : 0, (val & SERIAL_PORT_SDW) ? 1 : 0); + break; + } } static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) { @@ -1342,6 +1393,10 @@ static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) s3_virge_mmio_write(addr, val, p); s3_virge_mmio_write(addr + 1, val >> 8, p); break; + + case 0xff20: + s3_virge_mmio_write(addr, val, p); + break; } } static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) @@ -1480,6 +1535,12 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) svga->fullchange = changeframecount; break; + case 0x8504: + virge->subsys_stat &= ~(val & 0xff); + virge->subsys_cntl = (val >> 8); + s3_virge_update_irqs(virge); + 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: @@ -1779,6 +1840,10 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) // s3_virge_triangle(virge); break; + + case 0xff20: + s3_virge_mmio_write(addr, val, p); + break; } } @@ -1788,20 +1853,20 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) switch (bpp) \ { \ case 0: /*8 bpp*/ \ - val = vram[addr & 0x3fffff]; \ + val = vram[addr & svga->vram_mask]; \ break; \ case 1: /*16 bpp*/ \ - val = *(uint16_t *)&vram[addr & 0x3fffff]; \ + val = *(uint16_t *)&vram[addr & svga->vram_mask]; \ break; \ case 2: /*24 bpp*/ \ - val = (*(uint32_t *)&vram[addr & 0x3fffff]) & 0xffffff; \ + val = (*(uint32_t *)&vram[addr & svga->vram_mask]) & 0xffffff; \ break; \ } \ } while (0) -#define Z_READ(addr) *(uint16_t *)&vram[addr & 0x3fffff] +#define Z_READ(addr) *(uint16_t *)&vram[addr & svga->vram_mask] -#define Z_WRITE(addr, val) if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & 0x3fffff] = val +#define Z_WRITE(addr, val) if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & svga->vram_mask] = val #define CLIP(x, y) \ do \ @@ -1861,23 +1926,24 @@ static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) switch (bpp) \ { \ case 0: /*8 bpp*/ \ - vram[addr & 0x3fffff] = val; \ - virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \ + vram[addr & svga->vram_mask] = val; \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ break; \ case 1: /*16 bpp*/ \ - *(uint16_t *)&vram[addr & 0x3fffff] = val; \ - virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \ + *(uint16_t *)&vram[addr & svga->vram_mask] = val; \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 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; \ + *(uint32_t *)&vram[addr & svga->vram_mask] = (val & 0xffffff) | \ + (vram[(addr + 3) & svga->vram_mask] << 24); \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ break; \ } \ } while (0) static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) { + svga_t *svga = &virge->svga; uint8_t *vram = virge->svga.vram; uint32_t mono_pattern[64]; int count_mask; @@ -1887,6 +1953,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) int x_mul; int cpu_dat_shift; uint32_t *pattern_data; + uint32_t src_fg_clr, src_bg_clr; switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) { @@ -1895,12 +1962,16 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) x_mul = 1; cpu_dat_shift = 8; pattern_data = virge->s3d.pattern_8; + src_fg_clr = virge->s3d.src_fg_clr & 0xff; + src_bg_clr = virge->s3d.src_bg_clr & 0xff; break; case CMD_SET_FORMAT_16: bpp = 1; x_mul = 2; cpu_dat_shift = 16; pattern_data = virge->s3d.pattern_16; + src_fg_clr = virge->s3d.src_fg_clr & 0xffff; + src_bg_clr = virge->s3d.src_bg_clr & 0xffff; break; case CMD_SET_FORMAT_24: default: @@ -1908,6 +1979,8 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) x_mul = 3; cpu_dat_shift = 24; pattern_data = virge->s3d.pattern_32; + src_fg_clr = virge->s3d.src_fg_clr; + src_bg_clr = virge->s3d.src_bg_clr; break; } if (virge->s3d.cmd_set & CMD_SET_MP) @@ -1990,7 +2063,7 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) case 0: case CMD_SET_MS: READ(src_addr, source); - if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr) + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr) update = 0; break; case CMD_SET_IDS: @@ -2021,11 +2094,11 @@ static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) count = 0; } } - if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr) + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == 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; + source = (cpu_dat & (1 << 31)) ? src_fg_clr : src_bg_clr; if ((virge->s3d.cmd_set & CMD_SET_TP) && !(cpu_dat & (1 << 31))) update = 0; cpu_dat <<= 1; @@ -2885,6 +2958,7 @@ static void dest_pixel_lit_texture_modulate(s3d_state_t *state) static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) { + svga_t *svga = &virge->svga; uint8_t *vram = virge->svga.vram; int x_dir = s3d_tri->tlr ? 1 : -1; @@ -2928,7 +3002,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 y_count -= diff_y; } if ((state->y - y_count) < s3d_tri->clip_t) - y_count = state->y - s3d_tri->clip_t; + y_count = (state->y - s3d_tri->clip_t) + 1; } for (; y_count > 0; y_count--) @@ -2971,7 +3045,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (xe < s3d_tri->clip_l) goto tri_skip_line; if (xe > s3d_tri->clip_r) - xe = s3d_tri->clip_r; + xe = s3d_tri->clip_r + 1; if (x < s3d_tri->clip_l) { int diff_x = s3d_tri->clip_l - x; @@ -2996,7 +3070,7 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 if (xe > s3d_tri->clip_r) goto tri_skip_line; if (xe < s3d_tri->clip_l) - xe = s3d_tri->clip_l; + xe = s3d_tri->clip_l - 1; if (x > s3d_tri->clip_r) { int diff_x = x - s3d_tri->clip_r; @@ -3016,11 +3090,14 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 } } - virge->svga.changedvram[(dest_offset & 0x3fffff) >> 12] = changeframecount; + virge->svga.changedvram[(dest_offset & svga->vram_mask) >> 12] = changeframecount; dest_addr = dest_offset + (x * (bpp + 1)); z_addr = z_offset + (x << 1); + x &= 0xfff; + xe &= 0xfff; + for (; x != xe; x = (x + x_dir) & 0xfff) { int update = 1; @@ -3050,11 +3127,11 @@ static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int3 /*Not implemented yet*/ break; case 1: /*16 bpp*/ - src_col = *(uint16_t *)&vram[dest_addr & 0x3fffff]; + src_col = *(uint16_t *)&vram[dest_addr & svga->vram_mask]; 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; + src_col = (*(uint32_t *)&vram[dest_addr & svga->vram_mask]) & 0xffffff; RGB24_TO_24(src_col, src_r, src_g, src_b); break; } @@ -3304,6 +3381,8 @@ static void render_thread(void *param) thread_set_event(virge->not_full_event); } virge->s3d_busy = 0; + virge->subsys_stat |= INT_S3D_DONE; + s3_virge_update_irqs(virge); } } @@ -3330,8 +3409,32 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) uint16_t dat[2]; int xx; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + uint32_t fg, bg; -// pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y); +// pclog("HWcursor %i %i %08x %08x\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y, virge->hwcursor_col[0],virge->hwcursor_col[1]); + switch (svga->bpp) + { + case 15: + fg = video_15to32[virge->hwc_fg_col & 0xffff]; + bg = video_15to32[virge->hwc_bg_col & 0xffff]; + break; + + case 16: + fg = video_16to32[virge->hwc_fg_col & 0xffff]; + bg = video_16to32[virge->hwc_bg_col & 0xffff]; + break; + + case 24: case 32: + fg = virge->hwc_fg_col; + bg = virge->hwc_bg_col; + break; + + default: + fg = svga->pallook[virge->hwc_fg_col & 0xff]; + bg = svga->pallook[virge->hwc_bg_col & 0xff]; + break; + } + for (x = 0; x < 64; x += 16) { dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; @@ -3344,7 +3447,7 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) if (offset >= svga->hwcursor_latch.x) { if (dat[0] & 0x8000) - ((uint32_t *)buffer32->line[displine])[offset + 32] = virge->hwcursor_col[dat[1] >> 15]; + ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? fg : bg; } offset++; @@ -3360,7 +3463,7 @@ static void s3_virge_hwcursor_draw(svga_t *svga, int displine) if (offset >= svga->hwcursor_latch.x) { if (!(dat[0] & 0x8000)) - ((uint32_t *)buffer32->line[displine])[offset + 32] = virge->hwcursor_col[dat[1] >> 15]; + ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x8000) ? fg : bg; else if (dat[1] & 0x8000) ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; // pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga->hwcursor_on, dat[0], dat[1]); @@ -3764,7 +3867,7 @@ static void *s3_virge_init() s3_virge_hwcursor_draw, s3_virge_overlay_draw); - rom_init(&virge->bios_rom, "roms/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&virge->bios_rom, "s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (PCI) mem_mapping_disable(&virge->bios_rom.mapping); @@ -3840,6 +3943,11 @@ static void *s3_virge_init() virge->fifo_not_full_event = thread_create_event(); virge->fifo_thread = thread_create(fifo_thread, virge); + ddc_init(); + + //TODO ViRGE does not use packed chain4 + virge->svga.packed_chain4 = 1; + return virge; } @@ -3857,8 +3965,9 @@ static void *s3_virge_375_init() s3_virge_in, s3_virge_out, s3_virge_hwcursor_draw, s3_virge_overlay_draw); + virge->svga.vblank_start = s3_virge_vblank_start; - rom_init(&virge->bios_rom, "roms/86c375_1.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&virge->bios_rom, "86c375_1.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); if (PCI) mem_mapping_disable(&virge->bios_rom.mapping); @@ -3925,7 +4034,7 @@ static void *s3_virge_375_init() virge->is_375 = 1; - pci_add(s3_virge_pci_read, s3_virge_pci_write, virge); + virge->card = 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(); @@ -3935,7 +4044,12 @@ static void *s3_virge_375_init() virge->wake_fifo_thread = thread_create_event(); virge->fifo_not_full_event = thread_create_event(); virge->fifo_thread = thread_create(fifo_thread, virge); - + + ddc_init(); + + //TODO ViRGE does not use packed chain4 + virge->svga.packed_chain4 = 1; + return virge; } @@ -3964,12 +4078,12 @@ static void s3_virge_close(void *p) static int s3_virge_available() { - return rom_present("roms/s3virge.bin"); + return rom_present("s3virge.bin"); } static int s3_virge_375_available() { - return rom_present("roms/86c375_1.bin"); + return rom_present("86c375_1.bin"); } static void s3_virge_speed_changed(void *p) diff --git a/src/vid_sdac_ramdac.c b/src/vid_sdac_ramdac.c index 0098d60..ba0c3ee 100644 --- a/src/vid_sdac_ramdac.c +++ b/src/vid_sdac_ramdac.c @@ -1,124 +1,162 @@ /*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) +static void sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val) { -// /*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) + ramdac->command = val; +// pclog("RAMDAC command reg now %02X\n", val); + switch (val & 0xf0) { - 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); - 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; - } - } - //ramdac->magic_count = 0; + case 0x00: case 0x10: + svga->bpp = 8; break; - case 0x3C7: - ramdac->magic_count = 0; - if (ramdac->rs2) - ramdac->rindex = val; + case 0x20: case 0x30: case 0x80: case 0xa0: + svga->bpp = 15; break; - case 0x3C8: - ramdac->magic_count = 0; - if (ramdac->rs2) - ramdac->windex = val; + + case 0x50: case 0x60: case 0xc0: + svga->bpp = 16; 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++; - } + + case 0x40: case 0x90: case 0xe0: + svga->bpp = 24; + break; + + case 0x70: + svga->bpp = 32; + break; + + default: + svga->bpp = 8; break; } - svga_out(addr, val, svga); +} + +static void sdac_reg_write(sdac_ramdac_t *ramdac, int reg, uint8_t val) +{ + if ((reg >= 2 && reg <= 7) || (reg == 0xa) || (reg == 0xe)) + { + if (!ramdac->reg_ff) + ramdac->regs[reg] = (ramdac->regs[reg] & 0xff00) | val; + else + ramdac->regs[reg] = (ramdac->regs[reg] & 0x00ff) | (val << 8); + } + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + ramdac->windex++; +} + +static uint8_t sdac_reg_read(sdac_ramdac_t *ramdac, int reg) +{ + uint8_t temp; + + if (!ramdac->reg_ff) + temp = ramdac->regs[reg] & 0xff; + else + temp = ramdac->regs[reg] >> 8; + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + ramdac->rindex++; + + return temp; +} + +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 %i %i\n",addr,val,ramdac->magic_count,CS,cpu_state.pc, ramdac->rs2, ramdac->rindex, ramdac->windex); + switch (addr) + { + case 2: + if (ramdac->magic_count == 4) + sdac_control_write(ramdac, svga, val); + ramdac->magic_count = 0; + break; + + case 3: + ramdac->magic_count = 0; + break; + case 0: + ramdac->magic_count = 0; + break; + case 1: + ramdac->magic_count = 0; + break; + + case 4: + ramdac->windex = val; + ramdac->reg_ff = 0; + break; + case 5: + sdac_reg_write(ramdac, ramdac->windex & 0xff, val); + break; + case 6: + sdac_control_write(ramdac, svga, val); + break; + case 7: + ramdac->rindex = val; + ramdac->reg_ff = 0; + break; + } + if (!(addr & 4)) + { + if (addr < 2) + svga_out(addr + 0x3c8, val, svga); + else + svga_out(addr + 0x3c4, 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); +// /*if (CS!=0xC000) */pclog("IN RAMDAC %04X %04X:%04X %i %i %i\n",addr,CS,cpu_state.pc, ramdac->rs2, ramdac->rindex, ramdac->windex); switch (addr) { - case 0x3C6: - ramdac->reg_ff = 0; + case 2: if (ramdac->magic_count < 5) - ramdac->magic_count++; + ramdac->magic_count++; if (ramdac->magic_count == 4) { - temp = 0x70; /*SDAC ID*/ ramdac->rs2 = 1; + return 0x70; /*SDAC ID*/ } 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; + return ramdac->command; } break; + case 3: + ramdac->magic_count=0; + break; + case 0: + ramdac->magic_count=0; + break; + case 1: + ramdac->magic_count=0; + break; + + case 4: + return ramdac->windex; + case 5: + return sdac_reg_read(ramdac, ramdac->rindex & 0xff); + case 6: + return ramdac->command; + case 7: + return ramdac->rindex; } - return svga_in(addr, svga); + if (!(addr & 4)) + { + if (addr < 2) + return svga_in(addr + 0x3c8, svga); + else + return svga_in(addr + 0x3c4, svga); + } + return 0xff; } float sdac_getclock(int clock, void *p) @@ -126,10 +164,14 @@ float sdac_getclock(int clock, void *p) sdac_ramdac_t *ramdac = (sdac_ramdac_t *)p; float t; int m, n1, n2; + + if (ramdac->regs[0xe] & (1 << 5)) + clock = ramdac->regs[0xe] & 7; + // pclog("SDAC_Getclock %i %04X\n", clock, ramdac->regs[clock]); + clock &= 7; 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); @@ -137,3 +179,9 @@ float sdac_getclock(int clock, void *p) // 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; } + +void sdac_init(sdac_ramdac_t *ramdac) +{ + ramdac->regs[0] = 0x6128; + ramdac->regs[1] = 0x623d; +} diff --git a/src/vid_sdac_ramdac.h b/src/vid_sdac_ramdac.h index 3029d12..cd1d6f7 100644 --- a/src/vid_sdac_ramdac.h +++ b/src/vid_sdac_ramdac.h @@ -8,6 +8,8 @@ typedef struct sdac_ramdac_t int rs2; } sdac_ramdac_t; +void sdac_init(sdac_ramdac_t *ramdac); + 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); diff --git a/src/vid_sigma.c b/src/vid_sigma.c new file mode 100644 index 0000000..99235c2 --- /dev/null +++ b/src/vid_sigma.c @@ -0,0 +1,979 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "timer.h" +#include "video.h" +#include "vid_sigma.h" + + +/* The Sigma Designs Color 400 is a video card from 1985, presumably intended + * as an EGA competitor. + * + * The hardware seems to have gone through various iterations; I've seen + * pictures of full-length and half-length versions. + * TH99 describes the jumpers / switches: + * + * + * The card is CGA-compatible at BIOS level, but to improve compatibility + * attempts to write to the CGA I/O ports at 0x3D0-0x3DF trigger an NMI. The + * card's BIOS handles the NMI and translates the CGA writes into commands + * to its own hardware at 0x2D0-0x2DF. (DIP switches on the card allow the + * base address to be changed, but since the BIOS dump I have doesn't support + * this I haven't emulated it. Likewise the BIOS ROM address can be changed, + * but I'm going with the default of 0xC0000). + * + * The BIOS still functions if the NMI system isn't operational. There + * doesn't seem to be a jumper or DIP switch to lock it out, but at startup + * the BIOS tests for its presence and configures itself to work or not + * as required. I've therefore added a configuration option to handle this. + * + * The card's real CRTC at 0x2D0/0x2D1 appears to be a 6845. One oddity is + * that all its horizontal counts are halved compared to what a real CGA + * uses; 40-column modes have a width of 20, and 80-column modes have a + * width of 40. This means that the CRTC cursor position (registers 14/15) can + * only address even-numbered columns, so the top bit of the control + * register at 0x2D9 is used to adjust the position. + * + * Apart from the CRTC, registers are: + * + * 0x2D8: Mode register. Values written by the card BIOS are: + * Text 40x25: 0xA8 + * Text 80x25: 0xB9 + * Text 80x30: 0xB9 + * Text 80x50: 0x79 + * Graphics 320x200: 0x0F + * Graphics 640x200: 0x1F + * Graphics 640x400: 0x7F + * + * I have assumed this is a bitmap with the following meaning: */ +#define MODE_80COLS 0x01 /* For text modes, 80 columns across */ +#define MODE_GRAPHICS 0x02 /* Graphics mode */ +#define MODE_NOBLINK 0x04 /* Disable blink? */ +#define MODE_ENABLE 0x08 /* Enable display */ +#define MODE_HRGFX 0x10 /* For graphics modes, 640 pixels across */ +#define MODE_640x400 0x40 /* 400-line graphics mode */ +#define MODE_FONT16 0x80 /* Use 16-pixel high font */ +/* + * 0x2D9: Control register, with the following bits: */ +#define CTL_CURSOR 0x80 /* Low bit of cursor position */ +#define CTL_NMI 0x20 /* Writes to 0x3D0-0x3DF trigger NMI */ +#define CTL_CLEAR_LPEN 0x08 /* Strobe 0 to clear lightpen latch */ +#define CTL_SET_LPEN 0x04 /* Strobe 0 to set lightpen latch */ +#define CTL_PALETTE 0x01 /* 0x2DE writes to palette (1) or plane (0) */ +/* + * The card BIOS seems to support two variants of the hardware: One where + * bits 2 and 3 are normally 1 and are set to 0 to set/clear the latch, and + * one where they are normally 0 and are set to 1. Behaviour is selected by + * whether the byte at C000:17FFh is greater than 2Fh. + * + * 0x2DA: Status register. + */ +#define STATUS_CURSOR 0x80 /* Last value written to bit 7 of 0x2D9 */ +#define STATUS_NMI 0x20 /* Last value written to bit 5 of 0x2D9 */ +#define STATUS_RETR_V 0x10 /* Vertical retrace */ +#define STATUS_LPEN_T 0x04 /* Lightpen switch is off */ +#define STATUS_LPEN_A 0x02 /* Edge from lightpen has set trigger */ +#define STATUS_RETR_H 0x01 /* Horizontal retrace */ +/* + * 0x2DB: On read: Byte written to the card that triggered NMI + * 0x2DB: On write: Resets the 'card raised NMI' flag. + * 0x2DC: On read: Bit 7 set if the card raised NMI. If so, bits 0-3 + * give the low 4 bits of the I/O port address. + * 0x2DC: On write: Resets the NMI. + * 0x2DD: Memory paging. The memory from 0xC1800 to 0xC1FFF can be either: + * + * > ROM: A 128 character 8x16 font for use in graphics modes + * > RAM: Use by the video BIOS to hold its settings. + * + * Reading port 2DD switches to ROM. Bit 7 of the value read gives the + * previous paging state: bit 7 set if ROM was paged, clear if RAM was + * paged. + * + * Writing port 2DD switches to RAM. + * + * 0x2DE: Meaning depends on bottom bit of value written to port 0x2D9. + * Bit 0 set: Write to palette. High 4 bits of value = register, + * low 4 bits = RGBI values (active low) + * Bit 0 clear: Write to plane select. Low 2 bits of value select + * plane 0-3 + */ + + +typedef struct sigma_t +{ + mem_mapping_t mapping; + mem_mapping_t bios_ram; + rom_t bios_rom; + + uint8_t lastport; /* Last I/O port written */ + uint8_t lastwrite; /* Value written to that port */ + uint8_t sigma_ctl; /* Controls register: + * Bit 7 is low bit of cursor position + * Bit 5 set if writes to CGA ports trigger NMI + * Bit 3 clears lightpen latch + * Bit 2 sets lightpen latch + * Bit 1 controls meaning of port 2DE + */ + uint8_t enable_nmi; /* Enable the NMI mechanism for CGA emulation?*/ + uint8_t rom_paged; /* Is ROM paged in at 0xC1800? */ + + uint8_t crtc_value; /* Value to return from a CRTC register read */ + + int crtcreg; /* CRTC: Real selected register */ + uint8_t crtc[32]; /* CRTC: Real values */ + + uint8_t sigmastat; /* Status register [0x2DA] */ + + uint8_t sigmamode; /* Mode control register [0x2D8] */ + + int linepos, displine; + int sc, vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int oddeven; + + uint64_t dispontime, dispofftime; + pc_timer_t timer; + + int firstline, lastline; + + int drawcursor; + + uint8_t *vram; + uint8_t bram[2048]; + + uint8_t palette[16]; + + int plane; + int revision; +} sigma_t; + +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + +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 sigma_recalctimings(sigma_t *cga); + +void sigma_out(uint16_t addr, uint8_t val, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + uint8_t old; + +// pclog("SIGMA_OUT %04X %02X\n", addr, val); + +// if (addr == 0x3D8 && (val & 0x80)) output = 3; + + if (addr >= 0x3D0 && addr < 0x3E0) + { + sigma->lastport = addr & 0x0F; + sigma->lastwrite = val; + /* If set to NMI on video I/O... */ + if (sigma->enable_nmi && (sigma->sigma_ctl & CTL_NMI)) + { + sigma->lastport |= 0x80; /* Card raised NMI */ + nmi = 1; +// pclog("Sigma: Raise NMI\n"); + } + /* For CRTC emulation, the card BIOS sets the value to be + * read from port 0x3D1 like this */ + if (addr == 0x3D1) + sigma->crtc_value = val; + } + else switch (addr) + { + case 0x2D0: + case 0x2D2: + case 0x2D4: + case 0x2D6: + sigma->crtcreg = val & 31; + return; + + case 0x2D1: + case 0x2D3: + case 0x2D5: + case 0x2D7: + old = sigma->crtc[sigma->crtcreg]; + sigma->crtc[sigma->crtcreg] = val & crtcmask[sigma->crtcreg]; +// pclog("Sigma: CRTC[0x%02x] := 0x%02x\n", +// sigma->crtcreg, val); + if (old != val) + { + if (sigma->crtcreg < 0xe || sigma->crtcreg > 0x10) + { + fullchange = changeframecount; + sigma_recalctimings(sigma); + } + } + return; + + case 0x2D8: +// pclog("Sigma mode := %02x\n", val); + sigma->sigmamode = val; + return; + case 0x2D9: +// pclog("Sigma control := %02x\n", val); + sigma->sigma_ctl = val; + return; + case 0x2DB: + sigma->lastport &= 0x7F; + return; + case 0x2DC: /* Reset NMI */ + nmi = 0; + sigma->lastport &= 0x7F; +// pclog("Sigma: Reset NMI\n"); + return; + case 0x2DD: /* Page in RAM at 0xC1800 */ + if (sigma->rom_paged != 0) + mmu_invalidate(0xC0000); + sigma->rom_paged = 0; +// pclog("Sigma: page RAM at C1800\n"); + return; + + case 0x2DE: + if (sigma->sigma_ctl & CTL_PALETTE) + { +// pclog("Sigma: Write palette %x := %x\n", +// val >> 4, val & 0x0F); + sigma->palette[val >> 4] = (val & 0x0F) ^ 0x0F; + } + else + { +// pclog("Sigma: Set plane to %d\n", val & 3); + sigma->plane = val & 3; + } + return; + } +} + +uint8_t sigma_in(uint16_t addr, void *p) +{ + uint8_t result = 0xFF; + sigma_t *sigma = (sigma_t *)p; + + switch (addr) + { + case 0x2D0: + case 0x2D2: + case 0x2D4: + case 0x2D6: + result = sigma->crtcreg; + break; + + case 0x2D1: + case 0x2D3: + case 0x2D5: + case 0x2D7: + result = sigma->crtc[sigma->crtcreg & 0x1F]; + break; + + case 0x2DA: + result = (sigma->sigma_ctl & 0xE0) | + (sigma->sigmastat & 0x1F); + break; + + case 0x2DB: + result = sigma->lastwrite; /* Value that triggered NMI */ + break; + case 0x2DC: + result = sigma->lastport; /* Port that triggered NMI */ + break; + case 0x2DD: /* Page in ROM at 0xC1800 */ +// pclog("Sigma: page ROM at C1800\n"); + result = (sigma->rom_paged ? 0x80 : 0); + if (sigma->rom_paged != 0x80) + mmu_invalidate(0xC0000); + sigma->rom_paged = 0x80; + break; + + case 0x3D1: + case 0x3D3: + case 0x3D5: + case 0x3D7: + result = sigma->crtc_value; + break; + +/* For CGA compatibility we have to return something palatable on this port. + * On a real card this functionality can be turned on or off with SW1/6 */ + case 0x3DA: + result = sigma->sigmastat & 7; + if (sigma->sigmastat & STATUS_RETR_V) result |= 8; + break; + } +// pclog("SIGMA_IN %04X = %02x\n", addr, result); + return result; +} + +void sigma_write(uint32_t addr, uint8_t val, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + +// pclog("CGA_WRITE %04X %02X\n", addr, val); + sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)] = val; + egawrites++; + cycles -= 4; +} + +uint8_t sigma_read(uint32_t addr, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + + cycles -= 4; + egareads++; +// pclog("CGA_READ %04X\n", addr); + return sigma->vram[sigma->plane * 0x8000 + (addr & 0x7fff)]; +} + +void sigma_bwrite(uint32_t addr, uint8_t val, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + + addr &= 0x3FFF; + if (addr < 0x1800 || sigma->rom_paged || addr >= 0x2000) + { +// pclog("sigma_bwrite(0x%05x) := [ROM] %02x\n", addr, val); + } + else + { +// pclog("sigma_bwrite(0x%05x) := [RAM] %02x\n", addr, val); + sigma->bram[addr & 0x7FF] = val; + } +} + +uint8_t sigma_bread(uint32_t addr, void *p) +{ + sigma_t *sigma = (sigma_t *)p; + uint8_t result; + + addr &= 0x3FFF; + if (addr >= 0x2000) + { +// if (output == 3) pclog("sigma_bread(0x%05x) = [NIL] %02x\n", +// addr, 0xFF); + return 0xFF; + } + if (addr < 0x1800 || sigma->rom_paged) + { + result = sigma->bios_rom.rom[addr & 0x1FFF]; +// if (output == 3) pclog("sigma_bread(0x%05x) = [ROM] %02x\n", addr, result); + } + else + { + result = sigma->bram[addr & 0x7FF]; +// if (output == 3) pclog("sigma_bread(0x%05x) = [RAM] %02x\n", addr, result); + } + return result; +} + + + +void sigma_recalctimings(sigma_t *sigma) +{ + double disptime; + double _dispontime, _dispofftime; +// pclog("Sigma_recalctimings - total=%i displayed=%i hi-res=%i\n", +// sigma->crtc[0], sigma->crtc[1], sigma->sigmamode & MODE_80COLS); + if (sigma->sigmamode & MODE_80COLS) + { + disptime = (sigma->crtc[0] + 1) << 1; + _dispontime = (sigma->crtc[1]) << 1; + } + else + { + disptime = (sigma->crtc[0] + 1) << 2; + _dispontime = sigma->crtc[1] << 2; + } + _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); + sigma->dispontime = (uint64_t)_dispontime; + sigma->dispofftime = (uint64_t)_dispofftime; +} + + + + +/* Render a line in 80-column text mode */ +void sigma_text80(sigma_t *sigma) +{ + int x, c; + uint8_t chr, attr; + uint16_t ca = (sigma->crtc[15] | (sigma->crtc[14] << 8)); + uint16_t ma = ((sigma->ma & 0x3FFF) << 1); + int drawcursor; + uint32_t cols[4]; + uint8_t *vram = sigma->vram + (ma << 1); + + ca = ca << 1; + if (sigma->sigma_ctl & CTL_CURSOR) ++ca; + ca &= 0x3fff; +// pclog("sigma_text80: displine=%d sc=%d Width=%d\n", +// sigma->displine, sigma->sc, sigma->crtc[1]); + + /* The Sigma 400 seems to use screen widths stated in words + * (40 for 80-column, 20 for 40-column) */ + for (x = 0; x < (sigma->crtc[1] << 1); x++) + { + chr = vram[x << 1]; + attr = vram[(x << 1) + 1]; + drawcursor = ((ma == ca) && sigma->con && sigma->cursoron); + + if (!(sigma->sigmamode & MODE_NOBLINK)) + { + cols[1] = attr & 15; + cols[0] = (attr >> 4) & 7; + if ((sigma->cgablink & 8) && (attr & 0x80) && !sigma->drawcursor) + cols[1] = cols[0]; + } + else /* No blink */ + { + cols[1] = attr & 15; + cols[0] = attr >> 4; + } +// if (chr != ' ') +// { +// pclog("[%x:%x]%c", cols[1], cols[0], chr); +// } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + if (sigma->sigmamode & MODE_FONT16) + ((uint32_t *)buffer32->line[sigma->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + else ((uint32_t *)buffer32->line[sigma->displine])[(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + } + } + else + { + for (c = 0; c < 8; c++) + { + if (sigma->sigmamode & MODE_FONT16) + ((uint32_t *)buffer32->line[sigma->displine])[(x << 3) + c + 8] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + else ((uint32_t *)buffer32->line[sigma->displine])[(x << 3) + c + 8] = cols[(fontdat[chr][sigma->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + ++ma; + } + sigma->ma += sigma->crtc[1]; + //pclog("\n"); +} + + +/* Render a line in 40-column text mode */ +void sigma_text40(sigma_t *sigma) +{ + int x, c; + uint8_t chr, attr; + uint16_t ca = (sigma->crtc[15] | (sigma->crtc[14] << 8)); + uint16_t ma = ((sigma->ma & 0x3FFF) << 1); + int drawcursor; + uint32_t cols[4]; + uint8_t *vram = sigma->vram + ((ma << 1) & 0x3FFF); + + ca = ca << 1; + if (sigma->sigma_ctl & CTL_CURSOR) ++ca; + ca &= 0x3fff; + /* The Sigma 400 seems to use screen widths stated in words + * (40 for 80-column, 20 for 40-column) */ + for (x = 0; x < (sigma->crtc[1] << 1); x++) + { + chr = vram[x << 1]; + attr = vram[(x << 1) + 1]; + drawcursor = ((ma == ca) && sigma->con && sigma->cursoron); + + if (!(sigma->sigmamode & MODE_NOBLINK)) + { + cols[1] = attr & 15; + cols[0] = (attr >> 4) & 7; + if ((sigma->cgablink & 8) && (attr & 0x80) && !sigma->drawcursor) + cols[1] = cols[0]; + } + else /* No blink */ + { + cols[1] = attr & 15; + cols[0] = attr >> 4; + } +// if (chr != ' ') +// { +// pclog("[%x:%x]%c", cols[1], cols[0], chr); +// } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[sigma->displine])[(x << 4) + 2*c + 8] = + ((uint32_t *)buffer32->line[sigma->displine])[(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + } + } + else + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[sigma->displine])[(x << 4) + 2*c + 8] = + ((uint32_t *)buffer32->line[sigma->displine])[(x << 4) + 2*c + 9] = cols[(fontdatm[chr][sigma->sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + ma++; + } + sigma->ma += sigma->crtc[1]; + //pclog("\n"); +} + + + + +/* Draw a line in the 640x400 graphics mode */ +void sigma_gfx400(sigma_t *sigma) +{ + int x; + unsigned char *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + + (sigma->sc & 3) * 0x2000]; + uint8_t plane[4]; + uint8_t mask, col, c; + + for (x = 0; x < (sigma->crtc[1] << 1); x++) + { + plane[0] = vram[x]; + plane[1] = vram[0x8000 + x]; + plane[2] = vram[0x10000 + x]; + plane[3] = vram[0x18000 + x]; + + for (c = 0, mask = 0x80; c < 8; c++, mask >>= 1) + { + col = ((plane[3] & mask) ? 8 : 0) | + ((plane[2] & mask) ? 4 : 0) | + ((plane[1] & mask) ? 2 : 0) | + ((plane[0] & mask) ? 1 : 0); + ((uint32_t *)buffer32->line[sigma->displine])[(x << 3) + c + 8] = col; + } + if (x & 1) ++sigma->ma; + } +} + + +/* Draw a line in the 640x200 graphics mode. + * This is actually a 640x200x16 mode; on startup, the BIOS selects plane 2, + * blanks the other planes, and sets palette ink 4 to white. Pixels plotted + * in plane 2 come out in white, others black; but by programming the palette + * and plane registers manually you can get the full resolution. */ +void sigma_gfx200(sigma_t *sigma) +{ + int x; + unsigned char *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + + (sigma->sc & 2) * 0x1000]; + uint8_t plane[4]; + uint8_t mask, col, c; + + for (x = 0; x < (sigma->crtc[1] << 1); x++) + { + plane[0] = vram[x]; + plane[1] = vram[0x8000 + x]; + plane[2] = vram[0x10000 + x]; + plane[3] = vram[0x18000 + x]; + + for (c = 0, mask = 0x80; c < 8; c++, mask >>= 1) + { + col = ((plane[3] & mask) ? 8 : 0) | + ((plane[2] & mask) ? 4 : 0) | + ((plane[1] & mask) ? 2 : 0) | + ((plane[0] & mask) ? 1 : 0); + ((uint32_t *)buffer32->line[sigma->displine])[(x << 3) + c + 8] = col; + } + if (x & 1) ++sigma->ma; + } +} + + + + + +/* Draw a line in the 320x200 graphics mode */ +void sigma_gfx4col(sigma_t *sigma) +{ + int x; + unsigned char *vram = &sigma->vram[((sigma->ma << 1) & 0x1FFF) + + (sigma->sc & 2) * 0x1000]; + uint8_t plane[4]; + uint8_t mask, col, c; + + for (x = 0; x < (sigma->crtc[1] << 1); x++) + { + plane[0] = vram[x]; + plane[1] = vram[0x8000 + x]; + plane[2] = vram[0x10000 + x]; + plane[3] = vram[0x18000 + x]; + + mask = 0x80; + for (c = 0; c < 4; c++) + { + col = ((plane[3] & mask) ? 2 : 0) | + ((plane[2] & mask) ? 1 : 0); + mask = mask >> 1; + col |= ((plane[3] & mask) ? 8 : 0) | + ((plane[2] & mask) ? 4 : 0); + mask = mask >> 1; + + ((uint32_t *)buffer32->line[sigma->displine])[(x << 3) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[sigma->displine])[(x << 3) + (c << 1) + 9] = col; + } + if (x & 1) ++sigma->ma; + } +} + + + + +void sigma_poll(void *p) +{ + sigma_t *sigma = (sigma_t *)p; + int x, c; + int oldvc; + uint32_t cols[4]; + int oldsc; + + if (!sigma->linepos) + { + timer_advance_u64(&sigma->timer, sigma->dispofftime); + sigma->sigmastat |= STATUS_RETR_H; + sigma->linepos = 1; + oldsc = sigma->sc; + if ((sigma->crtc[8] & 3) == 3) + sigma->sc = ((sigma->sc << 1) + sigma->oddeven) & 7; + if (sigma->cgadispon) + { + if (sigma->displine < sigma->firstline) + { + sigma->firstline = sigma->displine; + video_wait_for_buffer(); +// printf("Firstline %i\n",firstline); + } + sigma->lastline = sigma->displine; + + cols[0] = 0; + // Left overscan + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[sigma->displine])[c] = cols[0]; + if (sigma->sigmamode & MODE_80COLS) + ((uint32_t *)buffer32->line[sigma->displine])[c + (sigma->crtc[1] << 4) + 8] = cols[0]; + else + ((uint32_t *)buffer32->line[sigma->displine])[c + (sigma->crtc[1] << 5) + 8] = cols[0]; + } + if (sigma->sigmamode & MODE_GRAPHICS) + { + if (sigma->sigmamode & MODE_640x400) + { + sigma_gfx400(sigma); + } + else if (sigma->sigmamode & MODE_HRGFX) + { + sigma_gfx200(sigma); + } + else sigma_gfx4col(sigma); + + } + else /* Text modes */ + { + if (sigma->sigmamode & MODE_80COLS) + { + sigma_text80(sigma); + } + else + { + sigma_text40(sigma); + } + } + } + else + { + cols[0] = 0; + if (sigma->sigmamode & MODE_80COLS) + hline(buffer32, 0, sigma->displine, (sigma->crtc[1] << 4) + 16, cols[0]); + else hline(buffer32, 0, sigma->displine, (sigma->crtc[1] << 5) + 16, cols[0]); + } + + if (sigma->sigmamode & MODE_80COLS) + { + x = (sigma->crtc[1] << 4) + 16; + } + else + { + x = (sigma->crtc[1] << 5) + 16; + } + + for (c = 0; c < x; c++) + { + ((uint32_t *)buffer32->line[sigma->displine])[c] = cgapal[sigma->palette[((uint32_t *)buffer32->line[sigma->displine])[c] & 0xf]]; + } + + sigma->sc = oldsc; + if (sigma->vc == sigma->crtc[7] && !sigma->sc) + sigma->sigmastat |= STATUS_RETR_V; + sigma->displine++; + if (sigma->displine >= 560) + sigma->displine = 0; + } + else + { + timer_advance_u64(&sigma->timer, sigma->dispontime); + sigma->linepos = 0; + if (sigma->vsynctime) + { + sigma->vsynctime--; + if (!sigma->vsynctime) + sigma->sigmastat &= ~STATUS_RETR_V; + } + if (sigma->sc == (sigma->crtc[11] & 31) || ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[11] & 31) >> 1))) + { + sigma->con = 0; + sigma->coff = 1; + } + if ((sigma->crtc[8] & 3) == 3 && sigma->sc == (sigma->crtc[9] >> 1)) + sigma->maback = sigma->ma; + if (sigma->vadj) + { + sigma->sc++; + sigma->sc &= 31; + sigma->ma = sigma->maback; + sigma->vadj--; + if (!sigma->vadj) + { + sigma->cgadispon = 1; + sigma->ma = sigma->maback = (sigma->crtc[13] | (sigma->crtc[12] << 8)) & 0x3fff; + sigma->sc = 0; + } + } + else if (sigma->sc == sigma->crtc[9]) + { + sigma->maback = sigma->ma; + sigma->sc = 0; + oldvc = sigma->vc; + sigma->vc++; + sigma->vc &= 127; + + if (sigma->vc == sigma->crtc[6]) + sigma->cgadispon = 0; + + if (oldvc == sigma->crtc[4]) + { + sigma->vc = 0; + sigma->vadj = sigma->crtc[5]; + if (!sigma->vadj) sigma->cgadispon = 1; + if (!sigma->vadj) sigma->ma = sigma->maback = (sigma->crtc[13] | (sigma->crtc[12] << 8)) & 0x3fff; + if ((sigma->crtc[10] & 0x60) == 0x20) sigma->cursoron = 0; + else sigma->cursoron = sigma->cgablink & 8; + } + + if (sigma->vc == sigma->crtc[7]) + { + sigma->cgadispon = 0; + sigma->displine = 0; + sigma->vsynctime = 16; + if (sigma->crtc[7]) + { + if (sigma->sigmamode & MODE_80COLS) + x = (sigma->crtc[1] << 4) + 16; + else + x = (sigma->crtc[1] << 5) + 16; + sigma->lastline++; + if (x != xsize || (sigma->lastline - sigma->firstline) != ysize) + { + xsize = x; + ysize = sigma->lastline - sigma->firstline; +// pclog("sigma: xsize := %d ysize := %d\n", xsize, ysize); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize + 8); + } + + video_blit_memtoscreen(0, sigma->firstline - 4, 0, (sigma->lastline - sigma->firstline) + 8, xsize, (sigma->lastline - sigma->firstline) + 8); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (sigma->sigmamode & MODE_GRAPHICS) + { + if (sigma->sigmamode & (MODE_HRGFX | MODE_640x400)) + { + video_bpp = 1; + } + else + { + video_res_x /= 2; + video_bpp = 2; + } + } + else if (sigma->sigmamode & MODE_80COLS) + { +/* 80-column text */ + video_res_x /= 8; + video_res_y /= sigma->crtc[9] + 1; + video_bpp = 0; + } + else + { +/* 40-column text */ + video_res_x /= 16; + video_res_y /= sigma->crtc[9] + 1; + video_bpp = 0; + } + } + sigma->firstline = 1000; + sigma->lastline = 0; + sigma->cgablink++; + sigma->oddeven ^= 1; + } + } + else + { + sigma->sc++; + sigma->sc &= 31; + sigma->ma = sigma->maback; + } + if (sigma->cgadispon) + sigma->sigmastat &= ~STATUS_RETR_H; + if ((sigma->sc == (sigma->crtc[10] & 31) || ((sigma->crtc[8] & 3) == 3 && sigma->sc == ((sigma->crtc[10] & 31) >> 1)))) + sigma->con = 1; + } +} + + + + +void *sigma_init() +{ + int display_type, contrast; + sigma_t *sigma = malloc(sizeof(sigma_t)); + memset(sigma, 0, sizeof(sigma_t)); + + display_type = device_get_config_int("display_type"); + contrast = device_get_config_int("contrast"); + sigma->enable_nmi = device_get_config_int("enable_nmi"); + + loadfont("sigma400_font.rom", 7); + rom_init(&sigma->bios_rom, "sigma400_bios.rom", 0xC0000, 0x2000, + 0x1FFF, 0, MEM_MAPPING_EXTERNAL); + /* The BIOS ROM is overlaid by RAM, so remove its default mapping + * and access it through sigma_bread() / sigma_bwrite() below */ + mem_mapping_disable(&sigma->bios_rom.mapping); + + sigma->vram = malloc(0x8000 * 4); + + timer_add(&sigma->timer, sigma_poll, sigma, 1); + mem_mapping_add(&sigma->mapping, 0xb8000, 0x08000, + sigma_read, NULL, NULL, + sigma_write, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, sigma); + mem_mapping_add(&sigma->bios_ram, 0xC1800, 0x0800, + sigma_bread, NULL, NULL, + sigma_bwrite, NULL, NULL, + sigma->bios_rom.rom, MEM_MAPPING_EXTERNAL, sigma); + io_sethandler(0x03d0, 0x0010, + sigma_in, NULL, NULL, + sigma_out, NULL, NULL, sigma); + io_sethandler(0x02d0, 0x0010, + sigma_in, NULL, NULL, + sigma_out, NULL, NULL, sigma); + + /* Start with ROM paged in, BIOS RAM paged out */ + sigma->rom_paged = 0x80; + + cgapal_rebuild(display_type, contrast); + + if (sigma->enable_nmi) + { + sigma->sigmastat = STATUS_LPEN_T; + } + return sigma; +} + +void sigma_close(void *p) +{ + sigma_t *sigma = (sigma_t *)p; + + free(sigma->vram); + free(sigma); +} + +void sigma_speed_changed(void *p) +{ + sigma_t *sigma = (sigma_t *)p; + + sigma_recalctimings(sigma); +} + +device_config_t sigma_config[] = +{ + { + .name = "display_type", + .description = "Display type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "RGB", + .value = DISPLAY_RGB + }, + { + .description = "RGB (no brown)", + .value = DISPLAY_RGB_NO_BROWN + }, + { + .description = "Green Monochrome", + .value = DISPLAY_GREEN + }, + { + .description = "Amber Monochrome", + .value = DISPLAY_AMBER + }, + { + .description = "White Monochrome", + .value = DISPLAY_WHITE + }, + { + .description = "" + } + }, + .default_int = DISPLAY_RGB + }, + { + .name = "enable_nmi", + .description = "Enable NMI for CGA emulation", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "contrast", + .description = "Alternate monochrome contrast", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .type = -1 + } +}; + +device_t sigma_device = +{ + "Sigma Color 400", + 0, + sigma_init, + sigma_close, + NULL, + sigma_speed_changed, + NULL, + NULL, + sigma_config +}; diff --git a/src/vid_sigma.h b/src/vid_sigma.h new file mode 100644 index 0000000..f59088e --- /dev/null +++ b/src/vid_sigma.h @@ -0,0 +1,2 @@ +extern device_t sigma_device; + diff --git a/src/vid_svga.c b/src/vid_svga.c index 34ecb1e..c41528c 100644 --- a/src/vid_svga.c +++ b/src/vid_svga.c @@ -53,6 +53,8 @@ void svga_out(uint16_t addr, uint8_t val, void *p) } else { + if ((svga->attraddr == 0x13) && (svga->attrregs[0x13] != val)) + svga->fullchange = changeframecount; svga->attrregs[svga->attraddr & 31] = val; if (svga->attraddr < 16) svga->fullchange = changeframecount; @@ -78,16 +80,9 @@ void svga_out(uint16_t addr, uint8_t val, void *p) case 0x3C2: svga->miscout = val; 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_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + if (!(val & 1)) io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); - } svga_recalctimings(svga); break; case 0x3C4: @@ -121,7 +116,8 @@ void svga_out(uint16_t addr, uint8_t val, void *p) 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->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && + ((svga->chain4 && svga->packed_chain4) || svga->fb_only); break; } break; @@ -151,7 +147,7 @@ void svga_out(uint16_t addr, uint8_t val, void *p) svga->dac_pos++; break; case 2: - svga->vgapal[svga->dac_write].r = svga->dac_r; + 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) @@ -206,7 +202,8 @@ void svga_out(uint16_t addr, uint8_t val, void *p) 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; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && + ((svga->chain4 && svga->packed_chain4) || svga->fb_only); if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) svga_recalctimings(svga); break; @@ -243,14 +240,20 @@ uint8_t svga_in(uint16_t addr, void *p) { case 0: svga->dac_pos++; - return svga->vgapal[svga->dac_read].r; + if (svga->ramdac_type == RAMDAC_8BIT) + return svga->vgapal[svga->dac_read].r; + return svga->vgapal[svga->dac_read].r & 0x3f; case 1: svga->dac_pos++; - return svga->vgapal[svga->dac_read].g; + if (svga->ramdac_type == RAMDAC_8BIT) + return svga->vgapal[svga->dac_read].g; + return svga->vgapal[svga->dac_read].g & 0x3f; case 2: svga->dac_pos=0; svga->dac_read = (svga->dac_read + 1) & 255; - return svga->vgapal[(svga->dac_read - 1) & 255].b; + if (svga->ramdac_type == RAMDAC_8BIT) + return svga->vgapal[(svga->dac_read - 1) & 255].b; + return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; } break; case 0x3CC: @@ -261,6 +264,7 @@ uint8_t svga_in(uint16_t addr, void *p) return svga->gdcreg[svga->gdcaddr & 0xf]; case 0x3DA: svga->attrff = 0; + if (svga->cgastat & 0x01) svga->cgastat &= ~0x30; else @@ -334,13 +338,17 @@ void svga_recalctimings(svga_t *svga) svga->interlace = 0; - svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + svga->ma_latch = ((svga->crtc[0xc] << 8) | svga->crtc[0xd]) + ((svga->crtc[8] & 0x60) >> 5); + svga->ca_adj = 0; + + svga->rowcount = svga->crtc[9] & 31; + svga->linedbl = svga->crtc[9] & 0x80; 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->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) /*Text mode*/ { if (svga->seqregs[1] & 8) /*40 column*/ { @@ -414,15 +422,14 @@ void svga_recalctimings(svga_t *svga) // 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; + svga->char_width = (svga->seqregs[1] & 1) ? 8 : 9; 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); + crtcconst = svga->clock * svga->char_width; disptime = svga->htotal; _dispontime = svga->hdisp_time; @@ -433,8 +440,14 @@ void svga_recalctimings(svga_t *svga) _dispontime *= crtcconst; _dispofftime *= crtcconst; - svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + svga->dispontime = (uint64_t)_dispontime; + svga->dispofftime = (uint64_t)_dispofftime; + if (svga->dispontime < TIMER_USEC) + svga->dispontime = TIMER_USEC; + if (svga->dispofftime < TIMER_USEC) + svga->dispofftime = TIMER_USEC; + + svga_recalc_remap_func(svga); /* 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]); @@ -453,13 +466,17 @@ void svga_poll(void *p) // 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_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff; + if (svga->hwcursor_on < 0) + svga->hwcursor_on = 0; 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_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff; + if (svga->hwcursor_on < 0) + svga->hwcursor_on = 0; svga->hwcursor_oddeven = 1; } @@ -474,7 +491,7 @@ void svga_poll(void *p) svga->overlay_oddeven = 1; } - svga->vidtime += svga->dispofftime; + timer_advance_u64(&svga->timer, svga->dispofftime); // if (output) printf("Display off %f\n",vidtime); svga->cgastat |= 1; svga->linepos = 1; @@ -483,7 +500,7 @@ void svga_poll(void *p) { svga->hdisp_on=1; - svga->ma &= svga->vrammask; + svga->ma &= svga->vram_display_mask; if (svga->firstline == 2000) { svga->firstline = svga->displine; @@ -491,7 +508,7 @@ void svga_poll(void *p) } if (svga->hwcursor_on || svga->overlay_on) - svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = 2; + svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = svga->interlace ? 3 : 2; if (!svga->override) svga->render(svga); @@ -536,7 +553,7 @@ void svga_poll(void *p) else { // pclog("VC %i ma %05X\n", svga->vc, svga->ma); - svga->vidtime += svga->dispontime; + timer_advance_u64(&svga->timer, svga->dispontime); // if (output) printf("Display on %f\n",vidtime); if (svga->dispon) @@ -561,7 +578,7 @@ void svga_poll(void *p) svga->maback += (svga->rowoffset << 3); if (svga->interlace) svga->maback += (svga->rowoffset << 3); - svga->maback &= svga->vrammask; + svga->maback &= svga->vram_display_mask; svga->ma = svga->maback; } else @@ -572,15 +589,29 @@ void svga_poll(void *p) svga->ma = svga->maback; } } + svga->hsync_divisor = !svga->hsync_divisor; + + if (svga->hsync_divisor && (svga->crtc[0x17] & 4)) + return; + 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; + int ret = 1; + + if (svga->line_compare) + ret = svga->line_compare(svga); + + if (ret) + { +// pclog("VC split\n"); + svga->ma = svga->maback = 0; + svga->sc = 0; + if (svga->attrregs[0x10] & 0x20) + svga->scrollcache = 0; + } } if (svga->vc == svga->dispend) { @@ -594,7 +625,7 @@ void svga_poll(void *p) svga->fullchange = 2; svga->blink++; - for (x = 0; x < (svga->vram_limit >> 12); x++) + for (x = 0; x < ((svga->vram_mask+1) >> 12); x++) { if (svga->changedvram[x]) svga->changedvram[x]--; @@ -635,41 +666,53 @@ void svga_poll(void *p) 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->ca = ((svga->crtc[0xe] << 8) | svga->crtc[0xf]) + svga->ca_adj; 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*/ + if (!svga->video_res_override) { - 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; + svga->video_res_x = wx; + svga->video_res_y = wy + 1; - switch (svga->gdcreg[5] & 0x60) + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) /*Text mode*/ { - case 0x00: svga->video_bpp = 4; break; - case 0x20: svga->video_bpp = 2; break; - case 0x40: case 0x60: svga->video_bpp = svga->bpp; break; + svga->video_res_x /= svga->char_width; + 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] & 2)) + svga->video_res_y *= 4; + else if (!(svga->crtc[0x17] & 1)) + svga->video_res_y *= 2; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + if (svga->render == svga_render_8bpp_lowres || + svga->render == svga_render_15bpp_lowres || + svga->render == svga_render_16bpp_lowres || + svga->render == svga_render_24bpp_lowres || + svga->render == svga_render_32bpp_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->vsync_callback) + svga->vsync_callback(svga); } if (svga->vc == svga->vtotal) { @@ -678,7 +721,7 @@ void svga_poll(void *p) // printf("Frame over at line %i %i %i %i\n",displine,vc,svga_vsyncstart,svga_dispend); svga->vc = 0; - svga->sc = 0; + svga->sc = svga->crtc[8] & 0x1f; svga->dispon = 1; svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; svga->scrollcache = svga->attrregs[0x13] & 7; @@ -724,23 +767,27 @@ int svga_init(svga_t *svga, void *p, int memsize, svga->crtc[0] = 63; svga->crtc[6] = 255; - svga->dispontime = 1000 * (1 << TIMER_SHIFT); - svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->dispontime = 1000ull << 32; + svga->dispofftime = 1000ull << 32; svga->bpp = 8; svga->vram = malloc(memsize); - svga->vram_limit = memsize; - svga->vrammask = memsize - 1; - svga->changedvram = malloc(/*(memsize >> 12) << 1*/0x800000 >> 12); + svga->vram_max = memsize; + svga->vram_display_mask = memsize - 1; + svga->vram_mask = memsize - 1; + svga->decode_mask = 0x7fffff; + svga->changedvram = malloc(/*(memsize >> 12) << 1*/0x1000000 >> 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->hwcursor.ysize = 64; + svga->ksc5601_english_font_type = 0; // _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); + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, MEM_MAPPING_EXTERNAL, svga); - timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); + timer_add(&svga->timer, svga_poll, svga, 1); svga_pri = svga; @@ -765,19 +812,25 @@ void svga_write(uint32_t addr, uint8_t val, void *p) egawrites++; - cycles -= video_timing_b; - cycles_lost += video_timing_b; + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; if (svga_output) pclog("Writeega %06X ",addr); addr &= svga->banked_mask; addr += svga->write_bank; if (!(svga->gdcreg[6] & 1)) svga->fullchange=2; - if (svga->chain4 || svga->fb_only) + if ((svga->chain4 && svga->packed_chain4) || svga->fb_only) { writemask2=1<<(addr&3); addr&=~3; } + else if (svga->chain4) + { + writemask2 = 1 << (addr & 3); + addr &= ~3; + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); + } else if (svga->chain2_write) { writemask2 &= ~0xa; @@ -790,10 +843,12 @@ void svga_write(uint32_t addr, uint8_t val, void *p) { addr<<=2; } - addr &= 0x7fffff; + addr &= svga->decode_mask; - if (addr >= svga->vram_limit) + if (addr >= svga->vram_max) return; + + addr &= svga->vram_mask; 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; @@ -809,7 +864,7 @@ void svga_write(uint32_t addr, uint8_t val, void *p) 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 (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { if (writemask2 & 1) svga->vram[addr] = val; if (writemask2 & 2) svga->vram[addr | 0x1] = val; @@ -858,7 +913,7 @@ void svga_write(uint32_t addr, uint8_t val, void *p) } break; case 2: - if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { 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]); @@ -949,24 +1004,35 @@ uint8_t svga_read(uint32_t addr, void *p) uint32_t latch_addr; int readplane = svga->readplane; - cycles -= video_timing_b; - cycles_lost += video_timing_b; - + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; + egareads++; // pclog("Readega %06X ",addr); + addr &= svga->banked_mask; addr += svga->read_bank; - - latch_addr = (addr << 2) & 0x7fffff; + + latch_addr = (addr << 2) & svga->decode_mask; // 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) + if ((svga->chain4 && svga->packed_chain4) || svga->fb_only) { - addr &= 0x7fffff; - if (addr >= svga->vram_limit) - return 0xff; - return svga->vram[addr]; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + latch_addr = addr & svga->vram_mask & ~3; + 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]; + return svga->vram[addr & svga->vram_mask]; + } + else if (svga->chain4) + { + readplane = addr & 3; + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); } else if (svga->chain2_read) { @@ -976,36 +1042,41 @@ uint8_t svga_read(uint32_t addr, void *p) } else addr<<=2; + + addr &= svga->decode_mask; - addr &= 0x7fffff; - - if (addr >= svga->vram_limit) - return 0xff; - - if (latch_addr < svga->vram_limit) + if (latch_addr >= svga->vram_max) + { + svga->la = svga->lb = svga->lc = svga->ld = 0xff; + } + else { + latch_addr &= svga->vram_mask; 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 (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + if (svga->readmode) { - temp = (svga->colournocare & 1) ? 0xff : 0; - temp &= svga->la; + temp = svga->la; temp ^= (svga->colourcompare & 1) ? 0xff : 0; - temp2 = (svga->colournocare & 2) ? 0xff : 0; - temp2 &= svga->lb; + temp &= (svga->colournocare & 1) ? 0xff : 0; + temp2 = svga->lb; temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; - temp3 = (svga->colournocare & 4) ? 0xff : 0; - temp3 &= svga->lc; + temp2 &= (svga->colournocare & 2) ? 0xff : 0; + temp3 = svga->lc; temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; - temp4 = (svga->colournocare & 8) ? 0xff : 0; - temp4 &= svga->ld; + temp3 &= (svga->colournocare & 4) ? 0xff : 0; + temp4 = svga->ld; temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + temp4 &= (svga->colournocare & 8) ? 0xff : 0; return ~(temp | temp2 | temp3 | temp4); } //pclog("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); @@ -1018,19 +1089,24 @@ void svga_write_linear(uint32_t addr, uint8_t val, void *p) uint8_t vala, valb, valc, vald, wm = svga->writemask; int writemask2 = svga->writemask; - cycles -= video_timing_b; - cycles_lost += video_timing_b; + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_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) + if ((svga->chain4 && svga->packed_chain4) || svga->fb_only) { writemask2=1<<(addr&3); addr&=~3; } + else if (svga->chain4) + { + writemask2 = 1 << (addr & 3); + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); + } else if (svga->chain2_write) { writemask2 &= ~0xa; @@ -1043,9 +1119,10 @@ void svga_write_linear(uint32_t addr, uint8_t val, void *p) { addr<<=2; } - addr &= 0x7fffff; - if (addr >= svga->vram_limit) + addr &= svga->decode_mask; + if (addr >= svga->vram_max) return; + addr &= svga->vram_mask; if (svga_output) pclog("%08X\n", addr); svga->changedvram[addr >> 12]=changeframecount; @@ -1060,7 +1137,7 @@ void svga_write_linear(uint32_t addr, uint8_t val, void *p) 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 (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { if (writemask2 & 1) svga->vram[addr] = val; if (writemask2 & 2) svga->vram[addr | 0x1] = val; @@ -1109,7 +1186,7 @@ void svga_write_linear(uint32_t addr, uint8_t val, void *p) } break; case 2: - if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) { 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]); @@ -1198,18 +1275,24 @@ 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; + uint32_t latch_addr = (addr << 2) & svga->decode_mask; - cycles -= video_timing_b; - cycles_lost += video_timing_b; + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; egareads++; - if (svga->chain4 || svga->fb_only) + if ((svga->chain4 && svga->packed_chain4) || svga->fb_only) { - addr &= 0x7fffff; - if (addr >= svga->vram_limit) - return 0xff; - return svga->vram[addr & 0x7fffff]; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + return svga->vram[addr & svga->vram_mask]; + } + else if (svga->chain4) + { + readplane = addr & 3; + addr = ((addr & 0xfffc) << 2) | ((addr & 0x30000) >> 14) | (addr & ~0x3ffff); } else if (svga->chain2_read) { @@ -1218,31 +1301,44 @@ uint8_t svga_read_linear(uint32_t addr, void *p) addr <<= 2; } else + { addr<<=2; + } - addr &= 0x7fffff; + addr &= svga->decode_mask; - if (addr >= svga->vram_limit) - return 0xff; + if (latch_addr >= svga->vram_max) + { + svga->la = svga->lb = svga->lc = svga->ld = 0xff; + } + else + { + latch_addr &= svga->vram_mask; + 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]; + } + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; - 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->la; temp ^= (svga->colourcompare & 1) ? 0xff : 0; - temp2 = (svga->colournocare & 2) ? 0xff : 0; - temp2 &= svga->lb; + temp &= (svga->colournocare & 1) ? 0xff : 0; + temp2 = svga->lb; temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; - temp3 = (svga->colournocare & 4) ? 0xff : 0; - temp3 &= svga->lc; + temp2 &= (svga->colournocare & 2) ? 0xff : 0; + temp3 = svga->lc; temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; - temp4 = (svga->colournocare & 8) ? 0xff : 0; - temp4 &= svga->ld; + temp3 &= (svga->colournocare & 4) ? 0xff : 0; + temp4 = svga->ld; temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + temp4 &= (svga->colournocare & 8) ? 0xff : 0; return ~(temp | temp2 | temp3 | temp4); } //printf("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); @@ -1268,7 +1364,10 @@ void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) if (xsize<64) xsize=656; if (ysize<32) ysize=200; - updatewindowsize(xsize,ysize); + if (svga->vertical_linedbl) + updatewindowsize(xsize,ysize*2); + else + updatewindowsize(xsize,ysize); } if (vid_resize) { @@ -1291,14 +1390,15 @@ void svga_writew(uint32_t addr, uint16_t val, void *p) egawrites += 2; - cycles -= video_timing_w; - cycles_lost += video_timing_w; + cycles -= video_timing_write_w; + cycles_lost += video_timing_write_w; if (svga_output) pclog("svga_writew: %05X ", addr); addr = (addr & svga->banked_mask) + svga->write_bank; - addr &= 0x7FFFFF; - if (addr >= svga->vram_limit) + addr &= svga->decode_mask; + if (addr >= svga->vram_max) return; + addr &= svga->vram_mask; 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; @@ -1319,14 +1419,15 @@ void svga_writel(uint32_t addr, uint32_t val, void *p) egawrites += 4; - cycles -= video_timing_l; - cycles_lost += video_timing_l; + cycles -= video_timing_write_l; + cycles_lost += video_timing_write_l; if (svga_output) pclog("svga_writel: %05X ", addr); addr = (addr & svga->banked_mask) + svga->write_bank; - addr &= 0x7FFFFF; - if (addr >= svga->vram_limit) + addr &= svga->decode_mask; + if (addr >= svga->vram_max) return; + addr &= svga->vram_mask; if (svga_output) pclog("%08X (%i, %i) %08X\n", addr, addr & 1023, addr >> 10, val); svga->changedvram[addr >> 12] = changeframecount; @@ -1342,16 +1443,17 @@ uint16_t svga_readw(uint32_t addr, void *p) egareads += 2; - cycles -= video_timing_w; - cycles_lost += video_timing_w; + cycles -= video_timing_read_w; + cycles_lost += video_timing_read_w; // pclog("Readw %05X ", addr); addr = (addr & svga->banked_mask) + svga->read_bank; - addr &= 0x7FFFFF; + addr &= svga->decode_mask; // pclog("%08X %04X\n", addr, *(uint16_t *)&vram[addr]); - if (addr >= svga->vram_limit) return 0xffff; + if (addr >= svga->vram_max) + return 0xffff; - return *(uint16_t *)&svga->vram[addr]; + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; } uint32_t svga_readl(uint32_t addr, void *p) @@ -1363,16 +1465,17 @@ uint32_t svga_readl(uint32_t addr, void *p) egareads += 4; - cycles -= video_timing_l; - cycles_lost += video_timing_l; + cycles -= video_timing_read_l; + cycles_lost += video_timing_read_l; // pclog("Readl %05X ", addr); addr = (addr & svga->banked_mask) + svga->read_bank; - addr &= 0x7FFFFF; + addr &= svga->decode_mask; // pclog("%08X %08X\n", addr, *(uint32_t *)&vram[addr]); - if (addr >= svga->vram_limit) return 0xffffffff; + if (addr >= svga->vram_max) + return 0xffffffff; - return *(uint32_t *)&svga->vram[addr]; + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; } void svga_writew_linear(uint32_t addr, uint16_t val, void *p) @@ -1388,13 +1491,14 @@ void svga_writew_linear(uint32_t addr, uint16_t val, void *p) egawrites += 2; - cycles -= video_timing_w; - cycles_lost += video_timing_w; + cycles -= video_timing_write_w; + cycles_lost += video_timing_write_w; if (svga_output) pclog("Write LFBw %08X %04X\n", addr, val); - addr &= 0x7FFFFF; - if (addr >= svga->vram_limit) + addr &= svga->decode_mask; + if (addr >= svga->vram_max) return; + addr &= svga->vram_mask; svga->changedvram[addr >> 12] = changeframecount; *(uint16_t *)&svga->vram[addr] = val; } @@ -1414,13 +1518,14 @@ void svga_writel_linear(uint32_t addr, uint32_t val, void *p) egawrites += 4; - cycles -= video_timing_l; - cycles_lost += video_timing_l; + cycles -= video_timing_write_l; + cycles_lost += video_timing_write_l; if (svga_output) pclog("Write LFBl %08X %08X\n", addr, val); - addr &= 0x7fffff; - if (addr >= svga->vram_limit) + addr &= svga->decode_mask; + if (addr >= svga->vram_max) return; + addr &= svga->vram_mask; svga->changedvram[addr >> 12] = changeframecount; *(uint32_t *)&svga->vram[addr] = val; } @@ -1434,13 +1539,14 @@ uint16_t svga_readw_linear(uint32_t addr, void *p) egareads += 2; - cycles -= video_timing_w; - cycles_lost += video_timing_w; + cycles -= video_timing_read_w; + cycles_lost += video_timing_read_w; - addr &= 0x7FFFFF; - if (addr >= svga->vram_limit) return 0xffff; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; - return *(uint16_t *)&svga->vram[addr]; + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; } uint32_t svga_readl_linear(uint32_t addr, void *p) @@ -1452,13 +1558,14 @@ uint32_t svga_readl_linear(uint32_t addr, void *p) egareads += 4; - cycles -= video_timing_l; - cycles_lost += video_timing_l; + cycles -= video_timing_read_l; + cycles_lost += video_timing_read_l; - addr &= 0x7FFFFF; - if (addr >= svga->vram_limit) return 0xffffffff; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffffffff; - return *(uint32_t *)&svga->vram[addr]; + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; } diff --git a/src/vid_svga.h b/src/vid_svga.h index 9dbacd7..f8fb48b 100644 --- a/src/vid_svga.h +++ b/src/vid_svga.h @@ -4,7 +4,7 @@ typedef struct svga_t uint8_t crtcreg; uint8_t crtc[128]; - uint8_t gdcreg[16]; + uint8_t gdcreg[64]; int gdcaddr; uint8_t attrregs[32]; int attraddr, attrff; @@ -15,7 +15,18 @@ typedef struct svga_t uint8_t miscout; int vidclock; - uint32_t vram_limit; + /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : + 0MB-1MB - VRAM + 1MB-2MB - VRAM mirror + 2MB-4MB - open bus + 4MB-xMB - mirror of above + + For the example memory map, decode_mask would be 4MB-1 (4MB address space), vram_max would be 2MB + (present video memory only responds to first 2MB), vram_mask would be 1MB-1 (video memory wraps at 1MB) + */ + uint32_t decode_mask; + uint32_t vram_max; + uint32_t vram_mask; uint8_t la, lb, lc, ld; @@ -35,9 +46,11 @@ typedef struct svga_t int chain4, chain2_write, chain2_read; uint8_t writemask; uint32_t charseta, charsetb; + + int set_reset_disabled; uint8_t egapal[16]; - uint32_t pallook[256]; + uint32_t pallook[512]; PALETTE vgapal; int ramdac_type; @@ -47,11 +60,11 @@ typedef struct svga_t int lowres, interlace; int linedbl, rowcount; double clock; - uint32_t ma_latch; + uint32_t ma_latch, ca_adj; int bpp; - int dispontime, dispofftime; - int vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; uint8_t scrblank; @@ -64,6 +77,7 @@ typedef struct svga_t int linepos, vslines, linecountff, oddeven; int con, cursoron, blink; int scrollcache; + int char_width; int firstline, lastline; int firstline_draw, lastline_draw; @@ -71,7 +85,7 @@ typedef struct svga_t uint8_t *vram; uint8_t *changedvram; - int vrammask; + uint32_t vram_display_mask; uint32_t banked_mask; uint32_t write_bank, read_bank; @@ -79,6 +93,8 @@ typedef struct svga_t int fullchange; int video_res_x, video_res_y, video_bpp; + int video_res_override; /*If clear then SVGA code will set above variables, if + set then card code will*/ int frames, fps; struct @@ -110,10 +126,38 @@ typedef struct svga_t void (*vblank_start)(struct svga_t *svga); + /*Called when VC=R18 and friends. If this returns zero then MA resetting + is skipped. Matrox Mystique in Power mode reuses this counter for + vertical line interrupt*/ + int (*line_compare)(struct svga_t *svga); + + /*Called at the start of vertical sync*/ + void (*vsync_callback)(struct svga_t *svga); + /*If set then another device is driving the monitor output and the SVGA card should not attempt to display anything */ int override; void *p; + + uint8_t ksc5601_sbyte_mask; + uint8_t ksc5601_udc_area_msb[2]; + int ksc5601_swap_mode; + uint16_t ksc5601_english_font_type; + + int vertical_linedbl; + + /*Used to implement CRTC[0x17] bit 2 hsync divisor*/ + int hsync_divisor; + + /*Tseng-style chain4 mode - CRTC dword mode is the same as byte mode, chain4 + addresses are shifted to match*/ + int packed_chain4; + + /*Force CRTC to dword mode, regardless of CR14/CR17. Required for S3 enhanced mode*/ + int force_dword_mode; + + int remap_required; + uint32_t (*remap_func)(struct svga_t *svga, uint32_t in_addr); } svga_t; extern int svga_init(svga_t *svga, void *p, int memsize, diff --git a/src/vid_svga_render.c b/src/vid_svga_render.c index 173fe6c..f07892b 100644 --- a/src/vid_svga_render.c +++ b/src/vid_svga_render.c @@ -3,6 +3,14 @@ #include "video.h" #include "vid_svga.h" #include "vid_svga_render.h" +#include "vid_svga_render_remap.h" + +void svga_render_null(svga_t *svga) +{ + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; +} void svga_render_blank(svga_t *svga) { @@ -40,7 +48,8 @@ void svga_render_text_40(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[32]; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; int x, xx; int drawcursor; uint8_t chr, attr, dat; @@ -50,9 +59,12 @@ void svga_render_text_40(svga_t *svga) for (x = 0; x < svga->hdisp; x += xinc) { + uint32_t addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); - chr = svga->vram[(svga->ma << 1) & svga->vrammask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vrammask]; + chr = svga->vram[addr]; + attr = svga->vram[addr+1]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); else charaddr = svga->charseta + (chr * 128); @@ -91,7 +103,7 @@ void svga_render_text_40(svga_t *svga) svga->ma += 4; p += xinc; } - svga->ma &= svga->vrammask; + svga->ma &= svga->vram_display_mask; } } @@ -103,7 +115,8 @@ void svga_render_text_80(svga_t *svga) if (svga->fullchange) { - uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[32]; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; int x, xx; int drawcursor; uint8_t chr, attr, dat; @@ -113,9 +126,12 @@ void svga_render_text_80(svga_t *svga) for (x = 0; x < svga->hdisp; x += xinc) { + uint32_t addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); - chr = svga->vram[(svga->ma << 1) & svga->vrammask]; - attr = svga->vram[((svga->ma << 1) + 1) & svga->vrammask]; + chr = svga->vram[addr]; + attr = svga->vram[addr+1]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); else charaddr = svga->charseta + (chr * 128); @@ -154,20 +170,152 @@ void svga_render_text_80(svga_t *svga) svga->ma += 4; p += xinc; } - svga->ma &= svga->vrammask; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_text_80_ksc5601(svga_t *svga) +{ + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) + { + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; + int x, xx; + int drawcursor; + uint8_t chr, attr, dat, nextchr; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 8 : 9; + + for (x = 0; x < svga->hdisp; x += xinc) + { + uint32_t addr = svga->remap_func(svga, svga->ma) & svga->vram_display_mask; + + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + chr = svga->vram[addr]; + nextchr = svga->vram[addr + 8]; + attr = svga->vram[addr + 1]; + + 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; + } + } + + if(x + xinc < svga->hdisp && (chr & (nextchr | svga->ksc5601_sbyte_mask) & 0x80)) + { + if((chr == svga->ksc5601_udc_area_msb[0] || chr == svga->ksc5601_udc_area_msb[1]) && (nextchr > 0xa0 && nextchr < 0xff)) + dat = fontdatksc5601_user[(chr == svga->ksc5601_udc_area_msb[1] ? 96 : 0) + (nextchr & 0x7F) - 0x20][svga->sc]; + else if(nextchr & 0x80) + { + if(svga->ksc5601_swap_mode == 1 && (nextchr > 0xa0 && nextchr < 0xff)) + { + if(chr >= 0x80 && chr < 0x99) chr += 0x30; + else if(chr >= 0xB0 && chr < 0xC9) chr -= 0x30; + } + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc]; + } + else + dat = 0xFF; + } + else + { + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + if ((svga->ksc5601_english_font_type >> 8) == 1) dat = fontdatksc5601[((svga->ksc5601_english_font_type & 0x7F) << 7) | (chr >> 1)][((chr & 1) << 4) | svga->sc]; + else 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; + + if(x + xinc < svga->hdisp && (chr & (nextchr | svga->ksc5601_sbyte_mask) & 0x80)) + { + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + 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; + } + } + + if((chr == svga->ksc5601_udc_area_msb[0] || chr == svga->ksc5601_udc_area_msb[1]) && (nextchr > 0xa0 && nextchr < 0xff)) + dat = fontdatksc5601_user[(chr == svga->ksc5601_udc_area_msb[1] ? 96 : 0) + (nextchr & 0x7F) - 0x20][svga->sc + 16]; + else if(nextchr & 0x80) + { + dat = fontdatksc5601[((chr & 0x7F) << 7) | (nextchr & 0x7F)][svga->sc + 16]; + } + else + dat = 0xFF; + 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; + x += xinc; + } + } + svga->ma &= svga->vram_display_mask; } } void svga_render_2bpp_lowres(svga_t *svga) { - int changed_offset; - - if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) - changed_offset = (svga->ma << 1) >> 12; - else - changed_offset = ((svga->ma << 1) + 0x8000) >> 12; + uint32_t changed_addr = svga->remap_func(svga, svga->ma); - if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = ((8 - svga->scrollcache) << 1) + 16; @@ -179,20 +327,13 @@ void svga_render_2bpp_lowres(svga_t *svga) for (x = 0; x <= svga->hdisp; x += 16) { + uint32_t addr = svga->remap_func(svga, svga->ma); 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]; - } + dat[0] = svga->vram[addr]; + dat[1] = svga->vram[addr + 1]; svga->ma += 4; - svga->ma &= svga->vrammask; + svga->ma &= svga->vram_display_mask; p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; @@ -210,14 +351,9 @@ void svga_render_2bpp_lowres(svga_t *svga) void svga_render_2bpp_highres(svga_t *svga) { - int changed_offset; - - 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) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - svga->scrollcache) + 24; @@ -229,38 +365,31 @@ void svga_render_2bpp_highres(svga_t *svga) for (x = 0; x <= svga->hdisp; x += 8) { + uint32_t addr = svga->remap_func(svga, svga->ma); 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]; - } + dat[0] = svga->vram[addr]; + dat[1] = svga->vram[addr + 1]; svga->ma += 4; - svga->ma &= svga->vrammask; + svga->ma &= svga->vram_display_mask; - 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; + *p++ = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + *p++ = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + *p++ = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + *p++ = svga->pallook[svga->egapal[dat[0] & 3]]; + *p++ = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + *p++ = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + *p++ = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + *p++ = svga->pallook[svga->egapal[dat[1] & 3]]; } } } void svga_render_4bpp_lowres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = ((8 - svga->scrollcache) << 1) + 16; @@ -274,10 +403,11 @@ void svga_render_4bpp_lowres(svga_t *svga) { uint8_t edat[4]; uint8_t dat; + uint32_t addr = svga->remap_func(svga, svga->ma); - *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); svga->ma += 4; - svga->ma &= svga->vrammask; + svga->ma &= svga->vram_display_mask; 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]]; @@ -299,14 +429,9 @@ void svga_render_4bpp_lowres(svga_t *svga) void svga_render_4bpp_highres(svga_t *svga) { - int changed_offset; - - 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) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - svga->scrollcache) + 24; @@ -320,35 +445,33 @@ void svga_render_4bpp_highres(svga_t *svga) { uint8_t edat[4]; uint8_t dat; + uint32_t addr = svga->remap_func(svga, svga->ma); - 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]); + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[addr]); svga->ma += 4; - svga->ma &= svga->vrammask; + svga->ma &= svga->vram_display_mask; 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]]; + *p++ = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + *p++ = 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]]; + *p++ = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + *p++ = 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]]; + *p++ = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + *p++ = 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; + *p++ = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + *p++ = svga->pallook[svga->egapal[dat & svga->plane_mask]]; } } } void svga_render_8bpp_lowres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; @@ -358,59 +481,99 @@ void svga_render_8bpp_lowres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 8) + if (!svga->remap_required) { - 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; + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + + 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; + else + { + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + 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->vram_display_mask; } } void svga_render_8bpp_highres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; - if (svga->firstline_draw == 2000) + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 8) + if (!svga->remap_required) { - 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]; + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + *p++ = svga->pallook[dat & 0xff]; + *p++ = svga->pallook[(dat >> 8) & 0xff]; + *p++ = svga->pallook[(dat >> 16) & 0xff]; + *p++ = 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; + dat = *(uint32_t *)(&svga->vram[(svga->ma+4) & svga->vram_display_mask]); + *p++ = svga->pallook[dat & 0xff]; + *p++ = svga->pallook[(dat >> 8) & 0xff]; + *p++ = svga->pallook[(dat >> 16) & 0xff]; + *p++ = svga->pallook[(dat >> 24) & 0xff]; + + svga->ma += 8; + } } - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + svga->ma += 4; + + *p++ = svga->pallook[dat & 0xff]; + *p++ = svga->pallook[(dat >> 8) & 0xff]; + *p++ = svga->pallook[(dat >> 16) & 0xff]; + *p++ = svga->pallook[(dat >> 24) & 0xff]; + } + } + + svga->ma &= svga->vram_display_mask; } } void svga_render_15bpp_lowres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; @@ -420,26 +583,44 @@ void svga_render_15bpp_lowres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 4) + if (!svga->remap_required) { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - p[x] = video_15to32[dat & 0xffff]; - p[x + 1] = video_15to32[dat >> 16]; + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + } + svga->ma += x << 1; } - svga->ma += x << 1; - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x += 2) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + + svga->ma += 4; + } + } + svga->ma &= svga->vram_display_mask; } } void svga_render_15bpp_highres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; @@ -449,32 +630,51 @@ void svga_render_15bpp_highres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 8) + if (!svga->remap_required) { - 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]; + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + *p++ = video_15to32[dat & 0xffff]; + *p++ = 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) + 4) & svga->vram_display_mask]); + *p++ = video_15to32[dat & 0xffff]; + *p++ = 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) + 8) & svga->vram_display_mask]); + *p++ = video_15to32[dat & 0xffff]; + *p++ = 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]; + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + } + + svga->ma += x << 1; } - svga->ma += x << 1; - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x += 2) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = video_15to32[dat & 0xffff]; + *p++ = video_15to32[dat >> 16]; + + svga->ma += 4; + } + } + svga->ma &= svga->vram_display_mask; } } void svga_render_16bpp_lowres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - (svga->scrollcache & 6)) + 24; @@ -484,26 +684,45 @@ void svga_render_16bpp_lowres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 4) + if (!svga->remap_required) { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; - dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); - p[x] = video_16to32[dat & 0xffff]; - p[x + 1] = video_16to32[dat >> 16]; + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + } + svga->ma += x << 1; } - svga->ma += x << 1; - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x += 2) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + + svga->ma += 4; + } + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; } } void svga_render_16bpp_highres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; @@ -513,55 +732,106 @@ void svga_render_16bpp_highres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 8) + if (!svga->remap_required) { - 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]; + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + *p++ = video_16to32[dat & 0xffff]; + *p++ = 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) + 4) & svga->vram_display_mask]); + *p++ = video_16to32[dat & 0xffff]; + *p++ = 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]; + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + } + + svga->ma += x << 1; } - svga->ma += x << 1; - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x += 2) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = video_16to32[dat & 0xffff]; + *p++ = video_16to32[dat >> 16]; + + svga->ma += 4; + } + } + svga->ma &= svga->vram_display_mask; } } void svga_render_24bpp_lowres(svga_t *svga) { - int x, offset; - uint32_t fg; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; + 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++) + if (!svga->remap_required) { - 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])[(x << 1) + offset] = ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + 1 + offset] = fg; + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat0 = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + uint32_t dat1 = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + uint32_t dat2 = *(uint32_t *)(&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + + p[0] = p[1] = dat0 & 0xffffff; + p[2] = p[3] = (dat0 >> 24) | ((dat1 & 0xffff) << 8); + p[4] = p[5] = (dat1 >> 16) | ((dat2 & 0xff) << 16); + p[6] = p[7] = dat2 >> 8; + + svga->ma += 12; + } + } + else + { + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat0, dat1, dat2; + uint32_t addr; + + addr = svga->remap_func(svga, svga->ma); + dat0 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + addr = svga->remap_func(svga, svga->ma + 4); + dat1 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + addr = svga->remap_func(svga, svga->ma + 8); + dat2 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + p[0] = p[1] = dat0 & 0xffffff; + p[2] = p[3] = (dat0 >> 24) | ((dat1 & 0xffff) << 8); + p[4] = p[5] = (dat1 >> 16) | ((dat2 & 0xff) << 16); + p[6] = p[7] = dat2 >> 8; + + svga->ma += 12; + } } } } void svga_render_24bpp_highres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; @@ -571,46 +841,84 @@ void svga_render_24bpp_highres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x += 4) + if (!svga->remap_required) { - 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; + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat0 = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + uint32_t dat1 = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + uint32_t dat2 = *(uint32_t *)(&svga->vram[(svga->ma + 8) & svga->vram_display_mask]); + + *p++ = dat0 & 0xffffff; + *p++ = (dat0 >> 24) | ((dat1 & 0xffff) << 8); + *p++ = (dat1 >> 16) | ((dat2 & 0xff) << 16); + *p++ = dat2 >> 8; + + svga->ma += 12; + } } - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat0, dat1, dat2; + uint32_t addr; + + addr = svga->remap_func(svga, svga->ma); + dat0 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + addr = svga->remap_func(svga, svga->ma + 4); + dat1 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + addr = svga->remap_func(svga, svga->ma + 8); + dat2 = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + + *p++ = dat0 & 0xffffff; + *p++ = (dat0 >> 24) | ((dat1 & 0xffff) << 8); + *p++ = (dat1 >> 16) | ((dat2 & 0xff) << 16); + *p++ = dat2 >> 8; + + svga->ma += 12; + } + } + svga->ma &= svga->vram_display_mask; } } void svga_render_32bpp_lowres(svga_t *svga) { - int x, offset; - uint32_t fg; - - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; + 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++) + if (!svga->remap_required) { - 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])[(x << 1) + offset] = ((uint32_t *)buffer32->line[svga->displine])[(x << 1) + 1 + offset] = fg; + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + *p++ = dat & 0xffffff; + *p++ = dat & 0xffffff; + } + svga->ma += x*4; } + else + { + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr]); + *p++ = dat & 0xffffff; + *p++ = dat & 0xffffff; + svga->ma += 4; + } + } + svga->ma &= svga->vram_display_mask; } } @@ -618,7 +926,9 @@ void svga_render_32bpp_lowres(svga_t *svga) 91%*/ void svga_render_32bpp_highres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; @@ -628,56 +938,102 @@ void svga_render_32bpp_highres(svga_t *svga) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x++) + if (!svga->remap_required) { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); - p[x] = dat & 0xffffff; + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + *p++ = dat & 0xffffff; + } + svga->ma += x*4; } - svga->ma += 4; - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + *p++ = dat & 0xffffff; + svga->ma += 4; + } + } + + svga->ma &= svga->vram_display_mask; } } void svga_render_ABGR8888_highres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; - - if (svga->firstline_draw == 2000) + + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x++) + if (!svga->remap_required) { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); - p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + *p++ = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + } + svga->ma += x*4; } - svga->ma += 4; - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + *p++ = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + svga->ma += 4; + } + } + + svga->ma &= svga->vram_display_mask; } } void svga_render_RGBA8888_highres(svga_t *svga) { - if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + uint32_t changed_addr = svga->remap_func(svga, svga->ma); + + if (svga->changedvram[changed_addr >> 12] || svga->changedvram[(changed_addr >> 12) + 1] || svga->fullchange) { int x; int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; - - if (svga->firstline_draw == 2000) + + if (svga->firstline_draw == 2000) svga->firstline_draw = svga->displine; svga->lastline_draw = svga->displine; - for (x = 0; x <= svga->hdisp; x++) + if (!svga->remap_required) { - uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); - p[x] = dat >> 8; + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + *p++ = dat >> 8; + } + svga->ma += x*4; } - svga->ma += 4; - svga->ma &= svga->vrammask; + else + { + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t addr = svga->remap_func(svga, svga->ma); + uint32_t dat = *(uint32_t *)(&svga->vram[addr & svga->vram_display_mask]); + *p++ = dat >> 8; + svga->ma += 4; + } + } + + svga->ma &= svga->vram_display_mask; } } diff --git a/src/vid_svga_render.h b/src/vid_svga_render.h index a0115ad..bb3b3c1 100644 --- a/src/vid_svga_render.h +++ b/src/vid_svga_render.h @@ -9,9 +9,13 @@ extern int scrollcache; extern uint8_t edatlookup[4][4]; +void svga_recalc_remap_func(svga_t *svga); + +void svga_render_null(svga_t *svga); 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_text_80_ksc5601(svga_t *svga); void svga_render_2bpp_lowres(svga_t *svga); void svga_render_2bpp_highres(svga_t *svga); diff --git a/src/vid_svga_render_remap.h b/src/vid_svga_render_remap.h new file mode 100644 index 0000000..189f846 --- /dev/null +++ b/src/vid_svga_render_remap.h @@ -0,0 +1,129 @@ +/*Variables : + byte/word/doubleword mode + word has MA13/MA15->MA0 + ET4000 treats doubleword as byte + row 0 -> MA13 + row 1 -> MA14 +*/ + +//S3 - enhanced mode mappings CR31.3 can force doubleword mode +//Cirrus Logic handles SVGA writes seperately +//S3, CL, TGUI blitters need checking + +//CL, S3, Mach64, ET4000, Banshee, TGUI all okay +//Still to check - ViRGE, HT216 +#define VAR_BYTE_MODE (0 << 0) +#define VAR_WORD_MODE_MA13 (1 << 0) +#define VAR_WORD_MODE_MA15 (2 << 0) +#define VAR_DWORD_MODE (3 << 0) +#define VAR_MODE_MASK (3 << 0) +#define VAR_ROW0_MA13 (1 << 2) +#define VAR_ROW1_MA14 (1 << 3) + +#define ADDRESS_REMAP_FUNC(nr) \ + static uint32_t address_remap_func_ ## nr(svga_t *svga, uint32_t in_addr) \ + { \ + uint32_t out_addr; \ + \ + switch (nr & VAR_MODE_MASK) \ + { \ + case VAR_BYTE_MODE: \ + out_addr = in_addr; \ + break; \ + \ + case VAR_WORD_MODE_MA13: \ + out_addr = ((in_addr << 1) & 0x1fff8) | \ + ((in_addr >> 13) & 0x4) | \ + (in_addr & ~0x1ffff); \ + break; \ + \ + case VAR_WORD_MODE_MA15: \ + out_addr = ((in_addr << 1) & 0x1fff8) | \ + ((in_addr >> 15) & 0x4) | \ + (in_addr & ~0x1ffff); \ + break; \ + \ + case VAR_DWORD_MODE: \ + out_addr = ((in_addr << 2) & 0x3fff0) | \ + ((in_addr >> 14) & 0xc) | \ + (in_addr & ~0x3ffff); \ + break; \ + } \ + \ + if (nr & VAR_ROW0_MA13) \ + out_addr = (out_addr & ~(1 << (13+2))) | \ + ((svga->sc & 1) ? (1 << (13+2)) : 0); \ + if (nr & VAR_ROW1_MA14) \ + out_addr = (out_addr & ~(1 << (14+2))) | \ + ((svga->sc & 2) ? (1 << (14+2)) : 0); \ + \ + return out_addr; \ + } + +ADDRESS_REMAP_FUNC(0) +ADDRESS_REMAP_FUNC(1) +ADDRESS_REMAP_FUNC(2) +ADDRESS_REMAP_FUNC(3) +ADDRESS_REMAP_FUNC(4) +ADDRESS_REMAP_FUNC(5) +ADDRESS_REMAP_FUNC(6) +ADDRESS_REMAP_FUNC(7) +ADDRESS_REMAP_FUNC(8) +ADDRESS_REMAP_FUNC(9) +ADDRESS_REMAP_FUNC(10) +ADDRESS_REMAP_FUNC(11) +ADDRESS_REMAP_FUNC(12) +ADDRESS_REMAP_FUNC(13) +ADDRESS_REMAP_FUNC(14) +ADDRESS_REMAP_FUNC(15) + +static uint32_t (*address_remap_funcs[16])(svga_t *svga, uint32_t in_addr) = +{ + address_remap_func_0, + address_remap_func_1, + address_remap_func_2, + address_remap_func_3, + address_remap_func_4, + address_remap_func_5, + address_remap_func_6, + address_remap_func_7, + address_remap_func_8, + address_remap_func_9, + address_remap_func_10, + address_remap_func_11, + address_remap_func_12, + address_remap_func_13, + address_remap_func_14, + address_remap_func_15 +}; + +void svga_recalc_remap_func(svga_t *svga) +{ + int func_nr; + + if (svga->fb_only) + func_nr = 0; + else + { + if (svga->force_dword_mode) + func_nr = VAR_DWORD_MODE; + else if (svga->crtc[0x14] & (1 << 6)) + func_nr = svga->packed_chain4 ? VAR_BYTE_MODE : VAR_DWORD_MODE; + else if (svga->crtc[0x17] & (1 << 6)) + func_nr = VAR_BYTE_MODE; + else if (svga->crtc[0x17] & (1 << 5)) + func_nr = VAR_WORD_MODE_MA15; + else + func_nr = VAR_WORD_MODE_MA13; + + if (!(svga->crtc[0x17] & (1 << 0))) + func_nr |= VAR_ROW0_MA13; + if (!(svga->crtc[0x17] & (1 << 1))) + func_nr |= VAR_ROW1_MA14; + } + +// pclog("svga_recalc_remap_func: fb_only=%i chain4=%i packed_chain4=%i crtc[14]=%02x crtc[17]=%02x func_nr=%i\n", +// svga->fb_only, svga->chain4, svga->packed_chain4, svga->crtc[0x14], svga->crtc[0x17], func_nr); + svga->remap_required = (func_nr != 0); + svga->remap_func = address_remap_funcs[func_nr]; +} diff --git a/src/vid_t1000.c b/src/vid_t1000.c new file mode 100644 index 0000000..b97e092 --- /dev/null +++ b/src/vid_t1000.c @@ -0,0 +1,713 @@ +/* Emulate the Toshiba 1000 plasma display. This display has a fixed 640x200 + * resolution. */ +#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_t1000.h" + +#define T1000_XSIZE 640 +#define T1000_YSIZE 200 + +/*Very rough estimate*/ +#define VID_CLOCK (double)(651 * 216 * 60) + +/* Mapping of attributes to colours */ +static uint32_t blue, grey; +static uint8_t boldcols[256]; /* Which attributes use the bold font */ +static uint32_t blinkcols[256][2]; +static uint32_t normcols[256][2]; +static uint8_t language; + +/* Video options set by the motherboard; they will be picked up by the card + * on the next poll. + * + * Bit 1: Danish + * Bit 0: Thin font + */ +static uint8_t st_video_options; +static uint8_t st_enabled = 1; +static uint8_t st_display_internal = -1; + +void t1000_video_options_set(uint8_t options) +{ + st_video_options = options & 1; + st_video_options |= language; +} + +void t1000_video_enable(uint8_t enabled) +{ + st_enabled = enabled; +} + +void t1000_display_set(uint8_t internal) +{ + st_display_internal = internal; +} + +uint8_t t1000_display_get() +{ + return st_display_internal; +} + + +typedef struct t1000_t +{ + mem_mapping_t mapping; + + cga_t cga; /* The CGA is used for the external + * display; most of its registers are + * ignored by the plasma display. */ + + int font; /* Current font, 0-3 */ + int enabled; /* Hardware enabled, 0 or 1 */ + int internal; /* Using internal display? */ + uint8_t attrmap; /* Attribute mapping register */ + + uint64_t dispontime, dispofftime; + + int linepos, displine; + int vc; + int dispon; + int vsynctime; + uint8_t video_options; + + uint8_t *vram; +} t1000_t; + + +static void t1000_recalctimings(t1000_t *t1000); +static void t1000_write(uint32_t addr, uint8_t val, void *p); +static uint8_t t1000_read(uint32_t addr, void *p); +static void t1000_recalcattrs(t1000_t *t1000); + + +static void t1000_out(uint16_t addr, uint8_t val, void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + switch (addr) + { + /* Emulated CRTC, register select */ + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + cga_out(addr, val, &t1000->cga); + break; + + /* Emulated CRTC, value */ + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + /* Register 0x12 controls the attribute mappings for the + * LCD screen. */ + if (t1000->cga.crtcreg == 0x12) + { + t1000->attrmap = val; + t1000_recalcattrs(t1000); + return; + } + cga_out(addr, val, &t1000->cga); + + t1000_recalctimings(t1000); + return; + + /* CGA control register */ + case 0x3D8: + cga_out(addr, val, &t1000->cga); + return; + /* CGA colour register */ + case 0x3D9: + cga_out(addr, val, &t1000->cga); + return; + } +} + +static uint8_t t1000_in(uint16_t addr, void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + uint8_t val; + + switch (addr) + { + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + if (t1000->cga.crtcreg == 0x12) + { + val = t1000->attrmap & 0x0F; + if (t1000->internal) val |= 0x20; /* LCD / CRT */ + return val; + } + } + + return cga_in(addr, &t1000->cga); +} + + + + +static void t1000_write(uint32_t addr, uint8_t val, void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + egawrites++; + +// pclog("CGA_WRITE %04X %02X\n", addr, val); + t1000->vram[addr & 0x3fff] = val; + cycles -= 4; +} + +static uint8_t t1000_read(uint32_t addr, void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + egareads++; + cycles -= 4; + +// pclog("CGA_READ %04X\n", addr); + return t1000->vram[addr & 0x3fff]; +} + + + +static void t1000_recalctimings(t1000_t *t1000) +{ + double disptime; + double _dispontime, _dispofftime; + + if (!t1000->internal) + { + cga_recalctimings(&t1000->cga); + return; + } + disptime = 651; + _dispontime = 640; + _dispofftime = disptime - _dispontime; + t1000->dispontime = (uint64_t)(_dispontime * (cpuclock / VID_CLOCK) * (double)(1ull << 32)); + t1000->dispofftime = (uint64_t)(_dispofftime * (cpuclock / VID_CLOCK) * (double)(1ull << 32)); +} + +/* Draw a row of text in 80-column mode */ +static void t1000_text_row80(t1000_t *t1000) +{ + uint32_t cols[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + int bold; + int blink; + uint16_t addr; + uint8_t sc; + uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; + uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff; + + sc = (t1000->displine) & 7; + addr = ((ma & ~1) + (t1000->displine >> 3) * 80) * 2; + ma += (t1000->displine >> 3) * 80; + + if ((t1000->cga.crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) && + ((t1000->cga.crtc[11] & 0x0F) >= sc); + } + for (x = 0; x < 80; x++) + { + chr = t1000->vram[(addr + 2 * x) & 0x3FFF]; + attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && + (t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16)); + + blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (t1000->video_options & 1) + bold = boldcols[attr] ? chr : chr + 256; + else + bold = boldcols[attr] ? chr + 256 : chr; + if (t1000->video_options & 2) + bold += 512; + + if (t1000->cga.cgamode & 0x20) /* Blink */ + { + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; + } + else + { + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); + } + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[t1000->displine])[(x << 3) + c] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + ++ma; + } +} + +/* Draw a row of text in 40-column mode */ +static void t1000_text_row40(t1000_t *t1000) +{ + uint32_t cols[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + int bold; + int blink; + uint16_t addr; + uint8_t sc; + uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; + uint16_t ca = (t1000->cga.crtc[15] | (t1000->cga.crtc[14] << 8)) & 0x3fff; + + sc = (t1000->displine) & 7; + addr = ((ma & ~1) + (t1000->displine >> 3) * 40) * 2; + ma += (t1000->displine >> 3) * 40; + + if ((t1000->cga.crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((t1000->cga.crtc[10] & 0x0F) <= sc) && + ((t1000->cga.crtc[11] & 0x0F) >= sc); + } + for (x = 0; x < 40; x++) + { + chr = t1000->vram[(addr + 2 * x) & 0x3FFF]; + attr = t1000->vram[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && + (t1000->cga.cgamode & 8) && (t1000->cga.cgablink & 16)); + + blink = ((t1000->cga.cgablink & 16) && (t1000->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (t1000->video_options & 1) + bold = boldcols[attr] ? chr : chr + 256; + else + bold = boldcols[attr] ? chr + 256 : chr; + if (t1000->video_options & 2) + bold += 512; + + if (t1000->cga.cgamode & 0x20) /* Blink */ + { + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; + } + else + { + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2 + 1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (blue ^ grey); + } + } + else + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t1000->displine])[(x << 4) + c*2+1] = cols[(fontdat[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + ++ma; + } +} + +/* Draw a line in CGA 640x200 mode */ +static void t1000_cgaline6(t1000_t *t1000) +{ + int x, c; + uint8_t dat; + uint32_t ink = 0; + uint16_t addr; + uint32_t fg = (t1000->cga.cgacol & 0x0F) ? blue : grey; + uint32_t bg = grey; + + uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; + + addr = ((t1000->displine) & 1) * 0x2000 + + (t1000->displine >> 1) * 80 + + ((ma & ~1) << 1); + + for (x = 0; x < 80; x++) + { + dat = t1000->vram[addr & 0x3FFF]; + addr++; + + for (c = 0; c < 8; c++) + { + ink = (dat & 0x80) ? fg : bg; + if (!(t1000->cga.cgamode & 8)) + ink = grey; + ((uint32_t *)buffer32->line[t1000->displine])[x*8+c] = ink; + dat = dat << 1; + } + } +} + +/* Draw a line in CGA 320x200 mode. Here the CGA colours are converted to + * dither patterns: colour 1 to 25% grey, colour 2 to 50% grey */ +static void t1000_cgaline4(t1000_t *t1000) +{ + int x, c; + uint8_t dat, pattern; + uint32_t ink0, ink1; + uint16_t addr; + + uint16_t ma = (t1000->cga.crtc[13] | (t1000->cga.crtc[12] << 8)) & 0x3fff; + addr = ((t1000->displine) & 1) * 0x2000 + + (t1000->displine >> 1) * 80 + + ((ma & ~1) << 1); + + for (x = 0; x < 80; x++) + { + dat = t1000->vram[addr & 0x3FFF]; + addr++; + + for (c = 0; c < 4; c++) + { + pattern = (dat & 0xC0) >> 6; + if (!(t1000->cga.cgamode & 8)) pattern = 0; + + switch (pattern & 3) + { + case 0: ink0 = ink1 = grey; break; + case 1: if (t1000->displine & 1) + { + ink0 = grey; ink1 = grey; + } + else + { + ink0 = blue; ink1 = grey; + } + break; + case 2: if (t1000->displine & 1) + { + ink0 = grey; ink1 = blue; + } + else + { + ink0 = blue; ink1 = grey; + } + break; + case 3: ink0 = ink1 = blue; break; + + } + ((uint32_t *)buffer32->line[t1000->displine])[x*8+2*c] = ink0; + ((uint32_t *)buffer32->line[t1000->displine])[x*8+2*c+1] = ink1; + dat = dat << 2; + } + } +} + +static void t1000_poll(void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + + if (t1000->video_options != st_video_options || + t1000->enabled != st_enabled) + { + t1000->video_options = st_video_options; + t1000->enabled = st_enabled; + + /* Set the font used for the external display */ + t1000->cga.fontbase = ((t1000->video_options & 3) * 256); + + if (t1000->enabled) /* Disable internal chipset */ + mem_mapping_enable(&t1000->mapping); + else mem_mapping_disable(&t1000->mapping); + } + /* Switch between internal plasma and external CRT display. */ + if (st_display_internal != -1 && st_display_internal != t1000->internal) + { + t1000->internal = st_display_internal; + t1000_recalctimings(t1000); + } + if (!t1000->internal) + { + cga_poll(&t1000->cga); + return; + } + + if (!t1000->linepos) + { + timer_advance_u64(&t1000->cga.timer, t1000->dispofftime); + t1000->cga.cgastat |= 1; + t1000->linepos = 1; + if (t1000->dispon) + { + if (t1000->displine == 0) + { + video_wait_for_buffer(); + } + + /* Graphics */ + if (t1000->cga.cgamode & 0x02) + { + if (t1000->cga.cgamode & 0x10) + t1000_cgaline6(t1000); + else t1000_cgaline4(t1000); + } + else + if (t1000->cga.cgamode & 0x01) /* High-res text */ + { + t1000_text_row80(t1000); + } + else + { + t1000_text_row40(t1000); + } + } + t1000->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (t1000->displine == 200) /* Start of VSYNC */ + { + t1000->cga.cgastat |= 8; + t1000->dispon = 0; + } + if (t1000->displine == 216) /* End of VSYNC */ + { + t1000->displine = 0; + t1000->cga.cgastat &= ~8; + t1000->dispon = 1; + } + } + else + { + if (t1000->dispon) + { + t1000->cga.cgastat &= ~1; + } + timer_advance_u64(&t1000->cga.timer, t1000->dispontime); + t1000->linepos = 0; + + if (t1000->displine == 200) + { + /* Hardcode 640x200 window size */ + if (T1000_XSIZE != xsize || T1000_YSIZE != ysize) + { + xsize = T1000_XSIZE; + ysize = T1000_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 640x200 resolution */ + video_res_x = T1000_XSIZE; + video_res_y = T1000_YSIZE; + + if (t1000->cga.cgamode & 0x02) + { + if (t1000->cga.cgamode & 0x10) + video_bpp = 1; + else video_bpp = 2; + + } + else video_bpp = 0; + t1000->cga.cgablink++; + } + } +} + +static void t1000_recalcattrs(t1000_t *t1000) +{ + int n; + + /* val behaves as follows: + * Bit 0: Attributes 01-06, 08-0E are inverse video + * Bit 1: Attributes 01-06, 08-0E are bold + * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF + * are inverse video + * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF + * are bold */ + + /* Set up colours */ + blue = makecol(0x2D, 0x39, 0x5A); + grey = makecol(0x85, 0xa0, 0xD6); + + /* Initialise the attribute mapping. Start by defaulting everything + * to grey on blue, and with bold set by bit 3 */ + for (n = 0; n < 256; n++) + { + boldcols[n] = (n & 8) != 0; + blinkcols[n][0] = normcols[n][0] = blue; + blinkcols[n][1] = normcols[n][1] = grey; + } + + /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the + * passed value. Exclude x0 and x8, which are always grey on + * blue. */ + for (n = 0x11; n <= 0xFF; n++) + { + if ((n & 7) == 0) continue; + if (t1000->attrmap & 4) /* Inverse */ + { + blinkcols[n][0] = normcols[n][0] = blue; + blinkcols[n][1] = normcols[n][1] = grey; + } + else /* Normal */ + { + blinkcols[n][0] = normcols[n][0] = grey; + blinkcols[n][1] = normcols[n][1] = blue; + } + if (t1000->attrmap & 8) boldcols[n] = 1; /* Bold */ + } + /* Set up the 01-0E range, controlled by bits 0 and 1 of the + * passed value. When blinking is enabled this also affects 81-8E. */ + for (n = 0x01; n <= 0x0E; n++) + { + if (n == 7) continue; + if (t1000->attrmap & 1) + { + blinkcols[n][0] = normcols[n][0] = blue; + blinkcols[n][1] = normcols[n][1] = grey; + blinkcols[n+128][0] = blue; + blinkcols[n+128][1] = grey; + } + else + { + blinkcols[n][0] = normcols[n][0] = grey; + blinkcols[n][1] = normcols[n][1] = blue; + blinkcols[n+128][0] = grey; + blinkcols[n+128][1] = blue; + } + if (t1000->attrmap & 2) boldcols[n] = 1; + } + /* Colours 07 and 0F are always blue on grey. If blinking is + * enabled so are 87 and 8F. */ + for (n = 0x07; n <= 0x0F; n += 8) + { + blinkcols[n][0] = normcols[n][0] = grey; + blinkcols[n][1] = normcols[n][1] = blue; + blinkcols[n+128][0] = grey; + blinkcols[n+128][1] = blue; + } + /* When not blinking, colours 81-8F are always blue on grey. */ + for (n = 0x81; n <= 0x8F; n ++) + { + normcols[n][0] = grey; + normcols[n][1] = blue; + boldcols[n] = (n & 0x08) != 0; + } + + + /* Finally do the ones which are solid grey. These differ between + * the normal and blinking mappings */ + for (n = 0; n <= 0xFF; n += 0x11) + { + normcols[n][0] = normcols[n][1] = grey; + } + /* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are grey */ + for (n = 0; n <= 0x77; n += 0x11) + { + blinkcols[n][0] = blinkcols[n][1] = grey; + blinkcols[n+128][0] = blinkcols[n+128][1] = grey; + } +} + + +static void *t1000_init() +{ + t1000_t *t1000 = malloc(sizeof(t1000_t)); + memset(t1000, 0, sizeof(t1000_t)); + cga_init(&t1000->cga); + + t1000->internal = 1; + + /* 16k video RAM */ + t1000->vram = malloc(0x4000); + + timer_set_callback(&t1000->cga.timer, t1000_poll); + timer_set_p(&t1000->cga.timer, t1000); + + /* Occupy memory between 0xB8000 and 0xBFFFF */ + mem_mapping_add(&t1000->mapping, 0xb8000, 0x8000, t1000_read, NULL, NULL, t1000_write, NULL, NULL, NULL, 0, t1000); + /* Respond to CGA I/O ports */ + io_sethandler(0x03d0, 0x000c, t1000_in, NULL, NULL, t1000_out, NULL, NULL, t1000); + + /* Default attribute mapping is 4 */ + t1000->attrmap = 4; + t1000_recalcattrs(t1000); + + /* Start off in 80x25 text mode */ + t1000->cga.cgastat = 0xF4; + t1000->cga.vram = t1000->vram; + t1000->enabled = 1; + t1000->video_options = 0x01; + language = device_get_config_int("display_language") ? 2 : 0; + return t1000; +} + +static void t1000_close(void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + + free(t1000->vram); + free(t1000); +} + +static void t1000_speed_changed(void *p) +{ + t1000_t *t1000 = (t1000_t *)p; + + t1000_recalctimings(t1000); +} + +static device_config_t t1000_config[] = +{ + { + .name = "display_language", + .description = "Language", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "USA", + .value = 0 + }, + { + .description = "Danish", + .value = 1 + } + }, + .default_int = 0 + }, + { + .type = -1 + } +}; + + +device_t t1000_device = +{ + "Toshiba T1000", + 0, + t1000_init, + t1000_close, + NULL, + t1000_speed_changed, + NULL, + NULL, + t1000_config +}; diff --git a/src/vid_t1000.h b/src/vid_t1000.h new file mode 100644 index 0000000..f754cfa --- /dev/null +++ b/src/vid_t1000.h @@ -0,0 +1,5 @@ +extern device_t t1000_device; + +void t1000_video_options_set(uint8_t options); +void t1000_display_set(uint8_t internal); +void t1000_video_enable(uint8_t enabled); diff --git a/src/vid_t3100e.c b/src/vid_t3100e.c new file mode 100644 index 0000000..8a48450 --- /dev/null +++ b/src/vid_t3100e.c @@ -0,0 +1,723 @@ +/* Emulate the Toshiba 3100e plasma display. This display has a fixed 640x400 + * resolution. */ +#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_t3100e.h" + +#define T3100E_XSIZE 640 +#define T3100E_YSIZE 400 + +/*Very rough estimate*/ +#define VID_CLOCK (double)(651 * 416 * 60) + +/* T3100e CRTC regs (from the ROM): + * + * Selecting a character height of 3 seems to be sufficient to convert the + * 640x200 graphics mode to 640x400 (and, by analogy, 320x200 to 320x400). + * + * + * Horiz-----> Vert------> I ch + * 38 28 2D 0A 1F 06 19 1C 02 07 06 07 CO40 + * 71 50 5A 0A 1F 06 19 1C 02 07 06 07 CO80 + * 38 28 2D 0A 7F 06 64 70 02 01 06 07 Graphics + * 61 50 52 0F 19 06 19 19 02 0D 0B 0C MONO + * 2D 28 22 0A 67 00 64 67 02 03 06 07 640x400 + */ +void updatewindowsize(int x, int y); + +/* Mapping of attributes to colours */ +static uint32_t amber, black; +static uint8_t boldcols[256]; /* Which attributes use the bold font */ +static uint32_t blinkcols[256][2]; +static uint32_t normcols[256][2]; + +/* Video options set by the motherboard; they will be picked up by the card + * on the next poll. + * + * Bit 3: Disable built-in video (for add-on card) + * Bit 2: Thin font + * Bits 0,1: Font set (not currently implemented) + */ +static uint8_t st_video_options; +static uint8_t st_display_internal = -1; + +void t3100e_video_options_set(uint8_t options) +{ + st_video_options = options; +} + +void t3100e_display_set(uint8_t internal) +{ + st_display_internal = internal; +} + +uint8_t t3100e_display_get() +{ + return st_display_internal; +} + + +typedef struct t3100e_t +{ + mem_mapping_t mapping; + + cga_t cga; /* The CGA is used for the external + * display; most of its registers are + * ignored by the plasma display. */ + + int font; /* Current font, 0-3 */ + int enabled; /* Hardware enabled, 0 or 1 */ + int internal; /* Using internal display? */ + uint8_t attrmap; /* Attribute mapping register */ + + uint64_t dispontime, dispofftime; + + int linepos, displine; + int vc; + int dispon; + int vsynctime; + uint8_t video_options; + + uint8_t *vram; +} t3100e_t; + + +void t3100e_recalctimings(t3100e_t *t3100e); +void t3100e_write(uint32_t addr, uint8_t val, void *p); +uint8_t t3100e_read(uint32_t addr, void *p); +void t3100e_recalcattrs(t3100e_t *t3100e); + + +void t3100e_out(uint16_t addr, uint8_t val, void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + switch (addr) + { + /* Emulated CRTC, register select */ + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + cga_out(addr, val, &t3100e->cga); + break; + + /* Emulated CRTC, value */ + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + /* Register 0x12 controls the attribute mappings for the + * plasma screen. */ + if (t3100e->cga.crtcreg == 0x12) + { + t3100e->attrmap = val; + t3100e_recalcattrs(t3100e); + return; + } + cga_out(addr, val, &t3100e->cga); + + t3100e_recalctimings(t3100e); + return; + + /* CGA control register */ + case 0x3D8: + cga_out(addr, val, &t3100e->cga); + return; + /* CGA colour register */ + case 0x3D9: + cga_out(addr, val, &t3100e->cga); + return; + } +} + +uint8_t t3100e_in(uint16_t addr, void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + uint8_t val; + + switch (addr) + { + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + if (t3100e->cga.crtcreg == 0x12) + { + val = t3100e->attrmap & 0x0F; + if (t3100e->internal) val |= 0x30; /* Plasma / CRT */ + return val; + } + } + + return cga_in(addr, &t3100e->cga); +} + + + + +void t3100e_write(uint32_t addr, uint8_t val, void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + egawrites++; + +// pclog("CGA_WRITE %04X %02X\n", addr, val); + t3100e->vram[addr & 0x7fff] = val; + cycles -= 4; +} + + + +uint8_t t3100e_read(uint32_t addr, void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + egareads++; + cycles -= 4; + +// pclog("CGA_READ %04X\n", addr); + return t3100e->vram[addr & 0x7fff]; +} + + + +void t3100e_recalctimings(t3100e_t *t3100e) +{ + double disptime; + double _dispontime, _dispofftime; + + if (!t3100e->internal) + { + cga_recalctimings(&t3100e->cga); + return; + } + disptime = 651; + _dispontime = 640; + _dispofftime = disptime - _dispontime; + t3100e->dispontime = (uint64_t)(_dispontime * (cpuclock / VID_CLOCK) * (double)(1ull << 32)); + t3100e->dispofftime = (uint64_t)(_dispofftime * (cpuclock / VID_CLOCK) * (double)(1ull << 32)); +} + + +/* Draw a row of text in 80-column mode */ +void t3100e_text_row80(t3100e_t *t3100e) +{ + uint32_t cols[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + int bold; + int blink; + uint16_t addr; + uint8_t sc; + uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; + uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff; + + sc = (t3100e->displine) & 15; + addr = ((ma & ~1) + (t3100e->displine >> 4) * 80) * 2; + ma += (t3100e->displine >> 4) * 80; + + if ((t3100e->cga.crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((t3100e->cga.crtc[10] & 0x0F)*2 <= sc) && + ((t3100e->cga.crtc[11] & 0x0F)*2 >= sc); + } + for (x = 0; x < 80; x++) + { + chr = t3100e->vram[(addr + 2 * x) & 0x7FFF]; + attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF]; + drawcursor = ((ma == ca) && cursorline && + (t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16)); + + blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (t3100e->video_options & 4) + bold = boldcols[attr] ? chr + 256 : chr; + else + bold = boldcols[attr] ? chr : chr + 256; + bold += 512 * (t3100e->video_options & 3); + + if (t3100e->cga.cgamode & 0x20) /* Blink */ + { + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; + } + else + { + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 3) + c] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + ++ma; + } +} + +/* Draw a row of text in 40-column mode */ +void t3100e_text_row40(t3100e_t *t3100e) +{ + uint32_t cols[2]; + int x, c; + uint8_t chr, attr; + int drawcursor; + int cursorline; + int bold; + int blink; + uint16_t addr; + uint8_t sc; + uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; + uint16_t ca = (t3100e->cga.crtc[15] | (t3100e->cga.crtc[14] << 8)) & 0x7fff; + + sc = (t3100e->displine) & 15; + addr = ((ma & ~1) + (t3100e->displine >> 4) * 40) * 2; + ma += (t3100e->displine >> 4) * 40; + + if ((t3100e->cga.crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((t3100e->cga.crtc[10] & 0x0F)*2 <= sc) && + ((t3100e->cga.crtc[11] & 0x0F)*2 >= sc); + } + for (x = 0; x < 40; x++) + { + chr = t3100e->vram[(addr + 2 * x) & 0x7FFF]; + attr = t3100e->vram[(addr + 2 * x + 1) & 0x7FFF]; + drawcursor = ((ma == ca) && cursorline && + (t3100e->cga.cgamode & 8) && (t3100e->cga.cgablink & 16)); + + blink = ((t3100e->cga.cgablink & 16) && (t3100e->cga.cgamode & 0x20) && + (attr & 0x80) && !drawcursor); + + if (t3100e->video_options & 4) + bold = boldcols[attr] ? chr + 256 : chr; + else bold = boldcols[attr] ? chr : chr + 256; + bold += 512 * (t3100e->video_options & 3); + + if (t3100e->cga.cgamode & 0x20) /* Blink */ + { + cols[1] = blinkcols[attr][1]; + cols[0] = blinkcols[attr][0]; + if (blink) cols[1] = cols[0]; + } + else + { + cols[1] = normcols[attr][1]; + cols[0] = normcols[attr][0]; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2 + 1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0] ^ (amber ^ black); + } + } + else + { + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2] = + ((uint32_t *)buffer32->line[t3100e->displine])[(x << 4) + c*2+1] = cols[(fontdatm[bold][sc] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + ++ma; + } +} + + + + +/* Draw a line in CGA 640x200 or T3100e 640x400 mode */ +void t3100e_cgaline6(t3100e_t *t3100e) +{ + int x, c; + uint8_t dat; + uint32_t ink = 0; + uint16_t addr; + uint32_t fg = (t3100e->cga.cgacol & 0x0F) ? amber : black; + uint32_t bg = black; + + uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; + + if (t3100e->cga.crtc[9] == 3) /* 640*400 */ + { + addr = ((t3100e->displine) & 1) * 0x2000 + + ((t3100e->displine >> 1) & 1) * 0x4000 + + (t3100e->displine >> 2) * 80 + + ((ma & ~1) << 1); + } + else + { + addr = ((t3100e->displine >> 1) & 1) * 0x2000 + + (t3100e->displine >> 2) * 80 + + ((ma & ~1) << 1); + } + for (x = 0; x < 80; x++) + { + dat = t3100e->vram[addr & 0x7FFF]; + addr++; + + for (c = 0; c < 8; c++) + { + ink = (dat & 0x80) ? fg : bg; + if (!(t3100e->cga.cgamode & 8)) ink = black; + ((uint32_t *)buffer32->line[t3100e->displine])[x*8+c] = ink; + dat = dat << 1; + } + } +} + + +/* Draw a line in CGA 320x200 mode. Here the CGA colours are converted to + * dither patterns: colour 1 to 25% grey, colour 2 to 50% grey */ +void t3100e_cgaline4(t3100e_t *t3100e) +{ + int x, c; + uint8_t dat, pattern; + uint32_t ink0, ink1; + uint16_t addr; + + uint16_t ma = (t3100e->cga.crtc[13] | (t3100e->cga.crtc[12] << 8)) & 0x7fff; + if (t3100e->cga.crtc[9] == 3) /* 320*400 undocumented */ + { + addr = ((t3100e->displine) & 1) * 0x2000 + + ((t3100e->displine >> 1) & 1) * 0x4000 + + (t3100e->displine >> 2) * 80 + + ((ma & ~1) << 1); + } + else /* 320*200 */ + { + addr = ((t3100e->displine >> 1) & 1) * 0x2000 + + (t3100e->displine >> 2) * 80 + + ((ma & ~1) << 1); + } + for (x = 0; x < 80; x++) + { + dat = t3100e->vram[addr & 0x7FFF]; + addr++; + + for (c = 0; c < 4; c++) + { + pattern = (dat & 0xC0) >> 6; + if (!(t3100e->cga.cgamode & 8)) pattern = 0; + + switch (pattern & 3) + { + case 0: ink0 = ink1 = black; break; + case 1: if (t3100e->displine & 1) + { + ink0 = black; ink1 = black; + } + else + { + ink0 = amber; ink1 = black; + } + break; + case 2: if (t3100e->displine & 1) + { + ink0 = black; ink1 = amber; + } + else + { + ink0 = amber; ink1 = black; + } + break; + case 3: ink0 = ink1 = amber; break; + + } + ((uint32_t *)buffer32->line[t3100e->displine])[x*8+2*c] = ink0; + ((uint32_t *)buffer32->line[t3100e->displine])[x*8+2*c+1] = ink1; + dat = dat << 2; + } + } +} + + + + + + +void t3100e_poll(void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + + if (t3100e->video_options != st_video_options) + { + t3100e->video_options = st_video_options; + + if (t3100e->video_options & 8) /* Disable internal CGA */ + mem_mapping_disable(&t3100e->mapping); + else mem_mapping_enable(&t3100e->mapping); + + /* Set the font used for the external display */ + t3100e->cga.fontbase = (512 * (t3100e->video_options & 3)) + + ((t3100e->video_options & 4) ? 256 : 0); + + } + /* Switch between internal plasma and external CRT display. */ + if (st_display_internal != -1 && st_display_internal != t3100e->internal) + { + t3100e->internal = st_display_internal; + t3100e_recalctimings(t3100e); + } + if (!t3100e->internal) + { + cga_poll(&t3100e->cga); + return; + } + + + if (!t3100e->linepos) + { + timer_advance_u64(&t3100e->cga.timer, t3100e->dispofftime); + t3100e->cga.cgastat |= 1; + t3100e->linepos = 1; + if (t3100e->dispon) + { + if (t3100e->displine == 0) + { + video_wait_for_buffer(); + } + + /* Graphics */ + if (t3100e->cga.cgamode & 0x02) + { + if (t3100e->cga.cgamode & 0x10) + t3100e_cgaline6(t3100e); + else t3100e_cgaline4(t3100e); + } + else + if (t3100e->cga.cgamode & 0x01) /* High-res text */ + { + t3100e_text_row80(t3100e); + } + else + { + t3100e_text_row40(t3100e); + } + } + t3100e->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (t3100e->displine == 400) /* Start of VSYNC */ + { + t3100e->cga.cgastat |= 8; + t3100e->dispon = 0; + } + if (t3100e->displine == 416) /* End of VSYNC */ + { + t3100e->displine = 0; + t3100e->cga.cgastat &= ~8; + t3100e->dispon = 1; + } + } + else + { + if (t3100e->dispon) + { + t3100e->cga.cgastat &= ~1; + } + timer_advance_u64(&t3100e->cga.timer, t3100e->dispontime); + t3100e->linepos = 0; + + if (t3100e->displine == 400) + { +/* Hardcode 640x400 window size */ + if (T3100E_XSIZE != xsize || T3100E_YSIZE != ysize) + { + xsize = T3100E_XSIZE; + ysize = T3100E_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 640x400 resolution */ + video_res_x = T3100E_XSIZE; + video_res_y = T3100E_YSIZE; + + if (t3100e->cga.cgamode & 0x02) + { + if (t3100e->cga.cgamode & 0x10) + video_bpp = 1; + else video_bpp = 2; + + } + else video_bpp = 0; + t3100e->cga.cgablink++; + } + } +} + + + +void t3100e_recalcattrs(t3100e_t *t3100e) +{ + int n; + + /* val behaves as follows: + * Bit 0: Attributes 01-06, 08-0E are inverse video + * Bit 1: Attributes 01-06, 08-0E are bold + * Bit 2: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF + * are inverse video + * Bit 3: Attributes 11-16, 18-1F, 21-26, 28-2F ... F1-F6, F8-FF + * are bold */ + + /* Set up colours */ + amber = makecol(0xf7, 0x7C, 0x34); + black = makecol(0x17, 0x0C, 0x00); + + /* Initialise the attribute mapping. Start by defaulting everything + * to black on amber, and with bold set by bit 3 */ + for (n = 0; n < 256; n++) + { + boldcols[n] = (n & 8) != 0; + blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][1] = normcols[n][1] = black; + } + + /* Colours 0x11-0xFF are controlled by bits 2 and 3 of the + * passed value. Exclude x0 and x8, which are always black on + * amber. */ + for (n = 0x11; n <= 0xFF; n++) + { + if ((n & 7) == 0) continue; + if (t3100e->attrmap & 4) /* Inverse */ + { + blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][1] = normcols[n][1] = black; + } + else /* Normal */ + { + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + } + if (t3100e->attrmap & 8) boldcols[n] = 1; /* Bold */ + } + /* Set up the 01-0E range, controlled by bits 0 and 1 of the + * passed value. When blinking is enabled this also affects 81-8E. */ + for (n = 0x01; n <= 0x0E; n++) + { + if (n == 7) continue; + if (t3100e->attrmap & 1) + { + blinkcols[n][0] = normcols[n][0] = amber; + blinkcols[n][1] = normcols[n][1] = black; + blinkcols[n+128][0] = amber; + blinkcols[n+128][1] = black; + } + else + { + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + blinkcols[n+128][0] = black; + blinkcols[n+128][1] = amber; + } + if (t3100e->attrmap & 2) boldcols[n] = 1; + } + /* Colours 07 and 0F are always amber on black. If blinking is + * enabled so are 87 and 8F. */ + for (n = 0x07; n <= 0x0F; n += 8) + { + blinkcols[n][0] = normcols[n][0] = black; + blinkcols[n][1] = normcols[n][1] = amber; + blinkcols[n+128][0] = black; + blinkcols[n+128][1] = amber; + } + /* When not blinking, colours 81-8F are always amber on black. */ + for (n = 0x81; n <= 0x8F; n ++) + { + normcols[n][0] = black; + normcols[n][1] = amber; + boldcols[n] = (n & 0x08) != 0; + } + + + /* Finally do the ones which are solid black. These differ between + * the normal and blinking mappings */ + for (n = 0; n <= 0xFF; n += 0x11) + { + normcols[n][0] = normcols[n][1] = black; + } + /* In the blinking range, 00 11 22 .. 77 and 80 91 A2 .. F7 are black */ + for (n = 0; n <= 0x77; n += 0x11) + { + blinkcols[n][0] = blinkcols[n][1] = black; + blinkcols[n+128][0] = blinkcols[n+128][1] = black; + } +} + + +void *t3100e_init() +{ + t3100e_t *t3100e = malloc(sizeof(t3100e_t)); + memset(t3100e, 0, sizeof(t3100e_t)); + cga_init(&t3100e->cga); + + t3100e->internal = 1; + + /* 32k video RAM */ + t3100e->vram = malloc(0x8000); + + timer_set_callback(&t3100e->cga.timer, t3100e_poll); + timer_set_p(&t3100e->cga.timer, t3100e); + + /* Occupy memory between 0xB8000 and 0xBFFFF */ + mem_mapping_add(&t3100e->mapping, 0xb8000, 0x8000, t3100e_read, NULL, NULL, t3100e_write, NULL, NULL, NULL, 0, t3100e); + /* Respond to CGA I/O ports */ + io_sethandler(0x03d0, 0x000c, t3100e_in, NULL, NULL, t3100e_out, NULL, NULL, t3100e); + + /* Default attribute mapping is 4 */ + t3100e->attrmap = 4; + t3100e_recalcattrs(t3100e); + +/* Start off in 80x25 text mode */ + t3100e->cga.cgastat = 0xF4; + t3100e->cga.vram = t3100e->vram; + t3100e->enabled = 1; + t3100e->video_options = 0xFF; + return t3100e; +} + +void t3100e_close(void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + + free(t3100e->vram); + free(t3100e); +} + +void t3100e_speed_changed(void *p) +{ + t3100e_t *t3100e = (t3100e_t *)p; + + t3100e_recalctimings(t3100e); +} + +device_t t3100e_device = +{ + "Toshiba T3100e", + 0, + t3100e_init, + t3100e_close, + NULL, + t3100e_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_t3100e.h b/src/vid_t3100e.h new file mode 100644 index 0000000..b09688c --- /dev/null +++ b/src/vid_t3100e.h @@ -0,0 +1,4 @@ +extern device_t t3100e_device; + +void t3100e_video_options_set(uint8_t options); +void t3100e_display_set(uint8_t internal); diff --git a/src/vid_tandy.c b/src/vid_tandy.c index 769a098..1b07f27 100644 --- a/src/vid_tandy.c +++ b/src/vid_tandy.c @@ -37,7 +37,8 @@ typedef struct tandy_t int vsynctime, vadj; uint16_t ma, maback; - int dispontime, dispofftime, vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; int composite; @@ -59,10 +60,10 @@ void tandy_out(uint16_t addr, uint8_t val, void *p) // pclog("Tandy OUT %04X %02X\n",addr,val); switch (addr) { - case 0x3d4: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: tandy->crtcreg = val & 0x1f; return; - case 0x3d5: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: old = tandy->crtc[tandy->crtcreg]; tandy->crtc[tandy->crtcreg] = val & crtcmask[tandy->crtcreg]; if (old != val) @@ -186,8 +187,8 @@ void tandy_recalctimings(tandy_t *tandy) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - tandy->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - tandy->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + tandy->dispontime = (uint64_t)_dispontime; + tandy->dispofftime = (uint64_t)_dispofftime; } @@ -208,7 +209,7 @@ void tandy_poll(void *p) { // cgapal[0]=tandy->col&15; // printf("Firstline %i Lastline %i tandy->displine %i\n",firstline,lastline,tandy->displine); - tandy->vidtime += tandy->dispofftime; + timer_advance_u64(&tandy->timer, tandy->dispofftime); tandy->stat |= 1; tandy->linepos = 1; oldsc = tandy->sc; @@ -223,26 +224,26 @@ void tandy_poll(void *p) // printf("Firstline %i\n",firstline); } tandy->lastline = tandy->displine; - cols[0] = (tandy->array[2] & 0xf) + 16; + cols[0] = tandy->array[2] & 0xf; 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]; + ((uint32_t *)buffer32->line[tandy->displine])[c] = cols[0]; + if (tandy->mode & 1) ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 3) + 8] = cols[0]; + else ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[tandy->displine])[c] = 0; + if (tandy->mode & 1) ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 3) + 8] = 0; + else ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[tandy->displine])[c] = tandy->col & 15; + if (tandy->mode & 1) ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 3) + 8] = tandy->col & 15; + else ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 4) + 8] = tandy->col & 15; } } // printf("X %i %i\n",c+(crtc[1]<<4)+8,c+(crtc[1]<<3)+8); @@ -254,14 +255,14 @@ void tandy_poll(void *p) 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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 8] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 9] = tandy->array[((dat >> 12) & tandy->array[1]) + 16]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 10] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 11] = tandy->array[((dat >> 8) & tandy->array[1]) + 16]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 12] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 13] = tandy->array[((dat >> 4) & tandy->array[1]) + 16]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 14] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 15] = tandy->array[(dat & tandy->array[1]) + 16]; } } else if (tandy->array[3] & 0x10) /*160x200x16*/ @@ -271,22 +272,22 @@ void tandy_poll(void *p) 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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 8] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 9] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 10] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 11] = tandy->array[((dat >> 12) & tandy->array[1]) + 16]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 12] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 13] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 14] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 15] = tandy->array[((dat >> 8) & tandy->array[1]) + 16]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 16] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 17] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 18] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 19] = tandy->array[((dat >> 4) & tandy->array[1]) + 16]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 20] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 21] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 22] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 23] = tandy->array[(dat & tandy->array[1]) + 16]; } } else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ @@ -300,7 +301,7 @@ void tandy_poll(void *p) { chr = (dat >> 7) & 1; chr |= ((dat >> 14) & 2); - buffer->line[tandy->displine][(x << 3) + 8 + c] = tandy->array[(chr & tandy->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 8 + c] = tandy->array[(chr & tandy->array[1]) + 16]; dat <<= 1; } } @@ -314,31 +315,31 @@ void tandy_poll(void *p) 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; + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16]; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 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; + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16]; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16]; } if (tandy->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[tandy->displine][(x << 3) + c + 8] = cols[0]; + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + c + 8] ^= 0xffffff; } tandy->ma++; } @@ -352,40 +353,40 @@ void tandy_poll(void *p) 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; + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16]; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 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; + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16]; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 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]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + c + 8] ^= 0xffffff; } } } - else if (!(tandy->mode& 16)) + else if (!(tandy->mode & 16)) { - cols[0] = (tandy->col & 15) | 16; - col = (tandy->col & 16) ? 24 : 16; + cols[0] = tandy->col & 15; + col = (tandy->col & 16) ? 8 : 0; if (tandy->mode & 4) { cols[1] = col | 3; @@ -411,8 +412,8 @@ void tandy_poll(void *p) 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]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; dat <<= 2; } } @@ -420,7 +421,7 @@ void tandy_poll(void *p) else { cols[0] = 0; - cols[1] = tandy->array[(tandy->col & tandy->array[1]) + 16] + 16; + cols[1] = tandy->array[(tandy->col & tandy->array[1]) + 16]; for (x = 0; x < tandy->crtc[1]; x++) { dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | @@ -428,7 +429,7 @@ void tandy_poll(void *p) tandy->ma++; for (c = 0; c < 16; c++) { - buffer->line[tandy->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -438,14 +439,14 @@ void tandy_poll(void *p) { 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); + if (tandy->mode & 1) hline(buffer32, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, tandy->array[2] & 0xf); + else hline(buffer32, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, tandy->array[2] & 0xf); } 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]); + cols[0] = ((tandy->mode & 0x12) == 0x12) ? 0 : (tandy->col & 0xf); + if (tandy->mode & 1) hline(buffer32, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, cols[0]); } } if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; @@ -454,10 +455,15 @@ void tandy_poll(void *p) if (tandy->composite) { for (c = 0; c < x; c++) - buffer32->line[tandy->displine][c] = buffer->line[tandy->displine][c] & 0xf; + buffer32->line[tandy->displine][c] = ((uint32_t *)buffer32->line[tandy->displine])[c] & 0xf; Composite_Process(tandy->mode, 0, x >> 2, buffer32->line[tandy->displine]); } + else + { + for (c = 0; c < x; c++) + ((uint32_t *)buffer32->line[tandy->displine])[c] = cgapal[((uint32_t *)buffer32->line[tandy->displine])[c] & 0xf]; + } tandy->sc = oldsc; if (tandy->vc == tandy->crtc[7] && !tandy->sc) @@ -471,7 +477,7 @@ void tandy_poll(void *p) } else { - tandy->vidtime += tandy->dispontime; + timer_advance_u64(&tandy->timer, tandy->dispontime); if (tandy->dispon) tandy->stat &= ~1; tandy->linepos = 0; @@ -553,10 +559,7 @@ void tandy_poll(void *p) // printf("Blit %i %i\n",firstline,lastline); //printf("Xsize is %i\n",xsize); - if (tandy->composite) - 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); + video_blit_memtoscreen(0, tandy->firstline-4, 0, (tandy->lastline - tandy->firstline) + 8, xsize, (tandy->lastline - tandy->firstline) + 8); frames++; video_res_x = xsize - 16; @@ -622,7 +625,7 @@ void *tandy_init() tandy->memctrl = -1; tandy->base = (mem_size - 128) * 1024; - timer_add(tandy_poll, &tandy->vidtime, TIMER_ALWAYS_ENABLED, tandy); + timer_add(&tandy->timer, tandy_poll, tandy, 1); 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*/ diff --git a/src/vid_tandysl.c b/src/vid_tandysl.c index 22f3521..1119f14 100644 --- a/src/vid_tandysl.c +++ b/src/vid_tandysl.c @@ -35,7 +35,8 @@ typedef struct tandysl_t int vsynctime, vadj; uint16_t ma, maback; - int dispontime, dispofftime, vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int firstline, lastline; } tandysl_t; @@ -59,10 +60,10 @@ static void tandysl_out(uint16_t addr, uint8_t val, void *p) // pclog("TandySL OUT %04X %02X\n",addr,val); switch (addr) { - case 0x3d4: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: tandy->crtcreg = val & 0x1f; return; - case 0x3d5: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: // pclog("Write CRTC R%02x %02x ",tandy->crtcreg, val); old = tandy->crtc[tandy->crtcreg]; tandy->crtc[tandy->crtcreg] = val & crtcmask[tandy->crtcreg]; @@ -249,8 +250,8 @@ static void tandysl_recalctimings(tandysl_t *tandy) _dispofftime = disptime - _dispontime; _dispontime *= CGACONST; _dispofftime *= CGACONST; - tandy->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - tandy->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + tandy->dispontime = (uint64_t)_dispontime; + tandy->dispofftime = (uint64_t)_dispofftime; } @@ -272,7 +273,7 @@ static void tandysl_poll(void *p) // 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; + timer_advance_u64(&tandy->timer, tandy->dispofftime); tandy->stat |= 1; tandy->linepos = 1; oldsc = tandy->sc; @@ -287,26 +288,26 @@ static void tandysl_poll(void *p) // printf("Firstline %i\n",firstline); } tandy->lastline = tandy->displine; - cols[0] = (tandy->array[2] & 0xf) + 16; + cols[0] = cgapal[tandy->array[2] & 0xf]; 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]; + ((uint32_t *)buffer32->line[tandy->displine])[c] = cols[0]; + if (tandy->mode & 1) ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 3) + 8] = cols[0]; + else ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[tandy->displine])[c] = cgapal[0]; + if (tandy->mode & 1) ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 3) + 8] = cgapal[0]; + else ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 4) + 8] = cgapal[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; + ((uint32_t *)buffer32->line[tandy->displine])[c] = cgapal[tandy->col & 15]; + if (tandy->mode & 1) ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 3) + 8] = cgapal[tandy->col & 15]; + else ((uint32_t *)buffer32->line[tandy->displine])[c + (tandy->crtc[1] << 4) + 8] = cgapal[tandy->col & 15]; } } if (tandy->array[5] & 1) /*640x200x16*/ @@ -316,10 +317,10 @@ static void tandysl_poll(void *p) 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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 2) + 8] = cgapal[tandy->array[((dat >> 12) & 0xf)/*tandy->array[1])*/ + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 2) + 9] = cgapal[tandy->array[((dat >> 8) & 0xf)/*tandy->array[1])*/ + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 2) + 10] = cgapal[tandy->array[((dat >> 4) & 0xf)/*tandy->array[1])*/ + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 2) + 11] = cgapal[tandy->array[(dat & 0xf)/*tandy->array[1])*/ + 16]]; } } else if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ @@ -329,14 +330,14 @@ static void tandysl_poll(void *p) 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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 8] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 9] = cgapal[tandy->array[((dat >> 12) & tandy->array[1]) + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 10] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 11] = cgapal[tandy->array[((dat >> 8) & tandy->array[1]) + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 12] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 13] = cgapal[tandy->array[((dat >> 4) & tandy->array[1]) + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 14] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 15] = cgapal[tandy->array[(dat & tandy->array[1]) + 16]]; } } else if (tandy->array[3] & 0x10) /*160x200x16*/ @@ -346,22 +347,22 @@ static void tandysl_poll(void *p) 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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 8] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 9] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 10] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 11] = cgapal[tandy->array[((dat >> 12) & tandy->array[1]) + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 12] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 13] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 14] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 15] = cgapal[tandy->array[((dat >> 8) & tandy->array[1]) + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 16] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 17] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 18] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 19] = cgapal[tandy->array[((dat >> 4) & tandy->array[1]) + 16]]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 20] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 21] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 22] = + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + 23] = cgapal[tandy->array[(dat & tandy->array[1]) + 16]]; } } else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ @@ -375,7 +376,7 @@ static void tandysl_poll(void *p) { chr = (dat >> 7) & 1; chr |= ((dat >> 14) & 2); - buffer->line[tandy->displine][(x << 3) + 8 + c] = tandy->array[(chr & tandy->array[1]) + 16] + 16; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + 8 + c] = cgapal[tandy->array[(chr & tandy->array[1]) + 16]]; dat <<= 1; } } @@ -389,31 +390,31 @@ static void tandysl_poll(void *p) 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; + cols[1] = cgapal[tandy->array[ ((attr & 15) & tandy->array[1]) + 16]]; + cols[0] = cgapal[tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 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; + cols[1] = cgapal[tandy->array[((attr & 15) & tandy->array[1]) + 16]]; + cols[0] = cgapal[tandy->array[((attr >> 4) & tandy->array[1]) + 16]]; } if (tandy->sc & 8) { for (c = 0; c < 8; c++) - buffer->line[tandy->displine][(x << 3) + c + 8] = cols[0]; + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 3) + c + 8] ^= 0xffffff; } tandy->ma++; } @@ -427,57 +428,57 @@ static void tandysl_poll(void *p) 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; + cols[1] = cgapal[tandy->array[ ((attr & 15) & tandy->array[1]) + 16]]; + cols[0] = cgapal[tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 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; + cols[1] = cgapal[tandy->array[((attr & 15) & tandy->array[1]) + 16]]; + cols[0] = cgapal[tandy->array[((attr >> 4) & tandy->array[1]) + 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]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + c + 8] ^= 0xffffff; } } } - else if (!(tandy->mode& 16)) + else if (!(tandy->mode & 16)) { - cols[0] = (tandy->col & 15) | 16; - col = (tandy->col & 16) ? 24 : 16; + cols[0] = cgapal[tandy->col & 15]; + col = (tandy->col & 16) ? 8 : 0; if (tandy->mode & 4) { - cols[1] = col | 3; - cols[2] = col | 4; - cols[3] = col | 7; + cols[1] = cgapal[col | 3]; + cols[2] = cgapal[col | 4]; + cols[3] = cgapal[col | 7]; } else if (tandy->col & 32) { - cols[1] = col | 3; - cols[2] = col | 5; - cols[3] = col | 7; + cols[1] = cgapal[col | 3]; + cols[2] = cgapal[col | 5]; + cols[3] = cgapal[col | 7]; } else { - cols[1] = col | 2; - cols[2] = col | 4; - cols[3] = col | 6; + cols[1] = cgapal[col | 2]; + cols[2] = cgapal[col | 4]; + cols[3] = cgapal[col | 6]; } for (x = 0; x < tandy->crtc[1]; x++) { @@ -486,16 +487,16 @@ static void tandysl_poll(void *p) 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]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->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; + cols[0] = cgapal[0]; + cols[1] = cgapal[tandy->array[(tandy->col & tandy->array[1]) + 16]]; for (x = 0; x < tandy->crtc[1]; x++) { dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | @@ -503,7 +504,7 @@ static void tandysl_poll(void *p) tandy->ma++; for (c = 0; c < 16; c++) { - buffer->line[tandy->displine][(x << 4) + c + 8] = cols[dat >> 15]; + ((uint32_t *)buffer32->line[tandy->displine])[(x << 4) + c + 8] = cols[dat >> 15]; dat <<= 1; } } @@ -513,14 +514,14 @@ static void tandysl_poll(void *p) { 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); + if (tandy->mode & 1) hline(buffer32, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, cgapal[tandy->array[2] & 0xf]); + else hline(buffer32, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, cgapal[tandy->array[2] & 0xf]); } 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]); + cols[0] = cgapal[((tandy->mode & 0x12) == 0x12) ? 0 : (tandy->col & 0xf)]; + if (tandy->mode & 1) hline(buffer32, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, cols[0]); } } if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; @@ -537,7 +538,7 @@ static void tandysl_poll(void *p) } else { - tandy->vidtime += tandy->dispontime; + timer_advance_u64(&tandy->timer, tandy->dispontime); if (tandy->dispon) tandy->stat &= ~1; tandy->linepos = 0; @@ -631,7 +632,7 @@ static void tandysl_poll(void *p) // printf("Blit %i %i\n",firstline,lastline); //printf("Xsize is %i\n",xsize); - video_blit_memtoscreen_8(0, tandy->firstline-4, xsize, (tandy->lastline - tandy->firstline) + 8); + video_blit_memtoscreen(0, tandy->firstline-4, 0, (tandy->lastline - tandy->firstline) + 8, xsize, (tandy->lastline - tandy->firstline) + 8); frames++; video_res_x = xsize - 16; @@ -694,7 +695,7 @@ static void *tandysl_init() tandy->b8000_limit = 0x8000; tandy->planar_ctrl = 4; - timer_add(tandysl_poll, &tandy->vidtime, TIMER_ALWAYS_ENABLED, tandy); + timer_add(&tandy->timer, tandysl_poll, tandy, 1); 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*/ diff --git a/src/vid_tgui9440.c b/src/vid_tgui9440.c index 6a93aec..a42f7e9 100644 --- a/src/vid_tgui9440.c +++ b/src/vid_tgui9440.c @@ -1,4 +1,4 @@ -/*Trident TGUI9440 emulation*/ +/*Trident TGUI9400CXi & TGUI9440 emulation*/ #include #include "ibm.h" #include "device.h" @@ -13,6 +13,42 @@ #include "vid_tkd8001_ramdac.h" #include "vid_tgui9440.h" +/*TGUI9400CXi has extended write modes, controlled by extended GDC registers : + + GDC[0x10] - Control + bit 0 - pixel width (1 = 16 bit, 0 = 8 bit) + bit 1 - mono->colour expansion (1 = enabled, 0 = disabled) + bit 2 - mono->colour expansion transparency (1 = tranparent, 0 = opaque) + bit 3 - extended latch copy + GDC[0x11] - Background colour (low byte) + GDC[0x12] - Background colour (high byte) + GDC[0x14] - Foreground colour (low byte) + GDC[0x15] - Foreground colour (high byte) + GDC[0x17] - Write mask (low byte) + GDC[0x18] - Write mask (high byte) + + Mono->colour expansion will expand written data 8:1 to 8/16 consecutive bytes. + MSB is processed first. On word writes, low byte is processed first. 1 bits write + foreground colour, 0 bits write background colour unless transparency is enabled. + If the relevant bit is clear in the write mask then the data is not written. + + With 16-bit pixel width, each bit still expands to one byte, so the TGUI driver + doubles up monochrome data. + + While there is room in the register map for three byte colours, I don't believe + 24-bit colour is supported. The TGUI9440 blitter has the same limitation. + + I don't think double word writes are supported. + + Extended latch copy uses an internal 16 byte latch. Reads load the latch, writing + writes out 16 bytes. I don't think the access size or host data has any affect, + but the Windows 3.1 driver always reads bytes and write words of 0xffff.*/ + +#define EXT_CTRL_16BIT 0x01 +#define EXT_CTRL_MONO_EXPANSION 0x02 +#define EXT_CTRL_MONO_TRANSPARENT 0x04 +#define EXT_CTRL_LATCH_COPY 0x08 + #define FIFO_SIZE 65536 #define FIFO_MASK (FIFO_SIZE - 1) #define FIFO_ENTRY_SIZE (1 << 31) @@ -24,6 +60,12 @@ #define FIFO_TYPE 0xff000000 #define FIFO_ADDR 0x00ffffff +enum +{ + TGUI_9400CXI = 0, + TGUI_9440 +}; + enum { FIFO_INVALID = (0x00 << 24), @@ -47,6 +89,10 @@ typedef struct tgui_t rom_t bios_rom; svga_t svga; + + tkd8001_ramdac_t ramdac; /*TGUI9400CXi*/ + + int type; struct { @@ -70,9 +116,13 @@ typedef struct tgui_t uint16_t tgui_pattern[8][8]; } accel; + + uint8_t ext_gdc_regs[16]; /*TGUI9400CXi only*/ + uint8_t copy_latch[16]; uint8_t tgui_3d8, tgui_3d9; int oldmode; + uint8_t oldctrl1; uint8_t oldctrl2,newctrl2; uint32_t linear_base, linear_size; @@ -94,6 +144,8 @@ typedef struct tgui_t int blitter_busy; uint64_t blitter_time; uint64_t status_time; + + volatile int write_blitter; } tgui_t; void tgui_recalcmapping(tgui_t *tgui); @@ -108,9 +160,20 @@ 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_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_write_fb_l(uint32_t addr, uint32_t val, void *priv); +static uint8_t tgui_ext_linear_read(uint32_t addr, void *p); +static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p); +static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p); +static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p); + +static uint8_t tgui_ext_read(uint32_t addr, void *p); +static void tgui_ext_write(uint32_t addr, uint8_t val, void *p); +static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p); +static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p); + void tgui_out(uint16_t addr, uint8_t val, void *p) { tgui_t *tgui = (tgui_t *)p; @@ -134,21 +197,31 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) svga->seqregs[0xc] = val; break; case 0xd: - if (tgui->oldmode) + 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; + if (tgui->oldmode) + tgui->oldctrl1 = val; + else + { + 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->type == TGUI_9400CXI) + { + tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga); + return; + } if (tgui->ramdac_state == 4) { tgui->ramdac_state = 0; @@ -171,10 +244,23 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) return; } case 0x3C7: case 0x3C8: case 0x3C9: + if (tgui->type == TGUI_9400CXI) + { + tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga); + return; + } tgui->ramdac_state = 0; break; case 0x3CF: + if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32) + { + old = tgui->ext_gdc_regs[svga->gdcaddr & 15]; + tgui->ext_gdc_regs[svga->gdcaddr & 15] = val; + if (svga->gdcaddr == 16) + tgui_recalcmapping(tgui); + return; + } switch (svga->gdcaddr & 15) { case 0x6: @@ -225,6 +311,7 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) { tgui->linear_base = ((val & 0xf) | ((val >> 2) & 0x30)) << 20; tgui->linear_size = (val & 0x10) ? 0x200000 : 0x100000; + tgui->svga.decode_mask = (val & 0x10) ? 0x1fffff : 0xfffff; } tgui_recalcmapping(tgui); } @@ -232,15 +319,23 @@ void tgui_out(uint16_t addr, uint8_t val, void *p) 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); + if (tgui->type >= TGUI_9440) + { + 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; + if (tgui->type >= TGUI_9440) + { + svga->hwcursor.ena = val & 0x80; + svga->hwcursor.xsize = (val & 1) ? 64 : 32; + svga->hwcursor.ysize = (val & 1) ? 64 : 32; + } break; } return; @@ -294,7 +389,13 @@ uint8_t tgui_in(uint16_t addr, void *p) { // printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); tgui->oldmode = 0; - return 0xe3; /*TGUI9440AGi*/ + switch (tgui->type) + { + case TGUI_9400CXI: + return 0x93; /*TGUI9400CXi*/ + case TGUI_9440: + return 0xe3; /*TGUI9440AGi*/ + } } if ((svga->seqaddr & 0xf) == 0xc) { @@ -303,18 +404,32 @@ uint8_t tgui_in(uint16_t addr, void *p) } if ((svga->seqaddr & 0xf) == 0xd) { - if (tgui->oldmode) return tgui->oldctrl2; + if (tgui->oldmode) + return tgui->oldctrl2; return tgui->newctrl2; } + if ((svga->seqaddr & 0xf) == 0xe) + { + if (tgui->oldmode) + return tgui->oldctrl1; + } break; case 0x3C6: + if (tgui->type == TGUI_9400CXI) + return tkd8001_ramdac_in(addr, &tgui->ramdac, svga); if (tgui->ramdac_state == 4) return tgui->ramdac_ctrl; tgui->ramdac_state++; break; case 0x3C7: case 0x3C8: case 0x3C9: + if (tgui->type == TGUI_9400CXI) + return tkd8001_ramdac_in(addr, &tgui->ramdac, svga); tgui->ramdac_state = 0; break; + case 0x3CF: + if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32) + return tgui->ext_gdc_regs[svga->gdcaddr & 15]; + break; case 0x3D4: return svga->crtcreg; case 0x3D5: @@ -334,7 +449,7 @@ void tgui_recalctimings(svga_t *svga) if (svga->crtc[0x29] & 0x10) svga->rowoffset += 0x100; - if (svga->bpp == 24) + if (tgui->type >= TGUI_9440 && svga->bpp == 24) svga->hdisp = (svga->crtc[1] + 1) * 8; if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; @@ -342,24 +457,55 @@ void tgui_recalctimings(svga_t *svga) if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; if (tgui->oldctrl2 & 0x10) - { svga->rowoffset <<= 1; + if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) 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->miscout & 8) - svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + if (svga->interlace && tgui->type < TGUI_9440) + svga->rowoffset >>= 1; - if (svga->gdcreg[0xf] & 0x08) - svga->clock *= 2; - else if (svga->gdcreg[0xf] & 0x40) - svga->clock *= 3; + if (tgui->type >= TGUI_9440) + { + if (svga->miscout & 8) + svga->clock = (cpuclock * (double)(1ull << 32)) / (((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; + } + else + { + switch (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8)) + { + case 0x02: svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; break; + case 0x03: svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; + case 0x04: svga->clock = (cpuclock * (double)(1ull << 32)) / 57272000.0; break; + case 0x05: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + case 0x06: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; + case 0x07: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 0x08: svga->clock = (cpuclock * (double)(1ull << 32)) / 88000000.0; break; + case 0x09: svga->clock = (cpuclock * (double)(1ull << 32)) / 98000000.0; break; + case 0x0a: svga->clock = (cpuclock * (double)(1ull << 32)) /118800000.0; break; + case 0x0b: svga->clock = (cpuclock * (double)(1ull << 32)) /108000000.0; break; + case 0x0c: svga->clock = (cpuclock * (double)(1ull << 32)) / 72000000.0; break; + case 0x0d: svga->clock = (cpuclock * (double)(1ull << 32)) / 77000000.0; break; + case 0x0e: svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0; break; + case 0x0f: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break; + } + if (svga->gdcreg[0xf] & 0x08) + { + svga->htotal *= 2; + svga->hdisp *= 2; + svga->hdisp_time *= 2; + } + } if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) { @@ -369,13 +515,19 @@ void tgui_recalctimings(svga_t *svga) svga->render = svga_render_8bpp_highres; break; case 15: - svga->render = svga_render_15bpp_highres; + svga->render = svga_render_15bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp /= 2; break; case 16: svga->render = svga_render_16bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp /= 2; break; case 24: svga->render = svga_render_24bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp = (svga->hdisp * 2) / 3; break; } } @@ -387,12 +539,69 @@ void tgui_recalcmapping(tgui_t *tgui) // pclog("tgui_recalcmapping : %02X %02X\n", svga->crtc[0x21], svga->gdcreg[6]); + if (tgui->type == TGUI_9400CXI) + { + if (tgui->ext_gdc_regs[0] & EXT_CTRL_LATCH_COPY) + { + mem_mapping_set_handler(&tgui->linear_mapping, + tgui_ext_linear_read, NULL, NULL, + tgui_ext_linear_write, tgui_ext_linear_writew, tgui_ext_linear_writel); + mem_mapping_set_handler(&svga->mapping, + tgui_ext_read, NULL, NULL, + tgui_ext_write, tgui_ext_writew, tgui_ext_writel); + } + else if (tgui->ext_gdc_regs[0] & EXT_CTRL_MONO_EXPANSION) + { + mem_mapping_set_handler(&tgui->linear_mapping, + svga_read_linear, svga_readw_linear, svga_readl_linear, + tgui_ext_linear_write, tgui_ext_linear_writew, tgui_ext_linear_writel); + mem_mapping_set_handler(&svga->mapping, + svga_read, svga_readw, svga_readl, + tgui_ext_write, tgui_ext_writew, tgui_ext_writel); + } + else + { + 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); + mem_mapping_set_handler(&svga->mapping, + svga_read, svga_readw, svga_readl, + svga_write, svga_writew, svga_writel); + } + } + 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); + if (tgui->type >= TGUI_9440) + { + mem_mapping_enable(&tgui->accel_mapping); + mem_mapping_disable(&svga->mapping); + } + else + { + 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); + 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; + } + } } else { @@ -422,14 +631,34 @@ void tgui_recalcmapping(tgui_t *tgui) } } +/*Remap address for chain-4/doubleword style layout*/ +static inline uint32_t dword_remap(uint32_t in_addr) +{ + return ((in_addr << 2) & 0x3fff0) | + ((in_addr >> 14) & 0xc) | + (in_addr & ~0x3fffc); +} +static inline uint32_t dword_remap_w(uint32_t in_addr) +{ + return ((in_addr << 2) & 0x1fff8) | + ((in_addr >> 14) & 0x6) | + (in_addr & ~0x1fffe); +} + 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; + uint32_t remapped_addr; - 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]; + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 8; + + remapped_addr = dword_remap(svga->hwcursor_latch.addr); + dat[0] = (svga->vram[remapped_addr] << 24) | (svga->vram[remapped_addr + 1] << 16) | (svga->vram[remapped_addr + 2] << 8) | svga->vram[remapped_addr + 3]; + remapped_addr = dword_remap(svga->hwcursor_latch.addr+4); + dat[1] = (svga->vram[remapped_addr] << 24) | (svga->vram[remapped_addr + 1] << 16) | (svga->vram[remapped_addr + 2] << 8) | svga->vram[remapped_addr + 3]; for (xx = 0; xx < 32; xx++) { if (offset >= svga->hwcursor_latch.x) @@ -446,6 +675,9 @@ void tgui_hwcursor_draw(svga_t *svga, int displine) dat[1] <<= 1; } svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 8; } uint8_t tgui_pci_read(int func, int addr, void *p) @@ -497,27 +729,34 @@ void tgui_pci_write(int func, int addr, uint8_t val, void *p) case 0x12: tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xe0) << 16); tgui->linear_size = 2 << 20; + tgui->svga.decode_mask = 0x1fffff; 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; + tgui->svga.decode_mask = 0x1fffff; svga->crtc[0x21] = (svga->crtc[0x21] & ~0xc0) | (val >> 6); tgui_recalcmapping(tgui); break; } } -void *tgui9440_init() +static void *tgui_init(char *bios_fn, int type, int mem_size) { tgui_t *tgui = malloc(sizeof(tgui_t)); memset(tgui, 0, sizeof(tgui_t)); - tgui->vram_size = device_get_config_int("memory") << 20; + if (mem_size) + tgui->vram_size = mem_size; + else + tgui->vram_size = device_get_config_int("memory") << 20; tgui->vram_mask = tgui->vram_size - 1; + + tgui->type = type; - rom_init(&tgui->bios_rom, "roms/9440.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + rom_init(&tgui->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); svga_init(&tgui->svga, tgui, tgui->vram_size, tgui_recalctimings, @@ -525,14 +764,16 @@ void *tgui9440_init() 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->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l, 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); + if (tgui->type >= TGUI_9440) + io_sethandler(0x43c8, 0x0002, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); - pci_add(tgui_pci_read, tgui_pci_write, tgui); + if (tgui->type >= TGUI_9440) + pci_add(tgui_pci_read, tgui_pci_write, tgui); tgui->wake_fifo_thread = thread_create_event(); tgui->fifo_not_full_event = thread_create_event(); @@ -541,9 +782,37 @@ void *tgui9440_init() return tgui; } +static void *tgui9400cxi_init() +{ + return tgui_init("9400CXI.vbi", TGUI_9400CXI, 0); +} + +static void *tgui9400cxi_elx_init() +{ + /*Try combined ROM dump first. If not present, use seperated dump*/ + FILE *f = romfopen("elx_pc425x/elx_pc425x.bin", "rb"); + if (f) + { + fclose(f); + return tgui_init("elx_pc425x/elx_pc425x.bin", TGUI_9400CXI, 512 << 10); + } + + return tgui_init("elx_pc425x/elx_pc425x_vbios.bin", TGUI_9400CXI, 512 << 10); +} + +static void *tgui9440_init() +{ + return tgui_init("9440.vbi", TGUI_9440, 0); +} + +static int tgui9400cxi_available() +{ + return rom_present("9400CXI.vbi"); +} + static int tgui9440_available() { - return rom_present("roms/9440.vbi"); + return rom_present("9440.vbi"); } void tgui_close(void *p) @@ -573,6 +842,222 @@ void tgui_force_redraw(void *p) tgui->svga.fullchange = changeframecount; } + +static uint8_t tgui_ext_linear_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + addr &= ~0xf; + addr = dword_remap(addr); + + for (c = 0; c < 16; c++) + { + tgui->copy_latch[c] = svga->vram[addr]; + addr += ((c & 3) == 3) ? 13 : 1; + } + + return svga->vram[addr & svga->vram_mask]; +} + +static uint8_t tgui_ext_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + return tgui_ext_linear_read(addr, svga); +} + +static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]}; + uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; + uint8_t mask = tgui->ext_gdc_regs[7]; + + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + addr &= (tgui->ext_gdc_regs[0] & 8) ? ~0xf : ~0x7; + + addr = dword_remap(addr); + svga->changedvram[addr >> 12] = changeframecount; + + switch (tgui->ext_gdc_regs[0] & 0xf) + { + /*8-bit mono->colour expansion, unmasked*/ + case 2: + for (c = 7; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0]; + addr += (c == 4) ? 13 : 1; + } + break; + + /*16-bit mono->colour expansion, unmasked*/ + case 3: + for (c = 7; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1]; + addr += (c == 4) ? 13 : 1; + } + break; + + /*8-bit mono->colour expansion, masked*/ + case 6: + for (c = 7; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[0]; + addr += (c == 4) ? 13 : 1; + } + break; + + /*16-bit mono->colour expansion, masked*/ + case 7: + for (c = 7; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1]; + addr += (c == 4) ? 13 : 1; + } + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + for (c = 0; c < 16; c++) + { + *(uint8_t *)&svga->vram[addr] = tgui->copy_latch[c]; + addr += ((c & 3) == 3) ? 13 : 1; + } + break; + } +} + +static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]}; + uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; + uint16_t mask = (tgui->ext_gdc_regs[7] << 8) | tgui->ext_gdc_regs[8]; + + cycles -= video_timing_write_w; + cycles_lost += video_timing_write_w; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + addr &= ~0xf; + + addr = dword_remap(addr); + svga->changedvram[addr >> 12] = changeframecount; + + val = (val >> 8) | (val << 8); + + switch (tgui->ext_gdc_regs[0] & 0xf) + { + /*8-bit mono->colour expansion, unmasked*/ + case 2: + for (c = 15; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0]; + addr += (c & 3) ? 1 : 13; + } + break; + + /*16-bit mono->colour expansion, unmasked*/ + case 3: + for (c = 15; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1]; + addr += (c & 3) ? 1 : 13; + } + break; + + /*8-bit mono->colour expansion, masked*/ + case 6: + for (c = 15; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[0]; + addr += (c & 3) ? 1 : 13; + } + break; + + /*16-bit mono->colour expansion, masked*/ + case 7: + for (c = 15; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1]; + addr += (c & 3) ? 1 : 13; + } + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + for (c = 0; c < 16; c++) + { + *(uint8_t *)&svga->vram[addr] = tgui->copy_latch[c]; + addr += ((c & 3) == 3) ? 13 : 1; + } + break; + } +} + +static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p) +{ + tgui_ext_linear_writew(addr, val, p); +} + +static void tgui_ext_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_write(addr, val, svga); +} +static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_writew(addr, val, svga); +} +static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_writel(addr, val, svga); +} + + enum { TGUI_BITBLT = 1 @@ -590,8 +1075,8 @@ enum 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 READ(addr, dat) if (tgui->accel.bpp == 0) dat = svga->vram[dword_remap(addr) & 0x1fffff]; \ + else dat = vram_w[dword_remap_w(addr) & 0xfffff]; #define MIX() do \ { \ @@ -607,18 +1092,15 @@ enum #define WRITE(addr, dat) if (tgui->accel.bpp == 0) \ { \ - svga->vram[addr & 0x1fffff] = dat; \ - svga->changedvram[((addr) & 0x1fffff) >> 12] = changeframecount; \ + svga->vram[dword_remap(addr) & 0x1fffff] = dat; \ + svga->changedvram[(dword_remap(addr) & 0x1fffff) >> 12] = changeframecount; \ } \ else \ { \ - vram_w[addr & 0xfffff] = dat; \ - svga->changedvram[((addr) & 0xfffff) >> 11] = changeframecount; \ + vram_w[dword_remap_w(addr) & 0xfffff] = dat; \ + svga->changedvram[(dword_remap_w(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; @@ -634,7 +1116,7 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) if (tgui->accel.bpp == 0) trans_col &= 0xff; - if (count != -1 && !tgui->accel.x) + if (count != -1 && !tgui->accel.x && (tgui->accel.flags & TGUI_SRCMONO)) { count -= tgui->accel.offset; cpu_dat <<= tgui->accel.offset; @@ -714,8 +1196,9 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) { // 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); - + { + tgui->write_blitter = 1; + } if (tgui->accel.use_src) return; } @@ -767,8 +1250,7 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) { 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); + tgui->write_blitter = 0; } return; } @@ -784,7 +1266,9 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) { // 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); + { + tgui->write_blitter = 1; + } // pclog(" %i\n", tgui->accel.command); if (tgui->accel.use_src) @@ -828,8 +1312,7 @@ void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) { 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); + tgui->write_blitter = 0; } return; } @@ -1245,24 +1728,33 @@ 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); + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_BYTE); + else + svga_write_linear(addr, val, svga); } 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); + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_WORD); + else + svga_writew_linear(addr, val, svga); } 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); + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_LONG); + else + svga_writel_linear(addr, val, svga); } void tgui_add_status_info(char *s, int max_len, void *p) @@ -1308,6 +1800,32 @@ static device_config_t tgui9440_config[] = } }; +device_t tgui9400cxi_device = +{ + "Trident TGUI 9400CXi", + 0, + tgui9400cxi_init, + tgui_close, + tgui9400cxi_available, + tgui_speed_changed, + tgui_force_redraw, + tgui_add_status_info, + tgui9440_config +}; + +device_t tgui9400cxi_elx_device = +{ + "Trident TGUI 9400CXi (Elonex PC-425X)", + 0, + tgui9400cxi_elx_init, + tgui_close, + tgui9400cxi_available, + tgui_speed_changed, + tgui_force_redraw, + tgui_add_status_info, + tgui9440_config +}; + device_t tgui9440_device = { "Trident TGUI 9440", diff --git a/src/vid_tgui9440.h b/src/vid_tgui9440.h index 828562d..66db2d0 100644 --- a/src/vid_tgui9440.h +++ b/src/vid_tgui9440.h @@ -1 +1,3 @@ +extern device_t tgui9400cxi_device; +extern device_t tgui9400cxi_elx_device; extern device_t tgui9440_device; diff --git a/src/vid_tvga.c b/src/vid_tvga.c index e3a3df0..6a42ac4 100644 --- a/src/vid_tvga.c +++ b/src/vid_tvga.c @@ -11,6 +11,12 @@ #include "vid_tkd8001_ramdac.h" #include "vid_tvga.h" +enum +{ + TVGA_8900D = 0x33, + TVGA_9000 = 0x23 +}; + typedef struct tvga_t { mem_mapping_t linear_mapping; @@ -28,6 +34,8 @@ typedef struct tvga_t int vram_size; uint32_t vram_mask; + + uint8_t id; } tvga_t; static uint8_t crtc_mask[0x40] = @@ -67,7 +75,7 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) break; case 0xd: if (tvga->oldmode) - tvga->oldctrl2 = val; + tvga->oldctrl2 = val; else { tvga->newctrl2 = val; @@ -76,7 +84,10 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) break; case 0xE: if (tvga->oldmode) + { tvga->oldctrl1 = val; + svga_recalctimings(svga); + } else { svga->seqregs[0xe] = val ^ 2; @@ -88,12 +99,25 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - tkd8001_ramdac_out(addr, val, &tvga->ramdac, svga); - return; + if (tvga->id != TVGA_9000) + { + tkd8001_ramdac_out(addr, val, &tvga->ramdac, svga); + return; + } + break; case 0x3CF: switch (svga->gdcaddr & 15) { + case 0x6: + old = svga->gdcreg[6]; + svga_out(addr, val, svga); + if ((old & 0xc) != 0 && (val & 0xc) == 0) + { + /*override mask - TVGA supports linear 128k at A0000*/ + svga->banked_mask = 0x1ffff; + } + return; case 0xE: svga->gdcreg[0xe] = val ^ 2; tvga->tvga_3d9 = svga->gdcreg[0xe] & 0xf; @@ -128,7 +152,7 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) switch (svga->crtcreg) { case 0x1e: - svga->vrammask = (val & 0x80) ? tvga->vram_mask : 0x3ffff; + svga->vram_display_mask = (val & 0x80) ? tvga->vram_mask : 0x3ffff; break; } return; @@ -146,6 +170,16 @@ void tvga_out(uint16_t addr, uint8_t val, void *p) tvga_recalcbanking(tvga); } return; + case 0x3DB: + if (tvga->id == TVGA_8900D) + { + /*3db appears to be a 4 bit clock select register on 8900D*/ + svga->miscout = (svga->miscout & ~0x0c) | ((val & 3) << 2); + tvga->newctrl2 = (tvga->newctrl2 & ~0x01) | ((val & 4) >> 2); + tvga->oldctrl1 = (tvga->oldctrl1 & ~0x10) | ((val & 8) << 1); + svga_recalctimings(svga); + } + break; } svga_out(addr, val, svga); } @@ -166,7 +200,7 @@ uint8_t tvga_in(uint16_t addr, void *p) { // printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); tvga->oldmode = 0; - return 0x33; /*TVGA8900D*/ + return tvga->id; } if ((svga->seqaddr & 0xf) == 0xc) { @@ -185,7 +219,9 @@ uint8_t tvga_in(uint16_t addr, void *p) } break; case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: - return tkd8001_ramdac_in(addr, &tvga->ramdac, svga); + if (tvga->id != TVGA_9000) + return tkd8001_ramdac_in(addr, &tvga->ramdac, svga); + break; case 0x3D4: return svga->crtcreg; case 0x3D5: @@ -217,6 +253,9 @@ static void tvga_recalcbanking(tvga_t *tvga) void tvga_recalctimings(svga_t *svga) { tvga_t *tvga = (tvga_t *)svga->p; + int clksel; + int high_res_256 = 0; + 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*/ @@ -246,18 +285,43 @@ void tvga_recalctimings(svga_t *svga) if (svga->interlace) svga->rowoffset >>= 1; - switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4)) + if (tvga->id == TVGA_8900D) + clksel = ((svga->miscout >> 2) & 3) | ((tvga->newctrl2 & 0x01) << 2) | ((tvga->oldctrl1 & 0x10) >> 1); + else + clksel = ((svga->miscout >> 2) & 3) | ((tvga->newctrl2 & 0x01) << 2) | ((tvga->newctrl2 & 0x40) >> 3); + switch (clksel) { - 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; + case 0x2: svga->clock = (cpuclock * (double)(1ull << 32)) / 44900000.0; break; + case 0x3: svga->clock = (cpuclock * (double)(1ull << 32)) / 36000000.0; break; + case 0x4: svga->clock = (cpuclock * (double)(1ull << 32)) / 57272000.0; break; + case 0x5: svga->clock = (cpuclock * (double)(1ull << 32)) / 65000000.0; break; + case 0x6: svga->clock = (cpuclock * (double)(1ull << 32)) / 50350000.0; break; + case 0x7: svga->clock = (cpuclock * (double)(1ull << 32)) / 40000000.0; break; + case 0x8: svga->clock = (cpuclock * (double)(1ull << 32)) / 88000000.0; break; + case 0x9: svga->clock = (cpuclock * (double)(1ull << 32)) / 98000000.0; break; + case 0xa: svga->clock = (cpuclock * (double)(1ull << 32)) / 118800000.0; break; + case 0xb: svga->clock = (cpuclock * (double)(1ull << 32)) / 108000000.0; break; + case 0xc: svga->clock = (cpuclock * (double)(1ull << 32)) / 72000000.0; break; + case 0xd: svga->clock = (cpuclock * (double)(1ull << 32)) / 77000000.0; break; + case 0xe: svga->clock = (cpuclock * (double)(1ull << 32)) / 80000000.0; break; + case 0xf: svga->clock = (cpuclock * (double)(1ull << 32)) / 75000000.0; break; } - if (tvga->oldctrl2 & 0x10) + if (tvga->id == TVGA_9000) { + /*TVGA9000 doesn't seem to have support for a 'high res' 256 colour mode + (without the VGA pixel doubling). Instead it implements these modes by + doubling the horizontal pixel count and pixel clock. Hence we use a + basic heuristic to detect this*/ + if (svga->interlace) + high_res_256 = (svga->htotal * 8) > (svga->vtotal * 4); + else + high_res_256 = (svga->htotal * 8) > (svga->vtotal * 2); + } + if ((tvga->oldctrl2 & 0x10) || high_res_256) + { + if (high_res_256) + svga->hdisp /= 2; switch (svga->bpp) { case 8: @@ -280,30 +344,45 @@ void tvga_recalctimings(svga_t *svga) } } -void *tvga8900d_init() +static void *tvga_common_init(char *fn, uint32_t id, int vram_size) { tvga_t *tvga = malloc(sizeof(tvga_t)); memset(tvga, 0, sizeof(tvga_t)); - - tvga->vram_size = device_get_config_int("memory") << 10; + + tvga->vram_size = vram_size << 10; tvga->vram_mask = tvga->vram_size - 1; - - rom_init(&tvga->bios_rom, "roms/trident.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); - + tvga->id = id; + + rom_init(&tvga->bios_rom, fn, 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 void *tvga8900d_init() +{ + int vram_size = device_get_config_int("memory"); + + return tvga_common_init("trident.bin", TVGA_8900D, vram_size); +} +static void *tvga9000b_init() +{ + return tvga_common_init("tvga9000b/BIOS.BIN", TVGA_9000, 512); +} static int tvga8900d_available() { - return rom_present("roms/trident.bin"); + return rom_present("trident.bin"); +} +static int tvga9000b_available() +{ + return rom_present("tvga9000b/BIOS.BIN"); } void tvga_close(void *p) @@ -380,3 +459,15 @@ device_t tvga8900d_device = tvga_add_status_info, tvga_config }; +device_t tvga9000b_device = +{ + "Trident TVGA 9000B", + 0, + tvga9000b_init, + tvga_close, + tvga9000b_available, + tvga_speed_changed, + tvga_force_redraw, + tvga_add_status_info, + NULL +}; diff --git a/src/vid_tvga.h b/src/vid_tvga.h index d55ff65..c2c1019 100644 --- a/src/vid_tvga.h +++ b/src/vid_tvga.h @@ -1 +1,2 @@ extern device_t tvga8900d_device; +extern device_t tvga9000b_device; diff --git a/src/vid_vga.c b/src/vid_vga.c index 6f4d639..64bd67c 100644 --- a/src/vid_vga.c +++ b/src/vid_vga.c @@ -9,6 +9,8 @@ #include "vid_svga.h" #include "vid_vga.h" +svga_t *mb_vga = NULL; + typedef struct vga_t { svga_t svga; @@ -30,9 +32,11 @@ void vga_out(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x3D4: - svga->crtcreg = val & 0x1f; + svga->crtcreg = val & 0x3f; return; case 0x3D5: + if (svga->crtcreg & 0x20) + return; if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) return; if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) @@ -69,7 +73,10 @@ uint8_t vga_in(uint16_t addr, void *p) temp = svga->crtcreg; break; case 0x3D5: - temp = svga->crtc[svga->crtcreg]; + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg]; break; default: temp = svga_in(addr, svga); @@ -79,12 +86,36 @@ uint8_t vga_in(uint16_t addr, void *p) return temp; } +void vga_disable(void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + +// pclog("vga_disable\n"); + io_removehandler(0x03a0, 0x0040, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + mem_mapping_disable(&svga->mapping); +} + +void vga_enable(void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + +// pclog("vga_enable\n"); + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + if (!(svga->miscout & 1)) + io_sethandler(0x03a0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + mem_mapping_enable(&svga->mapping); +} + + 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); + rom_init(&vga->bios_rom, "ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ NULL, @@ -117,18 +148,22 @@ void *ps1vga_init() vga->svga.bpp = 8; vga->svga.miscout = 1; + mb_vga = &vga->svga; + return vga; } static int vga_available() { - return rom_present("roms/ibm_vga.bin"); + return rom_present("ibm_vga.bin"); } void vga_close(void *p) { vga_t *vga = (vga_t *)p; + mb_vga = NULL; + svga_close(&vga->svga); free(vga); diff --git a/src/vid_vga.h b/src/vid_vga.h index 3bf9459..cf58f72 100644 --- a/src/vid_vga.h +++ b/src/vid_vga.h @@ -1,2 +1,8 @@ extern device_t vga_device; extern device_t ps1vga_device; + +void vga_disable(void *p); +void vga_enable(void *p); + +struct svga_t; +extern struct svga_t *mb_vga; diff --git a/src/vid_voodoo.c b/src/vid_voodoo.c index b77a14a..4164908 100644 --- a/src/vid_voodoo.c +++ b/src/vid_voodoo.c @@ -10,1033 +10,33 @@ #include "video.h" #include "vid_svga.h" #include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_blitter.h" +#include "vid_voodoo_display.h" #include "vid_voodoo_dither.h" +#include "vid_voodoo_fb.h" +#include "vid_voodoo_fifo.h" +#include "vid_voodoo_reg.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "vid_voodoo_texture.h" -#ifdef MIN -#undef MIN -#endif -#ifdef ABS -#undef ABS -#endif -#ifdef CLAMP -#undef CLAMP -#endif -#define MIN(a, b) ((a) < (b) ? (a) : (b)) +rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; -#define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) -#define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) -#define LOD_MAX 8 - -#define TEX_DIRTY_SHIFT 10 - -#define TEX_CACHE_MAX 64 - -enum -{ - VOODOO_1 = 0, - VOODOO_SB50 = 1, - VOODOO_2 = 2 -}; - -static uint32_t texture_offset[LOD_MAX+3] = -{ - 0, - 256*256, - 256*256 + 128*128, - 256*256 + 128*128 + 64*64, - 256*256 + 128*128 + 64*64 + 32*32, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1, - 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1 + 1 -}; - -static int tris = 0; +int tris = 0; static uint64_t status_time = 0; -static uint64_t voodoo_time = 0; -static int voodoo_render_time[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[2]; - - 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[2]; - uint32_t tLOD[2]; - - uint32_t texBaseAddr[2], texBaseAddr1[2], texBaseAddr2[2], texBaseAddr38[2]; - - uint32_t tex_base[2][LOD_MAX+2]; - int tex_width[2]; - int tex_w_mask[2][LOD_MAX+2]; - int tex_w_nmask[2][LOD_MAX+2]; - int tex_h_mask[2][LOD_MAX+2]; - int tex_shift[2][LOD_MAX+2]; - int tex_lod[2][LOD_MAX+2]; - int tex_entry[2]; - int detail_max[2], detail_bias[2], detail_scale[2]; - - uint32_t draw_offset, aux_offset; - - int tformat[2]; - - int clipLeft, clipRight, clipLowY, clipHighY; - - int sign; - - uint32_t front_offset; - - uint32_t swapbufferCMD; - - uint32_t stipple; -} voodoo_params_t; - -typedef struct texture_t -{ - uint32_t base; - uint32_t tLOD; - volatile int refcount, refcount_r[2]; - int is16; - uint32_t palette_checksum; - uint32_t addr_start, addr_end; - uint32_t *data; -} texture_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; - uint32_t fbiInit5, fbiInit6, fbiInit7; /*Voodoo 2*/ - - 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; - int block_width; - - uint8_t *fb_mem, *tex_mem[2]; - uint16_t *tex_mem_w[2]; - - int rgb_sel; - - uint32_t trexInit1[2]; - - int swap_count; - - int disp_buffer, draw_buffer; - int timer_count; - - int line; - svga_t *svga; - - uint32_t backPorch; - uint32_t videoDimensions; - uint32_t hSync, vSync; - - int h_total, v_total, v_disp; - int h_disp; - int v_retrace; - - struct - { - uint32_t y[4], i[4], q[4]; - } nccTable[2][2]; - - rgba_u palette[2][256]; - - rgba_u ncc_lookup[2][2][256]; - int ncc_dirty[2]; - - 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], texel_count[2], tri_count, frame_count; - int pixel_count_old[2], texel_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; - - int dual_tmus; - int type; - - 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; - - uint32_t cmdfifo_base, cmdfifo_end; - int cmdfifo_rp; - volatile int cmdfifo_depth_rd, cmdfifo_depth_wr; - uint32_t cmdfifo_amin, cmdfifo_amax; - - uint32_t sSetupMode; - struct - { - float sVx, sVy; - float sRed, sGreen, sBlue, sAlpha; - float sVz, sWb; - float sW0, sS0, sT0; - float sW1, sS1, sT1; - } verts[4]; - int vertex_num; - int num_verticies; - - int flush; - - int scrfilter; - int scrfilterEnabled; - int scrfilterThreshold; - int scrfilterThresholdOld; - - uint32_t last_write_addr; - - uint32_t fbiPixelsIn; - uint32_t fbiChromaFail; - uint32_t fbiZFuncFail; - uint32_t fbiAFuncFail; - uint32_t fbiPixelsOut; - - uint32_t bltSrcBaseAddr; - uint32_t bltDstBaseAddr; - int bltSrcXYStride, bltDstXYStride; - uint32_t bltSrcChromaRange, bltDstChromaRange; - int bltSrcChromaMinR, bltSrcChromaMinG, bltSrcChromaMinB; - int bltSrcChromaMaxR, bltSrcChromaMaxG, bltSrcChromaMaxB; - int bltDstChromaMinR, bltDstChromaMinG, bltDstChromaMinB; - int bltDstChromaMaxR, bltDstChromaMaxG, bltDstChromaMaxB; - - int bltClipRight, bltClipLeft; - int bltClipHighY, bltClipLowY; - - int bltSrcX, bltSrcY; - int bltDstX, bltDstY; - int bltSizeX, bltSizeY; - int bltRop[4]; - uint16_t bltColorFg, bltColorBg; - - uint32_t bltCommand; - - struct - { - int dst_x, dst_y; - int cur_x; - int size_x, size_y; - int x_dir, y_dir; - int dst_stride; - } blt; - - 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; - int buffer_cutoff; - - int read_time, write_time, burst_time; - - int wake_timer; - - uint8_t thefilter[256][256]; // pixel filter, feeding from one or two - uint8_t thefilterg[256][256]; // for green - uint8_t thefilterb[256][256]; // for blue - - /* the voodoo adds purple lines for some reason */ - uint16_t purpleline[256][3]; - - texture_t texture_cache[2][TEX_CACHE_MAX]; - uint8_t texture_present[2][4096]; - int texture_last_removed; - - uint32_t palette_checksum[2]; - int palette_dirty[2]; - - int use_recompiler; - void *codegen_data; -} voodoo_t; - -static inline void wait_for_render_thread_idle(voodoo_t *voodoo); - -enum -{ - SST_status = 0x000, - SST_intrCtrl = 0x004, - - 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_userIntrCMD = 0x13c, - SST_stipple = 0x140, - 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_cmdFifoBaseAddr = 0x1e0, - SST_cmdFifoBump = 0x1e4, - SST_cmdFifoRdPtr = 0x1e8, - SST_cmdFifoAMin = 0x1ec, - SST_cmdFifoAMax = 0x1f0, - SST_cmdFifoDepth = 0x1f4, - SST_cmdFifoHoles = 0x1f8, - - SST_fbiInit4 = 0x200, - SST_vRetrace = 0x204, - 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_scrFilter = 0x230, - - SST_hvRetrace = 0x240, - SST_fbiInit5 = 0x244, - SST_fbiInit6 = 0x248, - SST_fbiInit7 = 0x24c, - - SST_sSetupMode = 0x260, - SST_sVx = 0x264, - SST_sVy = 0x268, - SST_sARGB = 0x26c, - SST_sRed = 0x270, - SST_sGreen = 0x274, - SST_sBlue = 0x278, - SST_sAlpha = 0x27c, - SST_sVz = 0x280, - SST_sWb = 0x284, - SST_sW0 = 0x288, - SST_sS0 = 0x28c, - SST_sT0 = 0x290, - SST_sW1 = 0x294, - SST_sS1 = 0x298, - SST_sT1 = 0x29c, - - SST_sDrawTriCMD = 0x2a0, - SST_sBeginTriCMD = 0x2a4, - - SST_bltSrcBaseAddr = 0x2c0, - SST_bltDstBaseAddr = 0x2c4, - SST_bltXYStrides = 0x2c8, - SST_bltSrcChromaRange = 0x2cc, - SST_bltDstChromaRange = 0x2d0, - SST_bltClipX = 0x2d4, - SST_bltClipY = 0x2d8, - - SST_bltSrcXY = 0x2e0, - SST_bltDstXY = 0x2e4, - SST_bltSize = 0x2e8, - SST_bltRop = 0x2ec, - SST_bltColor = 0x2f0, - - SST_bltCommand = 0x2f8, - SST_bltData = 0x2fc, - - SST_textureMode = 0x300, - SST_tLOD = 0x304, - SST_tDetail = 0x308, - 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_DEPTH_SOURCE = (1 << 20), - - 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_APAL8 = 0x6, - TEX_ARGB8332 = 0x8, - TEX_A8Y4I2Q2 = 0x9, - 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), - TEXTUREMODE_TRILINEAR = (1 << 30) -}; - -enum -{ - FBIINIT0_VGA_PASS = 1, - FBIINIT0_GRAPHICS_RESET = (1 << 1) -}; - -enum -{ - FBIINIT3_REMAP = 1 -}; - -enum -{ - FBIINIT7_CMDFIFO_ENABLE = (1 << 8) -}; - -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, - CC_MSELECT_TEXRGB = 5 -}; - -enum -{ - CCA_MSELECT_ZERO = 0, - CCA_MSELECT_ALOCAL = 1, - CCA_MSELECT_AOTHER = 2, - CCA_MSELECT_ALOCAL2 = 3, - CCA_MSELECT_TEX = 4 -}; - -enum -{ - TC_MSELECT_ZERO = 0, - TC_MSELECT_CLOCAL = 1, - TC_MSELECT_AOTHER = 2, - TC_MSELECT_ALOCAL = 3, - TC_MSELECT_DETAIL = 4, - TC_MSELECT_LOD_FRAC = 5 -}; - -enum -{ - TCA_MSELECT_ZERO = 0, - TCA_MSELECT_CLOCAL = 1, - TCA_MSELECT_AOTHER = 2, - TCA_MSELECT_ALOCAL = 3, - TCA_MSELECT_DETAIL = 4, - TCA_MSELECT_LOD_FRAC = 5 -}; - -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_W = 0x18, - FOG_CONSTANT = 0x20 -}; - -enum -{ - LOD_ODD = (1 << 18), - LOD_SPLIT = (1 << 19), - LOD_S_IS_WIDER = (1 << 20), - LOD_TMIRROR_S = (1 << 28), - LOD_TMIRROR_T = (1 << 29) -}; -enum -{ - CMD_INVALID = 0, - CMD_DRAWTRIANGLE, - CMD_FASTFILL, - CMD_SWAPBUF -}; - -enum -{ - FBZCP_TEXTURE_ENABLED = (1 << 27) -}; - -enum -{ - BLTCMD_SRC_TILED = (1 << 14), - BLTCMD_DST_TILED = (1 << 15) -}; - -#define TEXTUREMODE_MASK 0x3ffff000 -#define TEXTUREMODE_PASSTHROUGH 0 - -#define TEXTUREMODE_LOCAL_MASK 0x00643000 -#define TEXTUREMODE_LOCAL 0x00241000 - -static void voodoo_threshold_check(voodoo_t *voodoo); - -static void voodoo_update_ncc(voodoo_t *voodoo, int tmu) -{ - 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 i_r, i_g, i_b; - int q_r, q_g, q_b; - - y = (voodoo->nccTable[tmu][tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; - - i_r = (voodoo->nccTable[tmu][tbl].i[i] >> 18) & 0x1ff; - if (i_r & 0x100) - i_r |= 0xfffffe00; - i_g = (voodoo->nccTable[tmu][tbl].i[i] >> 9) & 0x1ff; - if (i_g & 0x100) - i_g |= 0xfffffe00; - i_b = voodoo->nccTable[tmu][tbl].i[i] & 0x1ff; - if (i_b & 0x100) - i_b |= 0xfffffe00; - - q_r = (voodoo->nccTable[tmu][tbl].q[q] >> 18) & 0x1ff; - if (q_r & 0x100) - q_r |= 0xfffffe00; - q_g = (voodoo->nccTable[tmu][tbl].q[q] >> 9) & 0x1ff; - if (q_g & 0x100) - q_g |= 0xfffffe00; - q_b = voodoo->nccTable[tmu][tbl].q[q] & 0x1ff; - if (q_b & 0x100) - q_b |= 0xfffffe00; - - voodoo->ncc_lookup[tmu][tbl][col].rgba.r = CLAMP(y + i_r + q_r); - voodoo->ncc_lookup[tmu][tbl][col].rgba.g = CLAMP(y + i_g + q_g); - voodoo->ncc_lookup[tmu][tbl][col].rgba.b = CLAMP(y + i_b + q_b); - voodoo->ncc_lookup[tmu][tbl][col].rgba.a = 0xff; - } - } -} - -#define TRIPLE_BUFFER ((voodoo->fbiInit2 & 0x10) || (voodoo->fbiInit5 & 0x600) == 0x400) -static void voodoo_recalc(voodoo_t *voodoo) +void voodoo_recalc(voodoo_t *voodoo) { uint32_t buffer_offset = ((voodoo->fbiInit2 >> 11) & 511) * 4096; - + + if (voodoo->type >= VOODOO_BANSHEE) + return; + voodoo->params.front_offset = voodoo->disp_buffer*buffer_offset; voodoo->back_offset = voodoo->draw_buffer*buffer_offset; @@ -1078,7 +78,7 @@ static void voodoo_recalc(voodoo_t *voodoo) default: fatal("voodoo_recalc : unknown lfb source\n"); } - + switch (voodoo->params.fbzMode & FBZ_DRAW_MASK) { case FBZ_DRAW_FRONT: @@ -1093,4523 +93,21 @@ static void voodoo_recalc(voodoo_t *voodoo) default: fatal("voodoo_recalc : unknown draw buffer\n"); } - + voodoo->block_width = ((voodoo->fbiInit1 >> 4) & 15) * 2; if (voodoo->fbiInit6 & (1 << 30)) voodoo->block_width += 1; if (voodoo->fbiInit1 & (1 << 24)) voodoo->block_width += 32; voodoo->row_width = voodoo->block_width * 32 * 2; + voodoo->params.row_width = voodoo->row_width; + voodoo->aux_row_width = voodoo->row_width; + voodoo->params.aux_row_width = voodoo->aux_row_width; /* 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 tmu) -{ - int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3; - int width = 256, height = 256; - int shift = 8; - int lod; - uint32_t base = voodoo->params.texBaseAddr[tmu]; - int tex_lod = 0; - - if (voodoo->params.tLOD[tmu] & LOD_S_IS_WIDER) - height >>= aspect; - else - { - width >>= aspect; - shift -= aspect; - } - - if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD)) - { - width >>= 1; - height >>= 1; - shift--; - tex_lod++; - } - - for (lod = 0; lod <= LOD_MAX+1; lod++) - { - if (!width) - width = 1; - if (!height) - height = 1; - if (shift < 0) - shift = 0; - voodoo->params.tex_base[tmu][lod] = base; - voodoo->params.tex_w_mask[tmu][lod] = width - 1; - voodoo->params.tex_w_nmask[tmu][lod] = ~(width - 1); - voodoo->params.tex_h_mask[tmu][lod] = height - 1; - voodoo->params.tex_shift[tmu][lod] = shift; - voodoo->params.tex_lod[tmu][lod] = tex_lod; - - if (!(voodoo->params.tLOD[tmu] & LOD_SPLIT) || ((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) || (!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD))) - { - if (!(voodoo->params.tLOD[tmu] & LOD_ODD) || lod != 0) - { - if (voodoo->params.tformat[tmu] & 8) - base += width * height * 2; - else - base += width * height; - - if (voodoo->params.tLOD[tmu] & LOD_SPLIT) - { - width >>= 2; - height >>= 2; - shift -= 2; - tex_lod += 2; - } - else - { - width >>= 1; - height >>= 1; - shift--; - tex_lod++; - } - } - } - } - - voodoo->params.tex_width[tmu] = width; -} - -#define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24)) - -static void use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) -{ - int c; - int lod; - int lod_min, lod_max; - uint32_t addr = 0, addr_end; - uint32_t palette_checksum; - - lod_min = (params->tLOD[tmu] >> 2) & 15; - lod_max = (params->tLOD[tmu] >> 8) & 15; - - if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) - { - if (voodoo->palette_dirty[tmu]) - { - palette_checksum = 0; - - for (c = 0; c < 256; c++) - palette_checksum ^= voodoo->palette[tmu][c].u; - - voodoo->palette_checksum[tmu] = palette_checksum; - voodoo->palette_dirty[tmu] = 0; - } - else - palette_checksum = voodoo->palette_checksum[tmu]; - } - else - palette_checksum = 0; - - /*Try to find texture in cache*/ - for (c = 0; c < TEX_CACHE_MAX; c++) - { - if (voodoo->texture_cache[tmu][c].base == params->texBaseAddr[tmu] && - voodoo->texture_cache[tmu][c].tLOD == (params->tLOD[tmu] & 0xf00fff) && - voodoo->texture_cache[tmu][c].palette_checksum == palette_checksum) - { - params->tex_entry[tmu] = c; - voodoo->texture_cache[tmu][c].refcount++; - - return; - } - } - - /*Texture not found, search for unused texture*/ - do - { - for (c = 0; c < TEX_CACHE_MAX; c++) - { - voodoo->texture_last_removed++; - voodoo->texture_last_removed &= (TEX_CACHE_MAX-1); - if (voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[0] && - (voodoo->render_threads == 1 || voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[1])) - break; - } - if (c == TEX_CACHE_MAX) - wait_for_render_thread_idle(voodoo); - } while (c == TEX_CACHE_MAX); - if (c == TEX_CACHE_MAX) - fatal("Texture cache full!\n"); - - c = voodoo->texture_last_removed; - - voodoo->texture_cache[tmu][c].base = params->texBaseAddr[tmu]; - voodoo->texture_cache[tmu][c].tLOD = params->tLOD[tmu] & 0xf00fff; - - lod_min = (params->tLOD[tmu] >> 2) & 15; - lod_max = (params->tLOD[tmu] >> 8) & 15; -// pclog(" add new texture to %i tformat=%i %08x LOD=%i-%i\n", c, voodoo->params.tformat[tmu], params->texBaseAddr[tmu], lod_min, lod_max); - - for (lod = lod_min; lod <= lod_max; lod++) - { - uint32_t *base = &voodoo->texture_cache[tmu][c].data[texture_offset[lod]]; - uint32_t tex_addr = params->tex_base[tmu][lod] & voodoo->texture_mask; - int x, y; - int shift = 8 - params->tex_lod[tmu][lod]; - rgba_u *pal; - - //pclog(" LOD %i : %08x - %08x %i %i,%i\n", lod, params->tex_base[tmu][lod] & voodoo->texture_mask, addr, voodoo->params.tformat[tmu], voodoo->params.tex_w_mask[tmu][lod],voodoo->params.tex_h_mask[tmu][lod]); - - - switch (params->tformat[tmu]) - { - case TEX_RGB332: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(rgb332[dat].r, rgb332[dat].g, rgb332[dat].b, 0xff); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_Y4I2Q2: - pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_A8: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(dat, dat, dat, dat); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_I8: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(dat, dat, dat, 0xff); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_AI8: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba((dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0xf0) | ((dat >> 4) & 0x0f)); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_PAL8: - pal = voodoo->palette[tmu]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_APAL8: - pal = voodoo->palette[tmu]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; - - int r = ((pal[dat].rgba.r & 3) << 6) | ((pal[dat].rgba.g & 0xf0) >> 2) | (pal[dat].rgba.r & 3); - int g = ((pal[dat].rgba.g & 0xf) << 4) | ((pal[dat].rgba.b & 0xc0) >> 4) | ((pal[dat].rgba.g & 0xf) >> 2); - int b = ((pal[dat].rgba.b & 0x3f) << 2) | ((pal[dat].rgba.b & 0x30) >> 4); - int a = (pal[dat].rgba.r & 0xfc) | ((pal[dat].rgba.r & 0xc0) >> 6); - - base[x] = makergba(r, g, b, a); - } - tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); - base += (1 << shift); - } - break; - - case TEX_ARGB8332: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(rgb332[dat & 0xff].r, rgb332[dat & 0xff].g, rgb332[dat & 0xff].b, dat >> 8); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_A8Y4I2Q2: - pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_R5G6B5: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(rgb565[dat].r, rgb565[dat].g, rgb565[dat].b, 0xff); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_ARGB1555: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(argb1555[dat].r, argb1555[dat].g, argb1555[dat].b, argb1555[dat].a); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_ARGB4444: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(argb4444[dat].r, argb4444[dat].g, argb4444[dat].b, argb4444[dat].a); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_A8I8: - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(dat & 0xff, dat & 0xff, dat & 0xff, dat >> 8); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - case TEX_APAL88: - pal = voodoo->palette[tmu]; - for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) - { - for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) - { - uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; - - base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); - } - tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); - base += (1 << shift); - } - break; - - default: - fatal("Unknown texture format %i\n", params->tformat[tmu]); - } - } - - voodoo->texture_cache[tmu][c].is16 = voodoo->params.tformat[tmu] & 8; - - if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL88) - voodoo->texture_cache[tmu][c].palette_checksum = palette_checksum; - else - voodoo->texture_cache[tmu][c].palette_checksum = 0; - - addr = voodoo->params.tex_base[tmu][lod_min]; - addr_end = voodoo->params.tex_base[tmu][lod_max+1]; - voodoo->texture_cache[tmu][c].addr_start = addr; - voodoo->texture_cache[tmu][c].addr_end = addr_end; - for (; addr <= addr_end; addr += (1 << TEX_DIRTY_SHIFT)) - voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; - - params->tex_entry[tmu] = c; - voodoo->texture_cache[tmu][c].refcount++; -} - -static void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) -{ - int wait_for_idle = 0; - int c; - - memset(voodoo->texture_present[tmu], 0, sizeof(voodoo->texture_present[0])); -// pclog("Evict %08x %i\n", dirty_addr, sizeof(voodoo->texture_present)); - for (c = 0; c < TEX_CACHE_MAX; c++) - { - if (voodoo->texture_cache[tmu][c].base != -1) - { - int addr_start = voodoo->texture_cache[tmu][c].addr_start; - int addr_end = voodoo->texture_cache[tmu][c].addr_end; - - if (dirty_addr >= (addr_start & voodoo->texture_mask & ~0x3ff) && dirty_addr < (((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff)) - { -// pclog(" Evict texture %i %08x\n", c, voodoo->texture_cache[tmu][c].base); - - if (voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[0] || - (voodoo->render_threads == 2 && voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[1])) - wait_for_idle = 1; - - voodoo->texture_cache[tmu][c].base = -1; - } - else - { - for (; addr_start <= addr_end; addr_start += (1 << TEX_DIRTY_SHIFT)) - voodoo->texture_present[tmu][(addr_start & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; - } - } - } - if (wait_for_idle) - wait_for_render_thread_idle(voodoo); -} - -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[2]; - int64_t base_w; - int lod; - int lod_min[2], lod_max[2]; - int dx1, dx2; - int y, yend, ydir; - int32_t dxAB, dxAC, dxBC; - int tex_b[2], tex_g[2], tex_r[2], tex_a[2]; - int tex_s, tex_t; - int clamp_s[2], clamp_t[2]; - - int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; - - uint32_t *tex[2][LOD_MAX+1]; - int tformat; - - int *tex_w_mask[2]; - int *tex_h_mask[2]; - int *tex_shift[2]; - int *tex_lod[2]; - - 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 tmu1_s, tmu1_t; - int64_t tmu1_w; - int64_t w; - - int pixel_count, texel_count; - int x, x2; - - uint32_t w_depth; - - float log_temp; - uint32_t ebp_store; - uint32_t texBaseAddr; - - int lod_frac[2]; -} 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, int tmu) -{ - uint32_t dat; - - if (texture_state->s & ~texture_state->w_mask) - { - if (state->clamp_s[tmu]) - { - 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[tmu]) - { - 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; - } - - dat = state->tex[tmu][state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; - - state->tex_b[tmu] = dat & 0xff; - state->tex_g[tmu] = (dat >> 8) & 0xff; - state->tex_r[tmu] = (dat >> 16) & 0xff; - state->tex_a[tmu] = (dat >> 24) & 0xff; -} - -#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, int tmu, int x) -{ - rgba_u 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[tmu]) - { - 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[tmu]) - { - if (_t < 0) - _t = 0; - if (_t > texture_state->h_mask) - _t = texture_state->h_mask; - } - else - _t &= texture_state->h_mask; - } - dat[c].u = state->tex[tmu][state->lod][_s + (_t << texture_state->tex_shift)]; - } - } - else - { - dat[0].u = state->tex[tmu][state->lod][s + (t << texture_state->tex_shift)]; - dat[1].u = state->tex[tmu][state->lod][s + 1 + (t << texture_state->tex_shift)]; - dat[2].u = state->tex[tmu][state->lod][s + ((t + 1) << texture_state->tex_shift)]; - dat[3].u = state->tex[tmu][state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; - } - - state->tex_r[tmu] = (dat[0].rgba.r * d[0] + dat[1].rgba.r * d[1] + dat[2].rgba.r * d[2] + dat[3].rgba.r * d[3]) >> 8; - state->tex_g[tmu] = (dat[0].rgba.g * d[0] + dat[1].rgba.g * d[1] + dat[2].rgba.g * d[2] + dat[3].rgba.g * d[3]) >> 8; - state->tex_b[tmu] = (dat[0].rgba.b * d[0] + dat[1].rgba.b * d[1] + dat[2].rgba.b * d[2] + dat[3].rgba.b * d[3]) >> 8; - state->tex_a[tmu] = (dat[0].rgba.a * d[0] + dat[1].rgba.a * d[1] + dat[2].rgba.a * d[2] + dat[3].rgba.a * d[3]) >> 8; -} - -static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) -{ - voodoo_texture_state_t texture_state; - int d[4]; - int s, t; - int tex_lod = state->tex_lod[tmu][state->lod]; - - texture_state.w_mask = state->tex_w_mask[tmu][state->lod]; - texture_state.h_mask = state->tex_h_mask[tmu][state->lod]; - texture_state.tex_shift = 8 - tex_lod; - - if (params->tLOD[tmu] & LOD_TMIRROR_S) - { - if (state->tex_s & 0x1000) - state->tex_s = ~state->tex_s; - } - if (params->tLOD[tmu] & LOD_TMIRROR_T) - { - if (state->tex_t & 0x1000) - state->tex_t = ~state->tex_t; - } - - if (voodoo->bilinear_enabled && params->textureMode[tmu] & 6) - { - int _ds, dt; - - state->tex_s -= 1 << (3+tex_lod); - state->tex_t -= 1 << (3+tex_lod); - - s = state->tex_s >> tex_lod; - t = state->tex_t >> tex_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, tmu, x); - - -/* 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+tex_lod); - t = state->tex_t >> (4+tex_lod); - - texture_state.s = s; - texture_state.t = t; - tex_read(state, &texture_state, tmu); - -/* 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;*/ - } -} - -static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) -{ - if (params->textureMode[tmu] & 1) - { - int64_t _w = 0; - - if (tmu) - { - if (state->tmu1_w) - _w = (int64_t)((1ULL << 48) / state->tmu1_w); - state->tex_s = (int32_t)(((((state->tmu1_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); - state->tex_t = (int32_t)(((((state->tmu1_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); - } - else - { - if (state->tmu0_w) - _w = (int64_t)((1ULL << 48) / state->tmu0_w); - state->tex_s = (int32_t)(((((state->tmu0_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); - state->tex_t = (int32_t)(((((state->tmu0_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); - } - - state->lod = state->tmu[tmu].lod + (fastlog(_w) - (19 << 8)); - } - else - { - if (tmu) - { - state->tex_s = (int32_t)(state->tmu1_s >> (14+14)); - state->tex_t = (int32_t)(state->tmu1_t >> (14+14)); - } - 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[tmu].lod; - } - - if (state->lod < state->lod_min[tmu]) - state->lod = state->lod_min[tmu]; - else if (state->lod > state->lod_max[tmu]) - state->lod = state->lod_max[tmu]; - state->lod_frac[tmu] = state->lod & 0xff; - state->lod >>= 8; - - voodoo_get_texture(voodoo, params, state, tmu, x); -} - -#define DEPTH_TEST(comp_depth) \ - do \ - { \ - switch (depth_op) \ - { \ - case DEPTHOP_NEVER: \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - case DEPTHOP_LESSTHAN: \ - if (!(comp_depth < old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_EQUAL: \ - if (!(comp_depth == old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_LESSTHANEQUAL: \ - if (!(comp_depth <= old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_GREATERTHAN: \ - if (!(comp_depth > old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_NOTEQUAL: \ - if (!(comp_depth != old_depth)) \ - { \ - voodoo->fbiZFuncFail++; \ - goto skip_pixel; \ - } \ - break; \ - case DEPTHOP_GREATERTHANEQUAL: \ - if (!(comp_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, w) \ - 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 = 0; \ - int fog_idx; \ - \ - 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; \ - } \ - \ - switch (params->fogMode & (FOG_Z|FOG_ALPHA)) \ - { \ - case 0: \ - 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; \ - break; \ - case FOG_Z: \ - fog_a = (z >> 20) & 0xff; \ - break; \ - case FOG_ALPHA: \ - fog_a = CLAMP(ia >> 12); \ - break; \ - case FOG_W: \ - fog_a = CLAMP((w >> 32) & 0xff); \ - break; \ - } \ - 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 = 0, newdest_g = 0, newdest_b = 0; \ - \ - 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: \ - fatal("AFUNC_ACOLORBEFOREFOG\n"); \ - 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 tc_zero_other (params->textureMode[0] & (1 << 12)) -#define tc_sub_clocal (params->textureMode[0] & (1 << 13)) -#define tc_mselect ((params->textureMode[0] >> 14) & 7) -#define tc_reverse_blend (params->textureMode[0] & (1 << 17)) -#define tc_add_clocal (params->textureMode[0] & (1 << 18)) -#define tc_add_alocal (params->textureMode[0] & (1 << 19)) -#define tc_invert_output (params->textureMode[0] & (1 << 20)) -#define tca_zero_other (params->textureMode[0] & (1 << 21)) -#define tca_sub_clocal (params->textureMode[0] & (1 << 22)) -#define tca_mselect ((params->textureMode[0] >> 23) & 7) -#define tca_reverse_blend (params->textureMode[0] & (1 << 26)) -#define tca_add_clocal (params->textureMode[0] & (1 << 27)) -#define tca_add_alocal (params->textureMode[0] & (1 << 28)) -#define tca_invert_output (params->textureMode[0] & (1 << 29)) - -#define tc_sub_clocal_1 (params->textureMode[1] & (1 << 13)) -#define tc_mselect_1 ((params->textureMode[1] >> 14) & 7) -#define tc_reverse_blend_1 (params->textureMode[1] & (1 << 17)) -#define tc_add_clocal_1 (params->textureMode[1] & (1 << 18)) -#define tc_add_alocal_1 (params->textureMode[1] & (1 << 19)) -#define tca_sub_clocal_1 (params->textureMode[1] & (1 << 22)) -#define tca_mselect_1 ((params->textureMode[1] >> 23) & 7) -#define tca_reverse_blend_1 (params->textureMode[1] & (1 << 26)) -#define tca_add_clocal_1 (params->textureMode[1] & (1 << 27)) -#define tca_add_alocal_1 (params->textureMode[1] & (1 << 28)) - -#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) - -/*Perform texture fetch and blending for both TMUs*/ -static inline void voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x) -{ - int r,g,b,a; - int c_reverse, a_reverse; -// int c_reverse1, a_reverse1; - int factor_r = 0, factor_g = 0, factor_b = 0, factor_a = 0; - - voodoo_tmu_fetch(voodoo, params, state, 1, x); - - if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) - { - c_reverse = tc_reverse_blend; - a_reverse = tca_reverse_blend; - } - else - { - c_reverse = !tc_reverse_blend; - a_reverse = !tca_reverse_blend; - } -/* c_reverse1 = c_reverse; - a_reverse1 = a_reverse;*/ - if (tc_sub_clocal_1) - { - switch (tc_mselect_1) - { - case TC_MSELECT_ZERO: - factor_r = factor_g = factor_b = 0; - break; - case TC_MSELECT_CLOCAL: - factor_r = state->tex_r[1]; - factor_g = state->tex_g[1]; - factor_b = state->tex_b[1]; - break; - case TC_MSELECT_AOTHER: - factor_r = factor_g = factor_b = 0; - break; - case TC_MSELECT_ALOCAL: - factor_r = factor_g = factor_b = state->tex_a[1]; - break; - case TC_MSELECT_DETAIL: - factor_r = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; - if (factor_r > params->detail_max[1]) - factor_r = params->detail_max[1]; - factor_g = factor_b = factor_r; - break; - case TC_MSELECT_LOD_FRAC: - factor_r = factor_g = factor_b = state->lod_frac[1]; - break; - } - if (!c_reverse) - { - r = (-state->tex_r[1] * (factor_r + 1)) >> 8; - g = (-state->tex_g[1] * (factor_g + 1)) >> 8; - b = (-state->tex_b[1] * (factor_b + 1)) >> 8; - } - else - { - r = (-state->tex_r[1] * ((factor_r^0xff) + 1)) >> 8; - g = (-state->tex_g[1] * ((factor_g^0xff) + 1)) >> 8; - b = (-state->tex_b[1] * ((factor_b^0xff) + 1)) >> 8; - } - if (tc_add_clocal_1) - { - r += state->tex_r[1]; - g += state->tex_g[1]; - b += state->tex_b[1]; - } - else if (tc_add_alocal_1) - { - r += state->tex_a[1]; - g += state->tex_a[1]; - b += state->tex_a[1]; - } - state->tex_r[1] = CLAMP(r); - state->tex_g[1] = CLAMP(g); - state->tex_b[1] = CLAMP(b); - } - if (tca_sub_clocal_1) - { - switch (tca_mselect_1) - { - case TCA_MSELECT_ZERO: - factor_a = 0; - break; - case TCA_MSELECT_CLOCAL: - factor_a = state->tex_a[1]; - break; - case TCA_MSELECT_AOTHER: - factor_a = 0; - break; - case TCA_MSELECT_ALOCAL: - factor_a = state->tex_a[1]; - break; - case TCA_MSELECT_DETAIL: - factor_a = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; - if (factor_a > params->detail_max[1]) - factor_a = params->detail_max[1]; - break; - case TCA_MSELECT_LOD_FRAC: - factor_a = state->lod_frac[1]; - break; - } - if (!a_reverse) - a = (-state->tex_a[1] * ((factor_a ^ 0xff) + 1)) >> 8; - else - a = (-state->tex_a[1] * (factor_a + 1)) >> 8; - if (tca_add_clocal_1 || tca_add_alocal_1) - a += state->tex_a[1]; - state->tex_a[1] = CLAMP(a); - } - - - voodoo_tmu_fetch(voodoo, params, state, 0, x); - - if ((params->textureMode[0] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) - { - c_reverse = tc_reverse_blend; - a_reverse = tca_reverse_blend; - } - else - { - c_reverse = !tc_reverse_blend; - a_reverse = !tca_reverse_blend; - } - - if (!tc_zero_other) - { - r = state->tex_r[1]; - g = state->tex_g[1]; - b = state->tex_b[1]; - } - else - r = g = b = 0; - if (tc_sub_clocal) - { - r -= state->tex_r[0]; - g -= state->tex_g[0]; - b -= state->tex_b[0]; - } - switch (tc_mselect) - { - case TC_MSELECT_ZERO: - factor_r = factor_g = factor_b = 0; - break; - case TC_MSELECT_CLOCAL: - factor_r = state->tex_r[0]; - factor_g = state->tex_g[0]; - factor_b = state->tex_b[0]; - break; - case TC_MSELECT_AOTHER: - factor_r = factor_g = factor_b = state->tex_a[1]; - break; - case TC_MSELECT_ALOCAL: - factor_r = factor_g = factor_b = state->tex_a[0]; - break; - case TC_MSELECT_DETAIL: - factor_r = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; - if (factor_r > params->detail_max[0]) - factor_r = params->detail_max[0]; - factor_g = factor_b = factor_r; - break; - case TC_MSELECT_LOD_FRAC: - factor_r = factor_g = factor_b = state->lod_frac[0]; - break; - } - if (!c_reverse) - { - r = (r * (factor_r + 1)) >> 8; - g = (g * (factor_g + 1)) >> 8; - b = (b * (factor_b + 1)) >> 8; - } - else - { - r = (r * ((factor_r^0xff) + 1)) >> 8; - g = (g * ((factor_g^0xff) + 1)) >> 8; - b = (b * ((factor_b^0xff) + 1)) >> 8; - } - if (tc_add_clocal) - { - r += state->tex_r[0]; - g += state->tex_g[0]; - b += state->tex_b[0]; - } - else if (tc_add_alocal) - { - r += state->tex_a[0]; - g += state->tex_a[0]; - b += state->tex_a[0]; - } - - if (!tca_zero_other) - a = state->tex_a[1]; - else - a = 0; - if (tca_sub_clocal) - a -= state->tex_a[0]; - switch (tca_mselect) - { - case TCA_MSELECT_ZERO: - factor_a = 0; - break; - case TCA_MSELECT_CLOCAL: - factor_a = state->tex_a[0]; - break; - case TCA_MSELECT_AOTHER: - factor_a = state->tex_a[1]; - break; - case TCA_MSELECT_ALOCAL: - factor_a = state->tex_a[0]; - break; - case TCA_MSELECT_DETAIL: - factor_a = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; - if (factor_a > params->detail_max[0]) - factor_a = params->detail_max[0]; - break; - case TCA_MSELECT_LOD_FRAC: - factor_a = state->lod_frac[0]; - break; - } - if (a_reverse) - a = (a * ((factor_a ^ 0xff) + 1)) >> 8; - else - a = (a * (factor_a + 1)) >> 8; - if (tca_add_clocal || tca_add_alocal) - a += state->tex_a[0]; - - - state->tex_r[0] = CLAMP(r); - state->tex_g[0] = CLAMP(g); - state->tex_b[0] = CLAMP(b); - state->tex_a[0] = CLAMP(a); - - if (tc_invert_output) - { - state->tex_r[0] ^= 0xff; - state->tex_g[0] ^= 0xff; - state->tex_b[0] ^= 0xff; - } - if (tca_invert_output) - state->tex_a[0] ^= 0xff; -} - -#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 texels; - int c; - uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y); - - if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || - (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) - texels = 1; - else - texels = 2; - - state->clamp_s[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPS; - state->clamp_t[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPT; - state->clamp_s[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPS; - state->clamp_t[1] = params->textureMode[1] & 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[0][c] = &voodoo->texture_cache[0][params->tex_entry[0]].data[texture_offset[c]]; - state->tex[1][c] = &voodoo->texture_cache[1][params->tex_entry[1]].data[texture_offset[c]]; - } - - state->tformat = params->tformat[0]; - - state->tex_w_mask[0] = params->tex_w_mask[0]; - state->tex_h_mask[0] = params->tex_h_mask[0]; - state->tex_shift[0] = params->tex_shift[0]; - state->tex_lod[0] = params->tex_lod[0]; - state->tex_w_mask[1] = params->tex_w_mask[1]; - state->tex_h_mask[1] = params->tex_h_mask[1]; - state->tex_shift[1] = params->tex_shift[1]; - state->tex_lod[1] = params->tex_lod[1]; - - 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->tmu[1].base_s += params->tmu[1].dSdY*dy; - state->tmu[1].base_t += params->tmu[1].dTdY*dy; - state->tmu[1].base_w += params->tmu[1].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); - else - voodoo_draw = NULL; -#endif - - if (voodoo_output) - pclog("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC); -// 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->tmu1_s = state->tmu[1].base_s; - state->tmu1_t = state->tmu[1].base_t; - state->tmu1_w = state->tmu[1].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 (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); - - 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->tmu1_s += (params->tmu[1].dSdX * dx); - state->tmu1_t += (params->tmu[1].dTdX * dx); - state->tmu1_w += (params->tmu[1].dWdX * dx); - state->w += (params->dWdX * dx); - - 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)); - - 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->tmu1_s += params->tmu[1].dSdX*dx; - state->tmu1_t += params->tmu[1].dTdX*dx; - state->tmu1_w += params->tmu[1].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->tmu1_s += params->tmu[1].dSdX*dx; - state->tmu1_t += params->tmu[1].dTdX*dx; - state->tmu1_w += params->tmu[1].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 = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)]; - state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y * voodoo->row_width)) & voodoo->fb_mask]; - - 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); - - state->pixel_count = 0; - state->texel_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; - state->x = x; - voodoo->pixel_count[odd_even]++; - voodoo->texel_count[odd_even] += texels; - voodoo->fbiPixelsIn++; - - if (voodoo_output) - pclog(" X=%03i T=%08x\n", x, state->tmu0_t); -// 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 = 0, src_g = 0, src_b = 0, src_a = 0; - int msel_r, msel_g, msel_b, msel_a; - uint8_t dest_r, dest_g, dest_b, dest_a; - uint16_t 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 = CLAMP16(new_depth + (int16_t)params->zaColor); - - if (params->fbzMode & FBZ_DEPTH_ENABLE) - { - uint16_t old_depth = aux_mem[x]; - - DEPTH_TEST((params->fbzMode & FBZ_DEPTH_SOURCE) ? (params->zaColor & 0xffff) : new_depth); - } - - 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[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) - { - /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ - voodoo_tmu_fetch(voodoo, params, state, 0, x); - } - else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) - { - /*TMU0 in pass-through mode, only sample TMU1*/ - voodoo_tmu_fetch(voodoo, params, state, 1, x); - - state->tex_r[0] = state->tex_r[1]; - state->tex_g[0] = state->tex_g[1]; - state->tex_b[0] = state->tex_b[1]; - state->tex_a[0] = state->tex_a[1]; - } - else - { - voodoo_tmu_fetch_and_blend(voodoo, params, state, x); - } - - if ((params->fbzMode & FBZ_CHROMAKEY) && - state->tex_r[0] == params->chromaKey_r && - state->tex_g[0] == params->chromaKey_g && - state->tex_b[0] == params->chromaKey_b) - { - voodoo->fbiChromaFail++; - goto skip_pixel; - } - } - - if (voodoo->trexInit1[0] & (1 << 18)) - { - state->tex_r[0] = state->tex_g[0] = 0; - - if (voodoo->dual_tmus) - state->tex_b[0] = 1 | (3 << 6); - else - state->tex_b[0] = 1; - } - - if (cc_localselect_override) - sel = (state->tex_a[0] & 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[0]; - cother_g = state->tex_g[0]; - cother_b = state->tex_b[0]; - 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: - fatal("Bad cca_localselect %i\n", cca_localselect); - 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[0]; - break; - case A_SEL_COLOR1: - aother = (params->color1 >> 24) & 0xff; - break; - default: - fatal("Bad a_sel %i\n", a_sel); - 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[0]; - msel_g = state->tex_a[0]; - msel_b = state->tex_a[0]; - break; - case CC_MSELECT_TEXRGB: - msel_r = state->tex_r[0]; - msel_g = state->tex_g[0]; - msel_b = state->tex_b[0]; - break; - - default: - fatal("Bad cc_mselect %i\n", cc_mselect); - 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[0]; - break; - - default: - fatal("Bad cca_mselect %i\n", cca_mselect); - 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; - case 0: - break; - default: - fatal("Bad cc_add %i\n", cc_add); - } - - 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, state->w); - - 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 | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) - 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->tmu1_s += params->tmu[1].dSdX; - state->tmu1_t += params->tmu[1].dTdX; - state->tmu1_w += params->tmu[1].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->tmu1_s -= params->tmu[1].dSdX; - state->tmu1_t -= params->tmu[1].dTdX; - state->tmu1_w -= params->tmu[1].dWdX; - state->w -= params->dWdX; - } - - x += state->xdir; - } while (start_x != x2); - - voodoo->pixel_count[odd_even] += state->pixel_count; - voodoo->texel_count[odd_even] += state->texel_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->tmu[1].base_s += params->tmu[1].dSdY; - state->tmu[1].base_t += params->tmu[1].dTdY; - state->tmu[1].base_w += params->tmu[1].dWdY; - state->base_w += params->dWdY; - state->xstart += state->dx1; - state->xend += state->dx2; - } - - voodoo->texture_cache[0][params->tex_entry[0]].refcount_r[odd_even]++; - voodoo->texture_cache[1][params->tex_entry[1]].refcount_r[odd_even]++; -} - -static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) -{ - voodoo_state_t state; - int vertexAy_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,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%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] : 0, - (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode);*/ - - 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.tmu[1].base_s = params->tmu[1].startS; - state.tmu[1].base_t = params->tmu[1].startT; - state.tmu[1].base_w = params->tmu[1].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.tmu[1].base_s += (dx*params->tmu[1].dSdX + dy*params->tmu[1].dSdY) >> 4; - state.tmu[1].base_t += (dx*params->tmu[1].dTdX + dy*params->tmu[1].dTdY) >> 4; - state.tmu[1].base_w += (dx*params->tmu[1].dWdX + dy*params->tmu[1].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; - 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[0] = (params->tLOD[0] & 0x3f) << 6; - state.lod_max[0] = ((params->tLOD[0] >> 6) & 0x3f) << 6; - if (state.lod_max[0] > 0x800) - state.lod_max[0] = 0x800; - state.lod_min[1] = (params->tLOD[1] & 0x3f) << 6; - state.lod_max[1] = ((params->tLOD[1] >> 6) & 0x3f) << 6; - if (state.lod_max[1] > 0x800) - state.lod_max[1] = 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[0] >> 12) & 0x3f; - if (lodbias & 0x20) - lodbias |= ~0x3f; - state.tmu[0].lod = LOD + (lodbias << 6); - - - tempdx = (params->tmu[1].dSdX >> 14) * (params->tmu[1].dSdX >> 14) + (params->tmu[1].dTdX >> 14) * (params->tmu[1].dTdX >> 14); - tempdy = (params->tmu[1].dSdY >> 14) * (params->tmu[1].dSdY >> 14) + (params->tmu[1].dTdY >> 14) * (params->tmu[1].dTdY >> 14); - - if (tempdx > tempdy) - tempLOD = tempdx; - else - tempLOD = tempdy; - - LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); - LOD >>= 2; - - lodbias = (params->tLOD[1] >> 12) & 0x3f; - if (lodbias & 0x20) - lodbias |= ~0x3f; - state.tmu[1].lod = LOD + (lodbias << 6); - - - 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*/ - } - } - - use_texture(voodoo, params, 0); - if (voodoo->dual_tmus) - use_texture(voodoo, params, 1); - - memcpy(params_new, params, sizeof(voodoo_params_t)); - - 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; - int low_y, high_y; - - if (params->fbzMode & (1 << 17)) - { - high_y = voodoo->v_disp - params->clipLowY; - low_y = voodoo->v_disp - params->clipHighY; - } - else - { - low_y = params->clipLowY; - high_y = params->clipHighY; - } - - 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 = low_y; y < high_y; 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 = low_y; y < high_y; 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; - } - } -} - -enum -{ - SETUPMODE_RGB = (1 << 0), - SETUPMODE_ALPHA = (1 << 1), - SETUPMODE_Z = (1 << 2), - SETUPMODE_Wb = (1 << 3), - SETUPMODE_W0 = (1 << 4), - SETUPMODE_S0_T0 = (1 << 5), - SETUPMODE_W1 = (1 << 6), - SETUPMODE_S1_T1 = (1 << 7), - - SETUPMODE_STRIP_MODE = (1 << 16), - SETUPMODE_CULLING_ENABLE = (1 << 17), - SETUPMODE_CULLING_SIGN = (1 << 18), - SETUPMODE_DISABLE_PINGPONG = (1 << 19) -}; - -static void triangle_setup(voodoo_t *voodoo) -{ - float dxAB, dxBC, dyAB, dyBC; - float area; - int va = 0, vb = 1, vc = 2; - int reverse_cull = 0; - - if (voodoo->verts[0].sVy < voodoo->verts[1].sVy) - { - if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) - { - /* V1>V0, V2>V1, V2>V1>V0*/ - va = 0; /*OK*/ - vb = 1; - vc = 2; - } - else - { - /* V1>V0, V1>V2*/ - if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) - { - /* V1>V0, V1>V2, V2>V0, V1>V2>V0*/ - va = 0; - vb = 2; - vc = 1; - reverse_cull = 1; - } - else - { - /* V1>V0, V1>V2, V0>V2, V1>V0>V2*/ - va = 2; - vb = 0; - vc = 1; - } - } - } - else - { - if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) - { - /* V0>V1, V2>V1*/ - if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) - { - /* V0>V1, V2>V1, V2>V0, V2>V0>V1*/ - va = 1; - vb = 0; - vc = 2; - reverse_cull = 1; - } - else - { - /* V0>V1, V2>V1, V0>V2, V0>V2>V1*/ - va = 1; - vb = 2; - vc = 0; - } - } - else - { - /*V0>V1>V2*/ - va = 2; - vb = 1; - vc = 0; - reverse_cull = 1; - } - } - - dxAB = voodoo->verts[va].sVx - voodoo->verts[vb].sVx; - dxBC = voodoo->verts[vb].sVx - voodoo->verts[vc].sVx; - dyAB = voodoo->verts[va].sVy - voodoo->verts[vb].sVy; - dyBC = voodoo->verts[vb].sVy - voodoo->verts[vc].sVy; - - area = dxAB * dyBC - dxBC * dyAB; - - if (area == 0.0) - { - if ((voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) && - !(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) - voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; - - return; - } - - dxAB /= area; - dxBC /= area; - dyAB /= area; - dyBC /= area; - - if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) - { - int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN; - int sign = (area < 0.0); - - if (!(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) - voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; - - if (reverse_cull) - sign = !sign; - - if (cull_sign && sign) - return; - if (!cull_sign && !sign) - return; - } - - voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVx * 16.0f) & 0xffff); - voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVy * 16.0f) & 0xffff); - voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVx * 16.0f) & 0xffff); - voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVy * 16.0f) & 0xffff); - voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVx * 16.0f) & 0xffff); - voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVy * 16.0f) & 0xffff); - - if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) - fatal("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); - - if (voodoo->sSetupMode & SETUPMODE_RGB) - { - voodoo->params.startR = (int32_t)(voodoo->verts[va].sRed * 4096.0f); - voodoo->params.dRdX = (int32_t)(((voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dyBC - (voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dyAB) * 4096.0f); - voodoo->params.dRdY = (int32_t)(((voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dxAB - (voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dxBC) * 4096.0f); - voodoo->params.startG = (int32_t)(voodoo->verts[va].sGreen * 4096.0f); - voodoo->params.dGdX = (int32_t)(((voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dyBC - (voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dyAB) * 4096.0f); - voodoo->params.dGdY = (int32_t)(((voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dxAB - (voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dxBC) * 4096.0f); - voodoo->params.startB = (int32_t)(voodoo->verts[va].sBlue * 4096.0f); - voodoo->params.dBdX = (int32_t)(((voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dyBC - (voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dyAB) * 4096.0f); - voodoo->params.dBdY = (int32_t)(((voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dxAB - (voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dxBC) * 4096.0f); - } - if (voodoo->sSetupMode & SETUPMODE_ALPHA) - { - voodoo->params.startA = (int32_t)(voodoo->verts[va].sAlpha * 4096.0f); - voodoo->params.dAdX = (int32_t)(((voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dyBC - (voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dyAB) * 4096.0f); - voodoo->params.dAdY = (int32_t)(((voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dxAB - (voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dxBC) * 4096.0f); - } - if (voodoo->sSetupMode & SETUPMODE_Z) - { - voodoo->params.startZ = (int32_t)(voodoo->verts[va].sVz * 4096.0f); - voodoo->params.dZdX = (int32_t)(((voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dyBC - (voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dyAB) * 4096.0f); - voodoo->params.dZdY = (int32_t)(((voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dxAB - (voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dxBC) * 4096.0f); - } - if (voodoo->sSetupMode & SETUPMODE_Wb) - { - voodoo->params.startW = (int64_t)(voodoo->verts[va].sWb * 4294967296.0f); - voodoo->params.dWdX = (int64_t)(((voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dyBC - (voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dyAB) * 4294967296.0f); - voodoo->params.dWdY = (int64_t)(((voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dxAB - (voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dxBC) * 4294967296.0f); - voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW; - voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; - voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; - } - if (voodoo->sSetupMode & SETUPMODE_W0) - { - voodoo->params.tmu[0].startW = (int64_t)(voodoo->verts[va].sW0 * 4294967296.0f); - voodoo->params.tmu[0].dWdX = (int64_t)(((voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dyBC - (voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dWdY = (int64_t)(((voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dxAB - (voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dxBC) * 4294967296.0f); - voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW; - voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX; - voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY; - } - if (voodoo->sSetupMode & SETUPMODE_S0_T0) - { - voodoo->params.tmu[0].startS = (int64_t)(voodoo->verts[va].sS0 * 4294967296.0f); - voodoo->params.tmu[0].dSdX = (int64_t)(((voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dyBC - (voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dSdY = (int64_t)(((voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dxAB - (voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dxBC) * 4294967296.0f); - voodoo->params.tmu[0].startT = (int64_t)(voodoo->verts[va].sT0 * 4294967296.0f); - voodoo->params.tmu[0].dTdX = (int64_t)(((voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dyBC - (voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dyAB) * 4294967296.0f); - voodoo->params.tmu[0].dTdY = (int64_t)(((voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dxAB - (voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dxBC) * 4294967296.0f); - voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS; - voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX; - voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY; - voodoo->params.tmu[1].startT = voodoo->params.tmu[0].startT; - voodoo->params.tmu[1].dTdX = voodoo->params.tmu[0].dTdX; - voodoo->params.tmu[1].dTdY = voodoo->params.tmu[0].dTdY; - } - if (voodoo->sSetupMode & SETUPMODE_W1) - { - voodoo->params.tmu[1].startW = (int64_t)(voodoo->verts[va].sW1 * 4294967296.0f); - voodoo->params.tmu[1].dWdX = (int64_t)(((voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dyBC - (voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dWdY = (int64_t)(((voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dxAB - (voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dxBC) * 4294967296.0f); - } - if (voodoo->sSetupMode & SETUPMODE_S1_T1) - { - voodoo->params.tmu[1].startS = (int64_t)(voodoo->verts[va].sS1 * 4294967296.0f); - voodoo->params.tmu[1].dSdX = (int64_t)(((voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dyBC - (voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dSdY = (int64_t)(((voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dxAB - (voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dxBC) * 4294967296.0f); - voodoo->params.tmu[1].startT = (int64_t)(voodoo->verts[va].sT1 * 4294967296.0f); - voodoo->params.tmu[1].dTdX = (int64_t)(((voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dyBC - (voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dyAB) * 4294967296.0f); - voodoo->params.tmu[1].dTdY = (int64_t)(((voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dxAB - (voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dxBC) * 4294967296.0f); - } - - voodoo->params.sign = (area < 0.0); - - if (voodoo->ncc_dirty[0]) - voodoo_update_ncc(voodoo, 0); - if (voodoo->ncc_dirty[1]) - voodoo_update_ncc(voodoo, 1); - voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; - - queue_triangle(voodoo, &voodoo->params); -} - -enum -{ - BLIT_COMMAND_SCREEN_TO_SCREEN = 0, - BLIT_COMMAND_CPU_TO_SCREEN = 1, - BLIT_COMMAND_RECT_FILL = 2, - BLIT_COMMAND_SGRAM_FILL = 3 -}; - -enum -{ - BLIT_SRC_1BPP = (0 << 3), - BLIT_SRC_1BPP_BYTE_PACKED = (1 << 3), - BLIT_SRC_16BPP = (2 << 3), - BLIT_SRC_24BPP = (3 << 3), - BLIT_SRC_24BPP_DITHER_2X2 = (4 << 3), - BLIT_SRC_24BPP_DITHER_4X4 = (5 << 3) -}; - -enum -{ - BLIT_SRC_RGB_ARGB = (0 << 6), - BLIT_SRC_RGB_ABGR = (1 << 6), - BLIT_SRC_RGB_RGBA = (2 << 6), - BLIT_SRC_RGB_BGRA = (3 << 6) -}; - -enum -{ - BLIT_COMMAND_MASK = 7, - BLIT_SRC_FORMAT = (7 << 3), - BLIT_SRC_RGB_FORMAT = (3 << 6), - BLIT_SRC_CHROMA = (1 << 10), - BLIT_DST_CHROMA = (1 << 12), - BLIT_CLIPPING_ENABLED = (1 << 16) -}; - -enum -{ - BLIT_ROP_DST_PASS = (1 << 0), - BLIT_ROP_SRC_PASS = (1 << 1) -}; - -#define MIX(src_dat, dst_dat, rop) \ - switch (rop) \ - { \ - case 0x0: dst_dat = 0; break; \ - case 0x1: dst_dat = ~(src_dat | dst_dat); break; \ - case 0x2: dst_dat = ~src_dat & dst_dat; break; \ - case 0x3: dst_dat = ~src_dat; break; \ - case 0x4: dst_dat = src_dat & ~dst_dat; break; \ - case 0x5: dst_dat = ~dst_dat; break; \ - case 0x6: dst_dat = src_dat ^ dst_dat; break; \ - case 0x7: dst_dat = ~(src_dat & dst_dat); break; \ - case 0x8: dst_dat = src_dat & dst_dat; break; \ - case 0x9: dst_dat = ~(src_dat ^ dst_dat); break; \ - case 0xa: dst_dat = dst_dat; break; \ - case 0xb: dst_dat = ~src_dat | dst_dat; break; \ - case 0xc: dst_dat = src_dat; break; \ - case 0xd: dst_dat = src_dat | ~dst_dat; break; \ - case 0xe: dst_dat = src_dat | dst_dat; break; \ - case 0xf: dst_dat = 0xffff; break; \ - } - -#define ABS(x) ((x) > 0 ? (x) : -(x)) - -static void blit_start(voodoo_t *voodoo) -{ - uint64_t dat64; - int size_x = ABS(voodoo->bltSizeX), size_y = ABS(voodoo->bltSizeY); - int x_dir = (voodoo->bltSizeX > 0) ? 1 : -1; - int y_dir = (voodoo->bltSizeY > 0) ? 1 : -1; - int dst_x; - int src_y = voodoo->bltSrcY & 0x7ff, dst_y = voodoo->bltDstY & 0x7ff; - int src_stride = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcXYStride & 0x3f) * 32*2) : (voodoo->bltSrcXYStride & 0xff8); - int dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); - uint32_t src_base_addr = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcBaseAddr & 0x3ff) << 12) : (voodoo->bltSrcBaseAddr & 0x3ffff8); - uint32_t dst_base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); - int x, y; - -/* pclog("blit_start: command=%08x srcX=%i srcY=%i dstX=%i dstY=%i sizeX=%i sizeY=%i color=%04x,%04x\n", - voodoo->bltCommand, voodoo->bltSrcX, voodoo->bltSrcY, voodoo->bltDstX, voodoo->bltDstY, voodoo->bltSizeX, voodoo->bltSizeY, voodoo->bltColorFg, voodoo->bltColorBg);*/ - - wait_for_render_thread_idle(voodoo); - - switch (voodoo->bltCommand & BLIT_COMMAND_MASK) - { - case BLIT_COMMAND_SCREEN_TO_SCREEN: - for (y = 0; y <= size_y; y++) - { - uint16_t *src = (uint16_t *)&voodoo->fb_mem[src_base_addr + src_y*src_stride]; - uint16_t *dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; - int src_x = voodoo->bltSrcX, dst_x = voodoo->bltDstX; - - for (x = 0; x <= size_x; x++) - { - uint16_t src_dat = src[src_x]; - uint16_t dst_dat = dst[dst_x]; - int rop = 0; - - if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) - { - if (dst_x < voodoo->bltClipLeft || dst_x > voodoo->bltClipRight || - dst_y < voodoo->bltClipLowY || dst_y > voodoo->bltClipHighY) - goto skip_pixel_blit; - } - - if (voodoo->bltCommand & BLIT_SRC_CHROMA) - { - int r = (src_dat >> 11); - int g = (src_dat >> 5) & 0x3f; - int b = src_dat & 0x1f; - - if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && - g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && - b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) - rop |= BLIT_ROP_SRC_PASS; - } - if (voodoo->bltCommand & BLIT_DST_CHROMA) - { - int r = (dst_dat >> 11); - int g = (dst_dat >> 5) & 0x3f; - int b = dst_dat & 0x1f; - - if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && - g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && - b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) - rop |= BLIT_ROP_DST_PASS; - } - - MIX(src_dat, dst_dat, voodoo->bltRop[rop]); - - dst[dst_x] = dst_dat; -skip_pixel_blit: - src_x += x_dir; - dst_x += x_dir; - } - - src_y += y_dir; - dst_y += y_dir; - } - break; - - case BLIT_COMMAND_CPU_TO_SCREEN: - voodoo->blt.dst_x = voodoo->bltDstX; - voodoo->blt.dst_y = voodoo->bltDstY; - voodoo->blt.cur_x = 0; - voodoo->blt.size_x = size_x; - voodoo->blt.size_y = size_y; - voodoo->blt.x_dir = x_dir; - voodoo->blt.y_dir = y_dir; - voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); - break; - - case BLIT_COMMAND_RECT_FILL: - for (y = 0; y <= size_y; y++) - { - uint16_t *dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; - int dst_x = voodoo->bltDstX; - - for (x = 0; x <= size_x; x++) - { - if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) - { - if (dst_x < voodoo->bltClipLeft || dst_x > voodoo->bltClipRight || - dst_y < voodoo->bltClipLowY || dst_y > voodoo->bltClipHighY) - goto skip_pixel_fill; - } - - dst[dst_x] = voodoo->bltColorFg; -skip_pixel_fill: - dst_x += x_dir; - } - - dst_y += y_dir; - } - break; - - case BLIT_COMMAND_SGRAM_FILL: - /*32x32 tiles - 2kb*/ - dst_y = voodoo->bltDstY & 0x3ff; - size_x = voodoo->bltSizeX & 0x1ff; //512*8 = 4kb - size_y = voodoo->bltSizeY & 0x3ff; - - dat64 = voodoo->bltColorFg | ((uint64_t)voodoo->bltColorFg << 16) | - ((uint64_t)voodoo->bltColorFg << 32) | ((uint64_t)voodoo->bltColorFg << 48); - - for (y = 0; y <= size_y; y++) - { - uint64_t *dst; - - /*This may be wrong*/ - if (!y) - { - dst_x = voodoo->bltDstX & 0x1ff; - size_x = 511 - dst_x; - } - else if (y < size_y) - { - dst_x = 0; - size_x = 511; - } - else - { - dst_x = 0; - size_x = voodoo->bltSizeX & 0x1ff; - } - - dst = (uint64_t *)&voodoo->fb_mem[(dst_y*512*8 + dst_x*8) & voodoo->fb_mask]; - - for (x = 0; x <= size_x; x++) - dst[x] = dat64; - - dst_y++; - } - break; - - default: - fatal("bad blit command %08x\n", voodoo->bltCommand); - } -} - -static void blit_data(voodoo_t *voodoo, uint32_t data) -{ - int src_bits = 32; - uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); - uint16_t *dst = (uint16_t *)&voodoo->fb_mem[base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride]; - - if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN) - return; - - while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x) - { - int r = 0, g = 0, b = 0; - uint16_t src_dat = 0, dst_dat; - int x = (voodoo->blt.x_dir > 0) ? (voodoo->blt.dst_x + voodoo->blt.cur_x) : (voodoo->blt.dst_x - voodoo->blt.cur_x); - int rop = 0; - - switch (voodoo->bltCommand & BLIT_SRC_FORMAT) - { - case BLIT_SRC_1BPP: case BLIT_SRC_1BPP_BYTE_PACKED: - src_dat = (data & 1) ? voodoo->bltColorFg : voodoo->bltColorBg; - data >>= 1; - src_bits--; - break; - case BLIT_SRC_16BPP: - switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) - { - case BLIT_SRC_RGB_ARGB: case BLIT_SRC_RGB_RGBA: - src_dat = data & 0xffff; - break; - case BLIT_SRC_RGB_ABGR: case BLIT_SRC_RGB_BGRA: - src_dat = ((data & 0xf800) >> 11) | (data & 0x07c0) | ((data & 0x0038) << 11); - break; - } - data >>= 16; - src_bits -= 16; - break; - case BLIT_SRC_24BPP: case BLIT_SRC_24BPP_DITHER_2X2: case BLIT_SRC_24BPP_DITHER_4X4: - switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) - { - case BLIT_SRC_RGB_ARGB: - r = (data >> 16) & 0xff; - g = (data >> 8) & 0xff; - b = data & 0xff; - break; - case BLIT_SRC_RGB_ABGR: - r = data & 0xff; - g = (data >> 8) & 0xff; - b = (data >> 16) & 0xff; - break; - case BLIT_SRC_RGB_RGBA: - r = (data >> 24) & 0xff; - g = (data >> 16) & 0xff; - b = (data >> 8) & 0xff; - break; - case BLIT_SRC_RGB_BGRA: - r = (data >> 8) & 0xff; - g = (data >> 16) & 0xff; - b = (data >> 24) & 0xff; - break; - } - switch (voodoo->bltCommand & BLIT_SRC_FORMAT) - { - case BLIT_SRC_24BPP: - src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); - break; - case BLIT_SRC_24BPP_DITHER_2X2: - r = dither_rb2x2[r][voodoo->blt.dst_y & 1][x & 1]; - g = dither_g2x2[g][voodoo->blt.dst_y & 1][x & 1]; - b = dither_rb2x2[b][voodoo->blt.dst_y & 1][x & 1]; - src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); - break; - case BLIT_SRC_24BPP_DITHER_4X4: - r = dither_rb[r][voodoo->blt.dst_y & 3][x & 3]; - g = dither_g[g][voodoo->blt.dst_y & 3][x & 3]; - b = dither_rb[b][voodoo->blt.dst_y & 3][x & 3]; - src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); - break; - } - src_bits = 0; - break; - } - - if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) - { - if (x < voodoo->bltClipLeft || x > voodoo->bltClipRight || - voodoo->blt.dst_y < voodoo->bltClipLowY || voodoo->blt.dst_y > voodoo->bltClipHighY) - goto skip_pixel; - } - - dst_dat = dst[x]; - - if (voodoo->bltCommand & BLIT_SRC_CHROMA) - { - r = (src_dat >> 11); - g = (src_dat >> 5) & 0x3f; - b = src_dat & 0x1f; - - if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && - g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && - b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) - rop |= BLIT_ROP_SRC_PASS; - } - if (voodoo->bltCommand & BLIT_DST_CHROMA) - { - r = (dst_dat >> 11); - g = (dst_dat >> 5) & 0x3f; - b = dst_dat & 0x1f; - - if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && - g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && - b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) - rop |= BLIT_ROP_DST_PASS; - } - - MIX(src_dat, dst_dat, voodoo->bltRop[rop]); - - dst[x] = dst_dat; - -skip_pixel: - voodoo->blt.cur_x++; - } - - if (voodoo->blt.cur_x > voodoo->blt.size_x) - { - voodoo->blt.size_y--; - if (voodoo->blt.size_y >= 0) - { - voodoo->blt.cur_x = 0; - voodoo->blt.dst_y += voodoo->blt.y_dir; - } - } -} - -enum -{ - CHIP_FBI = 0x1, - CHIP_TREX0 = 0x2, - CHIP_TREX1 = 0x4, - CHIP_TREX2 = 0x8 -}; - -static void wait_for_swap_complete(voodoo_t *voodoo) -{ - 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; - } - } -} - -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_reg_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"); - - if (TRIPLE_BUFFER) - { - voodoo->disp_buffer = (voodoo->disp_buffer + 1) % 3; - voodoo->draw_buffer = (voodoo->draw_buffer + 1) % 3; - } - else - { - voodoo->disp_buffer = !voodoo->disp_buffer; - voodoo->draw_buffer = !voodoo->draw_buffer; - } - voodoo_recalc(voodoo); - - voodoo->params.swapbufferCMD = val; - - pclog("Swap buffer %08x %d %p\n", val, voodoo->swap_count, &voodoo->swap_count); -// 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 if (TRIPLE_BUFFER) - { - if (voodoo->swap_pending) - wait_for_swap_complete(voodoo); - - voodoo->swap_interval = (val >> 1) & 0xff; - voodoo->swap_offset = voodoo->params.front_offset; - voodoo->swap_pending = 1; - } - else - { - voodoo->swap_interval = (val >> 1) & 0xff; - voodoo->swap_offset = voodoo->params.front_offset; - voodoo->swap_pending = 1; - - wait_for_swap_complete(voodoo); - } - 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; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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_TREX1) - voodoo->params.tmu[1].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; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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; - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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_TREX1) - voodoo->params.tmu[1].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[0]) - voodoo_update_ncc(voodoo, 0); - if (voodoo->ncc_dirty[1]) - voodoo_update_ncc(voodoo, 1); - voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 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); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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_TREX1) - voodoo->params.tmu[1].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); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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_TREX1) - voodoo->params.tmu[1].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); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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); - if (chip & CHIP_TREX1) - voodoo->params.tmu[1].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_TREX1) - voodoo->params.tmu[1].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[0]) - voodoo_update_ncc(voodoo, 0); - if (voodoo->ncc_dirty[1]) - voodoo_update_ncc(voodoo, 1); - voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 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: - if (voodoo->type >= VOODOO_2) - { - voodoo->params.clipRight = val & 0xfff; - voodoo->params.clipLeft = (val >> 16) & 0xfff; - } - else - { - voodoo->params.clipRight = val & 0x3ff; - voodoo->params.clipLeft = (val >> 16) & 0x3ff; - } - break; - case SST_clipLowYHighY: - if (voodoo->type >= VOODOO_2) - { - voodoo->params.clipHighY = val & 0xfff; - voodoo->params.clipLowY = (val >> 16) & 0xfff; - } - else - { - 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_stipple: - voodoo->params.stipple = val; - 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_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; - if (val & 0x20000000) - { - voodoo->clutData[(val >> 24) & 0x3f].b = 255; - voodoo->clutData[(val >> 24) & 0x3f].g = 255; - voodoo->clutData[(val >> 24) & 0x3f].r = 255; - } - voodoo->clutData_dirty = 1; - break; - - case SST_sSetupMode: - voodoo->sSetupMode = val; - break; - case SST_sVx: - tempif.i = val; - voodoo->verts[3].sVx = tempif.f; -// pclog("sVx[%i]=%f\n", voodoo->vertex_num, tempif.f); - break; - case SST_sVy: - tempif.i = val; - voodoo->verts[3].sVy = tempif.f; -// pclog("sVy[%i]=%f\n", voodoo->vertex_num, tempif.f); - break; - case SST_sARGB: - voodoo->verts[3].sBlue = (float)(val & 0xff); - voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); - voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); - voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); - break; - case SST_sRed: - tempif.i = val; - voodoo->verts[3].sRed = tempif.f; - break; - case SST_sGreen: - tempif.i = val; - voodoo->verts[3].sGreen = tempif.f; - break; - case SST_sBlue: - tempif.i = val; - voodoo->verts[3].sBlue = tempif.f; - break; - case SST_sAlpha: - tempif.i = val; - voodoo->verts[3].sAlpha = tempif.f; - break; - case SST_sVz: - tempif.i = val; - voodoo->verts[3].sVz = tempif.f; - break; - case SST_sWb: - tempif.i = val; - voodoo->verts[3].sWb = tempif.f; - break; - case SST_sW0: - tempif.i = val; - voodoo->verts[3].sW0 = tempif.f; - break; - case SST_sS0: - tempif.i = val; - voodoo->verts[3].sS0 = tempif.f; - break; - case SST_sT0: - tempif.i = val; - voodoo->verts[3].sT0 = tempif.f; - break; - case SST_sW1: - tempif.i = val; - voodoo->verts[3].sW1 = tempif.f; - break; - case SST_sS1: - tempif.i = val; - voodoo->verts[3].sS1 = tempif.f; - break; - case SST_sT1: - tempif.i = val; - voodoo->verts[3].sT1 = tempif.f; - break; - - case SST_sBeginTriCMD: -// pclog("sBeginTriCMD %i %f\n", voodoo->vertex_num, voodoo->verts[4].sVx); - voodoo->verts[0] = voodoo->verts[3]; - voodoo->vertex_num = 1; - voodoo->num_verticies = 1; - break; - case SST_sDrawTriCMD: -// pclog("sDrawTriCMD %i %i %i\n", voodoo->num_verticies, voodoo->vertex_num, voodoo->sSetupMode & SETUPMODE_STRIP_MODE); - if (voodoo->vertex_num == 3) - voodoo->vertex_num = (voodoo->sSetupMode & SETUPMODE_STRIP_MODE) ? 1 : 0; - voodoo->verts[voodoo->vertex_num] = voodoo->verts[3]; - - voodoo->num_verticies++; - voodoo->vertex_num++; - if (voodoo->num_verticies == 3) - { -// pclog("triangle_setup\n"); - triangle_setup(voodoo); - - voodoo->num_verticies = 2; - } - if (voodoo->vertex_num == 4) - fatal("sDrawTriCMD overflow\n"); - break; - - case SST_bltSrcBaseAddr: - voodoo->bltSrcBaseAddr = val & 0x3fffff; - break; - case SST_bltDstBaseAddr: -// pclog("Write bltDstBaseAddr %08x\n", val); - voodoo->bltDstBaseAddr = val & 0x3fffff; - break; - case SST_bltXYStrides: - voodoo->bltSrcXYStride = val & 0xfff; - voodoo->bltDstXYStride = (val >> 16) & 0xfff; -// pclog("Write bltXYStrides %08x\n", val); - break; - case SST_bltSrcChromaRange: - voodoo->bltSrcChromaRange = val; - voodoo->bltSrcChromaMinB = val & 0x1f; - voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f; - voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f; - voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f; - voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f; - voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f; - break; - case SST_bltDstChromaRange: - voodoo->bltDstChromaRange = val; - voodoo->bltDstChromaMinB = val & 0x1f; - voodoo->bltDstChromaMinG = (val >> 5) & 0x3f; - voodoo->bltDstChromaMinR = (val >> 11) & 0x1f; - voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f; - voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f; - voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f; - break; - case SST_bltClipX: - voodoo->bltClipRight = val & 0xfff; - voodoo->bltClipLeft = (val >> 16) & 0xfff; - break; - case SST_bltClipY: - voodoo->bltClipHighY = val & 0xfff; - voodoo->bltClipLowY = (val >> 16) & 0xfff; - break; - - case SST_bltSrcXY: - voodoo->bltSrcX = val & 0x7ff; - voodoo->bltSrcY = (val >> 16) & 0x7ff; - break; - case SST_bltDstXY: -// pclog("Write bltDstXY %08x\n", val); - voodoo->bltDstX = val & 0x7ff; - voodoo->bltDstY = (val >> 16) & 0x7ff; - if (val & (1 << 31)) - blit_start(voodoo); - break; - case SST_bltSize: -// pclog("Write bltSize %08x\n", val); - voodoo->bltSizeX = val & 0xfff; - if (voodoo->bltSizeX & 0x800) - voodoo->bltSizeX |= 0xfffff000; - voodoo->bltSizeY = (val >> 16) & 0xfff; - if (voodoo->bltSizeY & 0x800) - voodoo->bltSizeY |= 0xfffff000; - if (val & (1 << 31)) - blit_start(voodoo); - break; - case SST_bltRop: - voodoo->bltRop[0] = val & 0xf; - voodoo->bltRop[1] = (val >> 4) & 0xf; - voodoo->bltRop[2] = (val >> 8) & 0xf; - voodoo->bltRop[3] = (val >> 12) & 0xf; - break; - case SST_bltColor: -// pclog("Write bltColor %08x\n", val); - voodoo->bltColorFg = val & 0xffff; - voodoo->bltColorBg = (val >> 16) & 0xffff; - break; - - case SST_bltCommand: - voodoo->bltCommand = val; -// pclog("Write bltCommand %08x\n", val); - if (val & (1 << 31)) - blit_start(voodoo); - break; - case SST_bltData: - blit_data(voodoo, val); - break; - - case SST_textureMode: - if (chip & CHIP_TREX0) - { - voodoo->params.textureMode[0] = val; - voodoo->params.tformat[0] = (val >> 8) & 0xf; - } - if (chip & CHIP_TREX1) - { - voodoo->params.textureMode[1] = val; - voodoo->params.tformat[1] = (val >> 8) & 0xf; - } - break; - case SST_tLOD: - if (chip & CHIP_TREX0) - { - voodoo->params.tLOD[0] = val; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.tLOD[1] = val; - voodoo_recalc_tex(voodoo, 1); - } - break; - case SST_tDetail: - if (chip & CHIP_TREX0) - { - voodoo->params.detail_max[0] = val & 0xff; - voodoo->params.detail_bias[0] = (val >> 8) & 0x3f; - voodoo->params.detail_scale[0] = (val >> 14) & 7; - } - if (chip & CHIP_TREX1) - { - voodoo->params.detail_max[1] = val & 0xff; - voodoo->params.detail_bias[1] = (val >> 8) & 0x3f; - voodoo->params.detail_scale[1] = (val >> 14) & 7; - } - break; - case SST_texBaseAddr: - if (chip & CHIP_TREX0) - { - voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 1); - } - break; - case SST_texBaseAddr1: - if (chip & CHIP_TREX0) - { - voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 1); - } - break; - case SST_texBaseAddr2: - if (chip & CHIP_TREX0) - { - voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 1); - } - break; - case SST_texBaseAddr38: - if (chip & CHIP_TREX0) - { - voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 0); - } - if (chip & CHIP_TREX1) - { - voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; - voodoo_recalc_tex(voodoo, 1); - } - break; - - case SST_trexInit1: - if (chip & CHIP_TREX0) - voodoo->trexInit1[0] = val; - if (chip & CHIP_TREX1) - voodoo->trexInit1[1] = val; - break; - - case SST_nccTable0_Y0: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].y[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].y[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable0_Y1: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].y[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].y[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable0_Y2: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].y[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].y[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable0_Y3: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].y[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].y[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - - case SST_nccTable0_I0: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_I2: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_Q0: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].q[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].q[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_Q2: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - if (val & (1 << 31)) - { - int p = (val >> 23) & 0xfe; - if (chip & CHIP_TREX0) - { - voodoo->palette[0][p].u = val | 0xff000000; - voodoo->palette_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->palette[1][p].u = val | 0xff000000; - voodoo->palette_dirty[1] = 1; - } - } - break; - - case SST_nccTable0_I1: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_I3: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].i[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].i[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_Q1: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].q[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].q[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - case SST_nccTable0_Q3: - if (!(val & (1 << 31))) - { - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][0].q[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][0].q[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - } - if (val & (1 << 31)) - { - int p = ((val >> 23) & 0xfe) | 0x01; - if (chip & CHIP_TREX0) - { - voodoo->palette[0][p].u = val | 0xff000000; - voodoo->palette_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->palette[1][p].u = val | 0xff000000; - voodoo->palette_dirty[1] = 1; - } - } - break; - - case SST_nccTable1_Y0: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].y[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].y[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Y1: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].y[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].y[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Y2: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].y[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].y[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Y3: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].y[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].y[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_I0: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].i[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].i[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_I1: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].i[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].i[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_I2: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].i[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].i[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_I3: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].i[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].i[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Q0: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].q[0] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].q[0] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Q1: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].q[1] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].q[1] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Q2: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].q[2] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].q[2] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - case SST_nccTable1_Q3: - if (chip & CHIP_TREX0) - { - voodoo->nccTable[0][1].q[3] = val; - voodoo->ncc_dirty[0] = 1; - } - if (chip & CHIP_TREX1) - { - voodoo->nccTable[1][1].q[3] = val; - voodoo->ncc_dirty[1] = 1; - } - break; - - case SST_userIntrCMD: - fatal("userIntrCMD write %08x from FIFO\n", val); - 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 = 0; - - colour_data.r = colour_data.g = colour_data.b = colour_data.a = 0; - - 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; - case LFB_FORMAT_DEPTH: - depth_data = val; - write_mask = LFB_WRITE_DEPTH; - 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(new_depth); - } - - 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; - int64_t w_depth = (int64_t)(int32_t)new_depth; - int32_t ia = alpha_data << 12; - - APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); - } - - 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 = 0, 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(new_depth); - } - - 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; - int64_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, w_depth); - } - - 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; - int tmu; - - if (addr & 0x400000) - return; /*TREX != 0*/ - - tmu = (addr & 0x200000) ? 1 : 0; - - if (tmu && !voodoo->dual_tmus) - return; - -// 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[tmu] & 8) - s = (addr >> 1) & 0xfe; - else - { - if (voodoo->params.textureMode[tmu] & (1 << 31)) - s = addr & 0xfc; - else - s = (addr >> 1) & 0xfc; - } - - if (lod > LOD_MAX) - return; - -// if (addr >= 0x200000) -// return; - - if (voodoo->params.tformat[tmu] & 8) - addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2; - else - addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]); - if (voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) - { -// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); - flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu); - } - *(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val; -} - -#define WAKE_DELAY (TIMER_USEC * 100) -static inline void wake_fifo_thread(voodoo_t *voodoo) -{ - if (!voodoo->wake_timer) - { - /*Don't wake FIFO thread immediately - if we do that it will probably - process one word and go back to sleep, requiring it to be woken on - almost every write. Instead, wait a short while so that the CPU - emulation writes more data so we have more batched-up work.*/ - timer_process(); - voodoo->wake_timer = WAKE_DELAY; - timer_update_outstanding(); - } -} - -static inline void wake_fifo_thread_now(voodoo_t *voodoo) -{ - thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ -} - -static void voodoo_wake_timer(void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - - voodoo->wake_timer = 0; - - 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]; - - 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) { @@ -5621,13 +119,24 @@ static uint16_t voodoo_readw(uint32_t addr, void *p) if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ { + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + int y = (addr >> 11) & 0x3ff; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + } + voodoo->flush = 1; while (!FIFO_EMPTY) { - wake_fifo_thread_now(voodoo); + voodoo_wake_fifo_thread_now(voodoo); thread_wait_event(voodoo->fifo_not_full_event, 1); } - wait_for_render_thread_idle(voodoo); + voodoo_wait_for_render_thread_idle(voodoo); voodoo->flush = 0; return voodoo_fb_readw(addr, voodoo); @@ -5636,17 +145,6 @@ static uint16_t voodoo_readw(uint32_t addr, void *p) return 0xffff; } -static void voodoo_flush(voodoo_t *voodoo) -{ - voodoo->flush = 1; - while (!FIFO_EMPTY) - { - wake_fifo_thread_now(voodoo); - thread_wait_event(voodoo->fifo_not_full_event, 1); - } - wait_for_render_thread_idle(voodoo); - voodoo->flush = 0; -} static uint32_t voodoo_readl(uint32_t addr, void *p) { @@ -5663,13 +161,24 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) } else if (addr & 0x400000) /*Framebuffer*/ { + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + int y = (addr >> 11) & 0x3ff; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + } + voodoo->flush = 1; while (!FIFO_EMPTY) { - wake_fifo_thread_now(voodoo); + voodoo_wake_fifo_thread_now(voodoo); thread_wait_event(voodoo->fifo_not_full_event, 1); } - wait_for_render_thread_idle(voodoo); + voodoo_wait_for_render_thread_idle(voodoo); voodoo->flush = 0; temp = voodoo_fb_readl(addr, voodoo); @@ -5677,21 +186,47 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) 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->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) - temp |= 0x380; /*Busy*/ - if (!voodoo->v_retrace) - temp |= 0x40; - if (!voodoo->voodoo_busy) - wake_fifo_thread(voodoo); + { + int fifo_entries = FIFO_ENTRIES; + int swap_count = voodoo->swap_count; + int written = voodoo->cmd_written + voodoo->cmd_written_fifo; + int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr); + + if (SLI_ENABLED && voodoo->type != VOODOO_2) + { + voodoo_t *voodoo_other = (voodoo == voodoo->set->voodoos[0]) ? voodoo->set->voodoos[1] : voodoo->set->voodoos[0]; + int other_written = voodoo_other->cmd_written + voodoo_other->cmd_written_fifo; + + if (voodoo_other->swap_count > swap_count) + swap_count = voodoo_other->swap_count; + if ((voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx) > fifo_entries) + fifo_entries = voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx; + if ((other_written - voodoo_other->cmd_read) || + (voodoo_other->cmdfifo_depth_rd != voodoo_other->cmdfifo_depth_wr)) + busy = 1; + if (!voodoo_other->voodoo_busy) + voodoo_wake_fifo_thread(voodoo_other); + } + + fifo_size = 0xffff - fifo_entries; + temp = fifo_size << 12; + if (fifo_size < 0x40) + temp |= fifo_size; + else + temp |= 0x3f; + if (swap_count < 7) + temp |= (swap_count << 28); + else + temp |= (7 << 28); + if (!voodoo->v_retrace) + temp |= 0x40; + + if (busy) + temp |= 0x380; /*Busy*/ + + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_thread(voodoo); + } break; case SST_fbzColorPath: @@ -5759,7 +294,7 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) temp = voodoo->fbiInit0; break; case SST_fbiInit1: - temp = voodoo->fbiInit1 & ~5; /*Pass-thru board with one SST-1*/ + temp = voodoo->fbiInit1; break; case SST_fbiInit2: if (voodoo->initEnable & 0x04) @@ -5768,21 +303,30 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) temp = voodoo->fbiInit2; break; case SST_fbiInit3: - temp = voodoo->fbiInit3; + temp = voodoo->fbiInit3 | (1 << 10) | (2 << 8); break; case SST_vRetrace: - timer_clock(); temp = voodoo->line & 0x1fff; break; case SST_hvRetrace: - timer_clock(); - temp = voodoo->line & 0x1fff; - temp |= ((((voodoo->line_time - voodoo->timer_count) * voodoo->h_total) / voodoo->timer_count) << 16) & 0x7ff0000; + { + uint32_t line_time = (uint32_t)(voodoo->line_time >> 32); + uint32_t diff = (timer_get_ts_int(&voodoo->timer) > (tsc & 0xffffffff)) ? (timer_get_ts_int(&voodoo->timer) - (tsc & 0xffffffff)) : 0; + uint32_t pre_div = diff * voodoo->h_total; + uint32_t post_div = pre_div / line_time; + uint32_t h_pos = (voodoo->h_total - 1) - post_div; + + if (h_pos >= voodoo->h_total) + h_pos = 0; + + temp = voodoo->line & 0x1fff; + temp |= (h_pos << 16); + } break; case SST_fbiInit5: - temp = voodoo->fbiInit5 & ~0x41ff; + temp = voodoo->fbiInit5 & ~0x1ff; break; case SST_fbiInit6: temp = voodoo->fbiInit6; @@ -5810,10 +354,10 @@ static uint32_t voodoo_readl(uint32_t addr, void *p) break; default: - fatal("voodoo_readl : bad addr %08X\n", addr); + pclog("voodoo_readl : bad addr %08X\n", addr); temp = 0xffffffff; } - + return temp; } @@ -5822,39 +366,11 @@ 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 -= voodoo->burst_time; - else - cycles -= voodoo->write_time; - voodoo->last_write_addr = addr; + + cycles -= voodoo->write_time; 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)); + voodoo_queue_command(voodoo, addr | FIFO_WRITEW_FB, val); } static void voodoo_writel(uint32_t addr, uint32_t val, void *p) @@ -5874,11 +390,11 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) if (addr & 0x800000) /*Texture*/ { voodoo->tex_count++; - queue_command(voodoo, addr | FIFO_WRITEL_TEX, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_TEX, val); } else if (addr & 0x400000) /*Framebuffer*/ { - queue_command(voodoo, addr | FIFO_WRITEL_FB, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_FB, val); } else if ((addr & 0x200000) && (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)) { @@ -5886,7 +402,7 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) *(uint32_t *)&voodoo->fb_mem[(voodoo->cmdfifo_base + (addr & 0x3fffc)) & voodoo->fb_mask] = val; voodoo->cmdfifo_depth_wr++; if ((voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd) < 20) - wake_fifo_thread(voodoo); + voodoo_wake_fifo_thread(voodoo); } else switch (addr & 0x3fc) { @@ -5900,44 +416,46 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) case SST_swapbufferCMD: voodoo->cmd_written++; + thread_lock_mutex(voodoo->swap_mutex); voodoo->swap_count++; + thread_unlock_mutex(voodoo->swap_mutex); if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_thread(voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_triangleCMD: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo->cmd_written++; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_thread(voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_ftriangleCMD: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo->cmd_written++; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_thread(voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_fastfillCMD: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo->cmd_written++; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_thread(voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_nopCMD: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) return; voodoo->cmd_written++; - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); if (!voodoo->voodoo_busy) - wake_fifo_thread(voodoo); + voodoo_wake_fifo_threads(voodoo->set, voodoo); break; case SST_fbiInit4: @@ -5960,7 +478,10 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) if (voodoo->initEnable & 0x01) { voodoo->fbiInit0 = val; - svga_set_override(voodoo->svga, val & 1); + if (voodoo->set->nr_cards == 2) + svga_set_override(voodoo->svga, (voodoo->set->voodoos[0]->fbiInit0 | voodoo->set->voodoos[1]->fbiInit0) & 1); + else + svga_set_override(voodoo->svga, val & 1); if (val & FBIINIT0_GRAPHICS_RESET) { /*Reset display/draw buffer selection. This may not actually @@ -5975,7 +496,15 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) case SST_fbiInit1: if (voodoo->initEnable & 0x01) { - voodoo->fbiInit1 = val; + if ((voodoo->fbiInit1 & FBIINIT1_VIDEO_RESET) && !(val & FBIINIT1_VIDEO_RESET)) + { + voodoo->line = 0; + thread_lock_mutex(voodoo->swap_mutex); + voodoo->swap_count = 0; + thread_unlock_mutex(voodoo->swap_mutex); + voodoo->retrace_count = 0; + } + voodoo->fbiInit1 = (val & ~5) | (voodoo->fbiInit1 & 5); voodoo->write_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit1 & 2) ? 1 : 0); voodoo->burst_time = pci_burst_time * ((voodoo->fbiInit1 & 2) ? 2 : 1); // pclog("fbiInit1 write %08x - write_time=%i burst_time=%i\n", val, voodoo->write_time, voodoo->burst_time); @@ -6072,7 +601,7 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) case SST_fbiInit5: if (voodoo->initEnable & 0x01) - voodoo->fbiInit5 = val; + voodoo->fbiInit5 = (val & ~0x41e6) | (voodoo->fbiInit5 & 0x41e6); break; case SST_fbiInit6: if (voodoo->initEnable & 0x01) @@ -6080,7 +609,10 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) break; case SST_fbiInit7: if (voodoo->initEnable & 0x01) + { voodoo->fbiInit7 = val; + voodoo->cmdfifo_enabled = val & 0x100; + } break; case SST_cmdFifoBaseAddr: @@ -6106,296 +638,102 @@ static void voodoo_writel(uint32_t addr, uint32_t val, void *p) default: if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) { - fatal("Unknown register write in CMDFIFO mode %08x %08x\n", addr, val); + pclog("Unknown register write in CMDFIFO mode %08x %08x\n", addr, val); } else { - queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + voodoo_queue_command(voodoo, addr | FIFO_WRITEL_REG, val); } break; } } -static uint32_t cmdfifo_get(voodoo_t *voodoo) +static uint16_t voodoo_snoop_readw(uint32_t addr, void *p) { - uint32_t val; + voodoo_set_t *set = (voodoo_set_t *)p; - while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) - { - thread_wait_event(voodoo->wake_fifo_thread, -1); - thread_reset_event(voodoo->wake_fifo_thread); - } - - val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; + return voodoo_readw(addr, set->voodoos[0]); +} +static uint32_t voodoo_snoop_readl(uint32_t addr, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; - voodoo->cmdfifo_depth_rd++; - voodoo->cmdfifo_rp += 4; - -// pclog(" CMDFIFO get %08x\n", val); - return val; + return voodoo_readl(addr, set->voodoos[0]); } -static inline float cmdfifo_get_f(voodoo_t *voodoo) +static void voodoo_snoop_writew(uint32_t addr, uint16_t val, void *p) { - union - { - uint32_t i; - float f; - } tempif; - - tempif.i = cmdfifo_get(voodoo); - return tempif.f; + voodoo_set_t *set = (voodoo_set_t *)p; + + voodoo_writew(addr, val, set->voodoos[0]); + voodoo_writew(addr, val, set->voodoos[1]); +} +static void voodoo_snoop_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + voodoo_writel(addr, val, set->voodoos[0]); + voodoo_writel(addr, val, set->voodoos[1]); } -enum +static void voodoo_recalcmapping(voodoo_set_t *set) { - CMDFIFO3_PC_MASK_RGB = (1 << 10), - CMDFIFO3_PC_MASK_ALPHA = (1 << 11), - CMDFIFO3_PC_MASK_Z = (1 << 12), - CMDFIFO3_PC_MASK_Wb = (1 << 13), - CMDFIFO3_PC_MASK_W0 = (1 << 14), - CMDFIFO3_PC_MASK_S0_T0 = (1 << 15), - CMDFIFO3_PC_MASK_W1 = (1 << 16), - CMDFIFO3_PC_MASK_S1_T1 = (1 << 17), - - CMDFIFO3_PC = (1 << 28) -}; - -static void fifo_thread(void *param) -{ - voodoo_t *voodoo = (voodoo_t *)param; - - while (1) + if (set->nr_cards == 2) { - 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) + if (set->voodoos[0]->pci_enable && set->voodoos[0]->memBaseAddr) { - 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) + if (set->voodoos[0]->type == VOODOO_2 && set->voodoos[1]->initEnable & (1 << 23)) { - 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 & 0x400000)) - voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); - break; + pclog("voodoo_recalcmapping (pri) with snoop : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->voodoos[0]->mapping); + mem_mapping_set_addr(&set->snoop_mapping, set->voodoos[0]->memBaseAddr, 0x01000000); } - 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; + else if (set->voodoos[1]->pci_enable && (set->voodoos[0]->memBaseAddr == set->voodoos[1]->memBaseAddr)) + { + pclog("voodoo_recalcmapping (pri) (sec) same addr : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->voodoos[0]->mapping); + mem_mapping_disable(&set->voodoos[1]->mapping); + mem_mapping_set_addr(&set->snoop_mapping, set->voodoos[0]->memBaseAddr, 0x01000000); + return; + } + else + { + pclog("voodoo_recalcmapping (pri) : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->snoop_mapping); + mem_mapping_set_addr(&set->voodoos[0]->mapping, set->voodoos[0]->memBaseAddr, 0x01000000); + } + } + else + { + pclog("voodoo_recalcmapping (pri) : disabled\n"); + mem_mapping_disable(&set->voodoos[0]->mapping); } - while (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) + if (set->voodoos[1]->pci_enable && set->voodoos[1]->memBaseAddr) { - uint64_t start_time = timer_read(); - uint64_t end_time; - uint32_t header = cmdfifo_get(voodoo); - uint32_t addr; - uint32_t mask; - int smode; - int num; - int num_verticies; - int v_num; - -// pclog(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); - - switch (header & 7) - { - case 0: -// pclog("CMDFIFO0\n"); - switch ((header >> 3) & 7) - { - case 0: /*NOP*/ - break; - - case 3: /*JMP local frame buffer*/ - voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; -// pclog("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); - break; - - default: - fatal("Bad CMDFIFO0 %08x\n", header); - } - break; - - case 1: - num = header >> 16; - addr = (header & 0x7ff8) >> 1; -// pclog("CMDFIFO1 addr=%08x\n",addr); - while (num--) - { - uint32_t val = cmdfifo_get(voodoo); - if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || - (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) - voodoo->cmd_written++; - - voodoo_reg_writel(addr, val, voodoo); - - if (header & (1 << 15)) - addr += 4; - } - break; - - case 3: - num = (header >> 29) & 7; - mask = header;//(header >> 10) & 0xff; - smode = (header >> 22) & 0xf; - voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); - num_verticies = (header >> 6) & 0xf; - v_num = 0; - if (((header >> 3) & 7) == 2) - v_num = 1; -// pclog("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff); -// pclog("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7); - - while (num_verticies--) - { - voodoo->verts[3].sVx = cmdfifo_get_f(voodoo); - voodoo->verts[3].sVy = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_RGB) - { - if (header & CMDFIFO3_PC) - { - uint32_t val = cmdfifo_get(voodoo); - voodoo->verts[3].sBlue = (float)(val & 0xff); - voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); - voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); - voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); - } - else - { - voodoo->verts[3].sRed = cmdfifo_get_f(voodoo); - voodoo->verts[3].sGreen = cmdfifo_get_f(voodoo); - voodoo->verts[3].sBlue = cmdfifo_get_f(voodoo); - } - } - if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC)) - voodoo->verts[3].sAlpha = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_Z) - voodoo->verts[3].sVz = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_Wb) - voodoo->verts[3].sWb = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_W0) - voodoo->verts[3].sW0 = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_S0_T0) - { - voodoo->verts[3].sS0 = cmdfifo_get_f(voodoo); - voodoo->verts[3].sT0 = cmdfifo_get_f(voodoo); - } - if (mask & CMDFIFO3_PC_MASK_W1) - voodoo->verts[3].sW1 = cmdfifo_get_f(voodoo); - if (mask & CMDFIFO3_PC_MASK_S1_T1) - { - voodoo->verts[3].sS1 = cmdfifo_get_f(voodoo); - voodoo->verts[3].sT1 = cmdfifo_get_f(voodoo); - } - if (v_num) - voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); - else - voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); - v_num++; - if (v_num == 3 && ((header >> 3) & 7) == 0) - v_num = 0; - } - break; - - case 4: - num = (header >> 29) & 7; - mask = (header >> 15) & 0x3fff; - addr = (header & 0x7ff8) >> 1; -// pclog("CMDFIFO4 addr=%08x\n",addr); - while (mask) - { - if (mask & 1) - { - uint32_t val = cmdfifo_get(voodoo); - if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || - (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) - voodoo->cmd_written++; - - voodoo_reg_writel(addr, val, voodoo); - } - - addr += 4; - mask >>= 1; - } - while (num--) - cmdfifo_get(voodoo); - break; - - case 5: - if (header & 0x3fc0000) - fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); - num = (header >> 3) & 0x7ffff; - addr = cmdfifo_get(voodoo) & 0xffffff; -// pclog("CMDFIFO5 addr=%08x num=%i\n", addr, num); - switch (header >> 30) - { - case 2: /*Framebuffer*/ - while (num--) - { - uint32_t val = cmdfifo_get(voodoo); - voodoo_fb_writel(addr, val, voodoo); - addr += 4; - } - break; - case 3: /*Texture*/ - while (num--) - { - uint32_t val = cmdfifo_get(voodoo); - voodoo_tex_writel(addr, val, voodoo); - addr += 4; - } - break; - - default: - fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp); - } - break; - - default: - pclog("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); - } - - end_time = timer_read(); - voodoo_time += end_time - start_time; + pclog("voodoo_recalcmapping (sec) : memBaseAddr %08X\n", set->voodoos[1]->memBaseAddr); + mem_mapping_set_addr(&set->voodoos[1]->mapping, set->voodoos[1]->memBaseAddr, 0x01000000); + } + else + { + pclog("voodoo_recalcmapping (sec) : disabled\n"); + mem_mapping_disable(&set->voodoos[1]->mapping); } - - voodoo->voodoo_busy = 0; - } -} - -static void voodoo_recalcmapping(voodoo_t *voodoo) -{ - if (voodoo->pci_enable && voodoo->memBaseAddr) - { - pclog("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo->memBaseAddr); - mem_mapping_set_addr(&voodoo->mapping, voodoo->memBaseAddr, 0x01000000); } else { - pclog("voodoo_recalcmapping : disabled\n"); - mem_mapping_disable(&voodoo->mapping); + voodoo_t *voodoo = set->voodoos[0]; + + if (voodoo->pci_enable && voodoo->memBaseAddr) + { + pclog("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo->memBaseAddr); + mem_mapping_set_addr(&voodoo->mapping, voodoo->memBaseAddr, 0x01000000); + } + else + { + pclog("voodoo_recalcmapping : disabled\n"); + mem_mapping_disable(&voodoo->mapping); + } } } @@ -6459,12 +797,12 @@ void voodoo_pci_write(int func, int addr, uint8_t val, void *p) { case 0x04: voodoo->pci_enable = val & 2; - voodoo_recalcmapping(voodoo); + voodoo_recalcmapping(voodoo->set); break; case 0x13: voodoo->memBaseAddr = val << 24; - voodoo_recalcmapping(voodoo); + voodoo_recalcmapping(voodoo->set); break; case 0x40: @@ -6475,541 +813,146 @@ void voodoo_pci_write(int func, int addr, uint8_t val, void *p) break; case 0x42: voodoo->initEnable = (voodoo->initEnable & ~0x00ff0000) | (val << 16); + voodoo_recalcmapping(voodoo->set); break; case 0x43: voodoo->initEnable = (voodoo->initEnable & ~0xff000000) | (val << 24); + voodoo_recalcmapping(voodoo->set); 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 FILTDIV 256 - -static int FILTCAP, FILTCAPG, FILTCAPB = 0; /* color filter threshold values */ - -static void voodoo_generate_filter_v1(voodoo_t *voodoo) -{ - int g, h; - float difference, diffg, diffb; - float thiscol, thiscolg, thiscolb, lined; - float fcr, fcg, fcb; - - fcr = FILTCAP * 5; - fcg = FILTCAPG * 6; - fcb = FILTCAPB * 5; - - for (g=0;g FILTCAP) - difference = FILTCAP; - if (difference < -FILTCAP) - difference = -FILTCAP; - - if (diffg > FILTCAPG) - diffg = FILTCAPG; - if (diffg < -FILTCAPG) - diffg = -FILTCAPG; - - if (diffb > FILTCAPB) - diffb = FILTCAPB; - if (diffb < -FILTCAPB) - diffb = -FILTCAPB; - - // hack - to make it not bleed onto black - //if (g == 0){ - //difference = diffg = diffb = 0; - //} - - if ((difference < fcr) || (-difference > -fcr)) - thiscol = g + (difference / 2); - if ((diffg < fcg) || (-diffg > -fcg)) - thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ - if ((diffb < fcb) || (-diffb > -fcb)) - thiscolb = g + (diffb / 2); - - if (thiscol < 0) - thiscol = 0; - if (thiscol > FILTDIV-1) - thiscol = FILTDIV-1; - - if (thiscolg < 0) - thiscolg = 0; - if (thiscolg > FILTDIV-1) - thiscolg = FILTDIV-1; - - if (thiscolb < 0) - thiscolb = 0; - if (thiscolb > FILTDIV-1) - thiscolb = FILTDIV-1; - - voodoo->thefilter[g][h] = thiscol; - voodoo->thefilterg[g][h] = thiscolg; - voodoo->thefilterb[g][h] = thiscolb; - } - - lined = g + 4; - if (lined > 255) - lined = 255; - voodoo->purpleline[g][0] = lined; - voodoo->purpleline[g][2] = lined; - - lined = g + 0; - if (lined > 255) - lined = 255; - voodoo->purpleline[g][1] = lined; - } -} - -static void voodoo_generate_filter_v2(voodoo_t *voodoo) -{ - int g, h; - float difference; - float thiscol, thiscolg, thiscolb, lined; - float clr, clg, clb = 0; - float fcr, fcg, fcb = 0; - - // pre-clamping - - fcr = FILTCAP; - fcg = FILTCAPG; - fcb = FILTCAPB; - - if (fcr > 32) fcr = 32; - if (fcg > 32) fcg = 32; - if (fcb > 32) fcb = 32; - - for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into - { - for (h=0;h<256;h++) // pixel 2 - our main pixel - { - float avg; - float avgdiff; - - difference = (float)(g - h); - avg = (float)((g + g + g + g + h) / 5); - avgdiff = avg - (float)((g + h + h + h + h) / 5); - if (avgdiff < 0) avgdiff *= -1; - if (difference < 0) difference *= -1; - - thiscol = thiscolg = thiscolb = g; - - // try lighten - if (h > g) - { - clr = clg = clb = avgdiff; - - if (clr>fcr) clr=fcr; - if (clg>fcg) clg=fcg; - if (clb>fcb) clb=fcb; - - - thiscol = g + clr; - thiscolg = g + clg; - thiscolb = g + clb; - - if (thiscol>g+FILTCAP) - thiscol=g+FILTCAP; - if (thiscolg>g+FILTCAPG) - thiscolg=g+FILTCAPG; - if (thiscolb>g+FILTCAPB) - thiscolb=g+FILTCAPB; - - - if (thiscol>g+avgdiff) - thiscol=g+avgdiff; - if (thiscolg>g+avgdiff) - thiscolg=g+avgdiff; - if (thiscolb>g+avgdiff) - thiscolb=g+avgdiff; - - } - - if (difference > FILTCAP) - thiscol = g; - if (difference > FILTCAPG) - thiscolg = g; - if (difference > FILTCAPB) - thiscolb = g; - - // clamp - if (thiscol < 0) thiscol = 0; - if (thiscolg < 0) thiscolg = 0; - if (thiscolb < 0) thiscolb = 0; - - if (thiscol > 255) thiscol = 255; - if (thiscolg > 255) thiscolg = 255; - if (thiscolb > 255) thiscolb = 255; - - // add to the table - voodoo->thefilter[g][h] = (thiscol); - voodoo->thefilterg[g][h] = (thiscolg); - voodoo->thefilterb[g][h] = (thiscolb); - - // debug the ones that don't give us much of a difference - //if (difference < FILTCAP) - //pclog("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb); - } - - lined = g + 3; - if (lined > 255) - lined = 255; - voodoo->purpleline[g][0] = lined; - voodoo->purpleline[g][1] = 0; - voodoo->purpleline[g][2] = lined; - } -} - -static void voodoo_threshold_check(voodoo_t *voodoo) -{ - int r, g, b; - - if (!voodoo->scrfilterEnabled) - return; /* considered disabled; don't check and generate */ - - /* Check for changes, to generate anew table */ - if (voodoo->scrfilterThreshold != voodoo->scrfilterThresholdOld) - { - r = (voodoo->scrfilterThreshold >> 16) & 0xFF; - g = (voodoo->scrfilterThreshold >> 8 ) & 0xFF; - b = voodoo->scrfilterThreshold & 0xFF; - - FILTCAP = r; - FILTCAPG = g; - FILTCAPB = b; - - pclog("Voodoo Filter Threshold Check: %06x - RED %i GREEN %i BLUE %i\n", voodoo->scrfilterThreshold, r, g, b); - - voodoo->scrfilterThresholdOld = voodoo->scrfilterThreshold; - - if (voodoo->type == VOODOO_2) - voodoo_generate_filter_v2(voodoo); - else - voodoo_generate_filter_v1(voodoo); - } -} - -static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) -{ - int x; - - // Scratchpad for avoiding feedback streaks - uint8_t fil3[(voodoo->h_disp) * 3]; - - /* 16 to 32-bit */ - for (x=0; x> 5) & 63) << 2); - fil[x*3+2] = (((src[x] >> 11) & 31) << 3); - - // Copy to our scratchpads - fil3[x*3+0] = fil[x*3+0]; - fil3[x*3+1] = fil[x*3+1]; - fil3[x*3+2] = fil[x*3+2]; - } - - - /* lines */ - - if (line & 1) - { - for (x=0; xpurpleline[fil[x*3]][0]; - fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1]; - fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2]; - } - } - - - /* filtering time */ - - for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; - fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; - fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; - } - - for (x=1; xthefilterb[fil3[x*3]][fil3[ (x-1) *3]]; - fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x-1) *3+1]]; - fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x-1) *3+2]]; - } - - for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; - fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; - fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; - } - - for (x=0; xthefilterb[fil3[x*3]][fil3[ (x+1) *3]]; - fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x+1) *3+1]]; - fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x+1) *3+2]]; - } -} - - -static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) -{ - int x; - - // Scratchpad for blending filter - uint8_t fil3[(voodoo->h_disp) * 3]; - - /* 16 to 32-bit */ - for (x=0; x> 5) & 63) << 2); - fil3[x*3+2] = fil[x*3+2] = (((src[x] >> 11) & 31) << 3); - } - - /* filtering time */ - - for (x=1; xthefilterb [((src[x+3] & 31) << 3)] [((src[x] & 31) << 3)]; - fil3[(x+3)*3+1] = voodoo->thefilterg [(((src[x+3] >> 5) & 63) << 2)] [(((src[x] >> 5) & 63) << 2)]; - fil3[(x+3)*3+2] = voodoo->thefilter [(((src[x+3] >> 11) & 31) << 3)] [(((src[x] >> 11) & 31) << 3)]; - - fil[(x+2)*3] = voodoo->thefilterb [fil3[(x+2)*3]][((src[x] & 31) << 3)]; - fil[(x+2)*3+1] = voodoo->thefilterg [fil3[(x+2)*3+1]][(((src[x] >> 5) & 63) << 2)]; - fil[(x+2)*3+2] = voodoo->thefilter [fil3[(x+2)*3+2]][(((src[x] >> 11) & 31) << 3)]; - - fil3[(x+1)*3] = voodoo->thefilterb [fil[(x+1)*3]][((src[x] & 31) << 3)]; - fil3[(x+1)*3+1] = voodoo->thefilterg [fil[(x+1)*3+1]][(((src[x] >> 5) & 63) << 2)]; - fil3[(x+1)*3+2] = voodoo->thefilter [fil[(x+1)*3+2]][(((src[x] >> 11) & 31) << 3)]; - - fil[(x-1)*3] = voodoo->thefilterb [fil3[(x-1)*3]][((src[x] & 31) << 3)]; - fil[(x-1)*3+1] = voodoo->thefilterg [fil3[(x-1)*3+1]][(((src[x] >> 5) & 63) << 2)]; - fil[(x-1)*3+2] = voodoo->thefilter [fil3[(x-1)*3+2]][(((src[x] >> 11) & 31) << 3)]; - } - - // unroll for edge cases - - fil3[(column-3)*3] = voodoo->thefilterb [((src[column-3] & 31) << 3)] [((src[column] & 31) << 3)]; - fil3[(column-3)*3+1] = voodoo->thefilterg [(((src[column-3] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; - fil3[(column-3)*3+2] = voodoo->thefilter [(((src[column-3] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; - - fil3[(column-2)*3] = voodoo->thefilterb [((src[column-2] & 31) << 3)] [((src[column] & 31) << 3)]; - fil3[(column-2)*3+1] = voodoo->thefilterg [(((src[column-2] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; - fil3[(column-2)*3+2] = voodoo->thefilter [(((src[column-2] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; - - fil3[(column-1)*3] = voodoo->thefilterb [((src[column-1] & 31) << 3)] [((src[column] & 31) << 3)]; - fil3[(column-1)*3+1] = voodoo->thefilterg [(((src[column-1] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; - fil3[(column-1)*3+2] = voodoo->thefilter [(((src[column-1] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; - - fil[(column-2)*3] = voodoo->thefilterb [fil3[(column-2)*3]][((src[column] & 31) << 3)]; - fil[(column-2)*3+1] = voodoo->thefilterg [fil3[(column-2)*3+1]][(((src[column] >> 5) & 63) << 2)]; - fil[(column-2)*3+2] = voodoo->thefilter [fil3[(column-2)*3+2]][(((src[column] >> 11) & 31) << 3)]; - - fil[(column-1)*3] = voodoo->thefilterb [fil3[(column-1)*3]][((src[column] & 31) << 3)]; - fil[(column-1)*3+1] = voodoo->thefilterg [fil3[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; - fil[(column-1)*3+2] = voodoo->thefilter [fil3[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; - - fil3[(column-1)*3] = voodoo->thefilterb [fil[(column-1)*3]][((src[column] & 31) << 3)]; - fil3[(column-1)*3+1] = voodoo->thefilterg [fil[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; - fil3[(column-1)*3+2] = voodoo->thefilter [fil[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; -} - - -void voodoo_callback(void *p) -{ - voodoo_t *voodoo = (voodoo_t *)p; - - 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])[32]; - 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; - video_wait_for_buffer(); - } - if (voodoo->line > voodoo->dirty_line_high) - voodoo->dirty_line_high = voodoo->line; - - if (voodoo->scrfilter && voodoo->scrfilterEnabled) - { - uint8_t fil[(voodoo->h_disp) * 3]; /* interleaved 24-bit RGB */ - - if (voodoo->type == VOODOO_2) - voodoo_filterline_v2(voodoo, fil, voodoo->h_disp, src, voodoo->line); - else - voodoo_filterline_v1(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-1, 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]; + voodoo_set_t *voodoo_set = (voodoo_set_t *)p; + voodoo_t *voodoo = voodoo_set->voodoos[0]; + voodoo_t *voodoo_slave = voodoo_set->voodoos[1]; + char temps[512], temps2[256]; + int pixel_count_current[4]; int pixel_count_total; - int texel_count_current[2]; + int texel_count_current[4]; int texel_count_total; + int render_time[4]; uint64_t new_time = timer_read(); uint64_t status_diff = new_time - status_time; status_time = new_time; + int c; 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]); - texel_count_current[0] = voodoo->texel_count[0]; - texel_count_current[1] = voodoo->texel_count[1]; - texel_count_total = (texel_count_current[0] + texel_count_current[1]) - (voodoo->texel_count_old[0] + voodoo->texel_count_old[1]); - sprintf(temps, "%f Mpixels/sec (%f)\n%f Mtexels/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*/, + for (c = 0; c < 4; c++) + { + pixel_count_current[c] = voodoo->pixel_count[c]; + texel_count_current[c] = voodoo->texel_count[c]; + render_time[c] = voodoo->render_time[c]; + } + if (voodoo_set->nr_cards == 2) + { + for (c = 0; c < 4; c++) + { + pixel_count_current[c] += voodoo_slave->pixel_count[c]; + texel_count_current[c] += voodoo_slave->texel_count[c]; + render_time[c] = (render_time[c] + voodoo_slave->render_time[c]) / 2; + } + } + pixel_count_total = (pixel_count_current[0] + pixel_count_current[1] + pixel_count_current[2] + pixel_count_current[3]) - + (voodoo->pixel_count_old[0] + voodoo->pixel_count_old[1] + voodoo->pixel_count_old[2] + voodoo->pixel_count_old[3]); + texel_count_total = (texel_count_current[0] + texel_count_current[1] + texel_count_current[2] + texel_count_current[3]) - + (voodoo->texel_count_old[0] + voodoo->texel_count_old[1] + voodoo->texel_count_old[2] + voodoo->texel_count_old[3]); + sprintf(temps, "%f Mpixels/sec (%f)\n%f Mtexels/sec (%f)\n%f ktris/sec\n%f%% CPU (%f%% real)\n%d frames/sec (%i)\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)pixel_count_total/1000000.0) / ((double)render_time[0] / status_diff), (double)texel_count_total/1000000.0, - ((double)texel_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); + ((double)texel_count_total/1000000.0) / ((double)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); + if (voodoo->render_threads >= 2) + { + sprintf(temps2, "%f%% CPU (%f%% real)\n", + ((double)voodoo->render_time[1] * 100.0) / timer_freq, ((double)voodoo->render_time[1] * 100.0) / status_diff); + strncat(temps, temps2, sizeof(temps)-1); + } + if (voodoo->render_threads == 4) + { + sprintf(temps2, "%f%% CPU (%f%% real)\n%f%% CPU (%f%% real)\n", + ((double)voodoo->render_time[2] * 100.0) / timer_freq, ((double)voodoo->render_time[2] * 100.0) / status_diff, + ((double)voodoo->render_time[3] * 100.0) / timer_freq, ((double)voodoo->render_time[3] * 100.0) / status_diff); + strncat(temps, temps2, sizeof(temps)-1); + } + if (voodoo_set->nr_cards == 2) + { + sprintf(temps2, "%f%% CPU (%f%% real)\n", + ((double)voodoo_slave->render_time[0] * 100.0) / timer_freq, ((double)voodoo_slave->render_time[0] * 100.0) / status_diff); + strncat(temps, temps2, sizeof(temps)-1); + + if (voodoo_slave->render_threads >= 2) + { + sprintf(temps2, "%f%% CPU (%f%% real)\n", + ((double)voodoo_slave->render_time[1] * 100.0) / timer_freq, ((double)voodoo_slave->render_time[1] * 100.0) / status_diff); + strncat(temps, temps2, sizeof(temps)-1); + } + if (voodoo_slave->render_threads == 4) + { + sprintf(temps2, "%f%% CPU (%f%% real)\n%f%% CPU (%f%% real)\n", + ((double)voodoo_slave->render_time[2] * 100.0) / timer_freq, ((double)voodoo_slave->render_time[2] * 100.0) / status_diff, + ((double)voodoo_slave->render_time[3] * 100.0) / timer_freq, ((double)voodoo_slave->render_time[3] * 100.0) / status_diff); + strncat(temps, temps2, sizeof(temps)-1); + } + } strncat(s, temps, max_len); - voodoo->pixel_count_old[0] = pixel_count_current[0]; - voodoo->pixel_count_old[1] = pixel_count_current[1]; - voodoo->texel_count_old[0] = texel_count_current[0]; - voodoo->texel_count_old[1] = texel_count_current[1]; + for (c = 0; c < 4; c++) + { + voodoo->pixel_count_old[c] = pixel_count_current[c]; + voodoo->texel_count_old[c] = texel_count_current[c]; + voodoo->render_time[c] = 0; + } 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->time = 0; + if (voodoo_set->nr_cards == 2) + { + for (c = 0; c < 4; c++) + { + voodoo_slave->pixel_count_old[c] = pixel_count_current[c]; + voodoo_slave->texel_count_old[c] = texel_count_current[c]; + voodoo_slave->render_time[c] = 0; + } + voodoo_slave->tri_count = voodoo_slave->frame_count = 0; + voodoo_slave->rd_count = voodoo_slave->wr_count = voodoo_slave->tex_count = 0; + voodoo_slave->time = 0; + } voodoo_recomp = 0; } static void voodoo_speed_changed(void *p) { - voodoo_t *voodoo = (voodoo_t *)p; + voodoo_set_t *voodoo_set = (voodoo_set_t *)p; - voodoo_pixelclock_update(voodoo); - voodoo->read_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit4 & 1) ? 2 : 1); - voodoo->write_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit1 & 2) ? 1 : 0); - voodoo->burst_time = pci_burst_time * ((voodoo->fbiInit1 & 2) ? 2 : 1); + voodoo_pixelclock_update(voodoo_set->voodoos[0]); + voodoo_set->voodoos[0]->read_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit4 & 1) ? 2 : 1); + voodoo_set->voodoos[0]->write_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit1 & 2) ? 1 : 0); + voodoo_set->voodoos[0]->burst_time = pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit1 & 2) ? 2 : 1); + if (voodoo_set->nr_cards == 2) + { + voodoo_pixelclock_update(voodoo_set->voodoos[1]); + voodoo_set->voodoos[1]->read_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit4 & 1) ? 2 : 1); + voodoo_set->voodoos[1]->write_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit1 & 2) ? 1 : 0); + voodoo_set->voodoos[1]->burst_time = pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit1 & 2) ? 2 : 1); + } // pclog("Voodoo read_time=%i write_time=%i burst_time=%i %08x %08x\n", voodoo->read_time, voodoo->write_time, voodoo->burst_time, voodoo->fbiInit1, voodoo->fbiInit4); } -void *voodoo_init() +void *voodoo_card_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->dithersub_enabled = device_get_config_int("dithersub"); voodoo->scrfilter = device_get_config_int("dacfilter"); voodoo->texture_size = device_get_config_int("texture_memory"); voodoo->texture_mask = (voodoo->texture_size << 20) - 1; @@ -7052,18 +995,18 @@ void *voodoo_init() for (c = 0; c < TEX_CACHE_MAX; c++) { - voodoo->texture_cache[0][c].data = malloc((256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1) * 4); + voodoo->texture_cache[0][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); voodoo->texture_cache[0][c].base = -1; /*invalid*/ voodoo->texture_cache[0][c].refcount = 0; if (voodoo->dual_tmus) { - voodoo->texture_cache[1][c].data = malloc((256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1) * 4); + voodoo->texture_cache[1][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); voodoo->texture_cache[1][c].base = -1; /*invalid*/ voodoo->texture_cache[1][c].refcount = 0; } } - timer_add(voodoo_callback, &voodoo->timer_count, TIMER_ALWAYS_ENABLED, voodoo); + timer_add(&voodoo->timer, voodoo_callback, voodoo, 1); voodoo->svga = svga_get_pri(); voodoo->fbiInit0 = 0; @@ -7071,16 +1014,25 @@ void *voodoo_init() 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_render_thread[2] = thread_create_event(); + voodoo->wake_render_thread[3] = 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); - - timer_add(voodoo_wake_timer, &voodoo->wake_timer, &voodoo->wake_timer, (void *)voodoo); + voodoo->render_not_full_event[2] = thread_create_event(); + voodoo->render_not_full_event[3] = thread_create_event(); + voodoo->fifo_thread = thread_create(voodoo_fifo_thread, voodoo); + voodoo->render_thread[0] = thread_create(voodoo_render_thread_1, voodoo); + if (voodoo->render_threads >= 2) + voodoo->render_thread[1] = thread_create(voodoo_render_thread_2, voodoo); + if (voodoo->render_threads == 4) + { + voodoo->render_thread[2] = thread_create(voodoo_render_thread_3, voodoo); + voodoo->render_thread[3] = thread_create(voodoo_render_thread_4, voodoo); + } + voodoo->swap_mutex = thread_create_mutex(); + timer_add(&voodoo->wake_timer, voodoo_wake_timer, (void *)voodoo, 0); for (c = 0; c < 0x100; c++) { @@ -7140,28 +1092,214 @@ void *voodoo_init() return voodoo; } -void voodoo_close(void *p) +void *voodoo_2d3d_card_init(int type) { + int c; + voodoo_t *voodoo = malloc(sizeof(voodoo_t)); + memset(voodoo, 0, sizeof(voodoo_t)); + + voodoo->bilinear_enabled = device_get_config_int("bilinear"); + voodoo->dithersub_enabled = device_get_config_int("dithersub"); + voodoo->scrfilter = device_get_config_int("dacfilter"); + 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->type = type; + voodoo->dual_tmus = (type == VOODOO_3) ? 1 : 0; + + /*generate filter lookup tables*/ + voodoo_generate_filter_v2(voodoo); + + for (c = 0; c < TEX_CACHE_MAX; c++) + { + voodoo->texture_cache[0][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[0][c].base = -1; /*invalid*/ + voodoo->texture_cache[0][c].refcount = 0; + if (voodoo->dual_tmus) + { + voodoo->texture_cache[1][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[1][c].base = -1; /*invalid*/ + voodoo->texture_cache[1][c].refcount = 0; + } + } + + timer_add(&voodoo->timer, voodoo_callback, voodoo, 1); + + 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_render_thread[2] = thread_create_event(); + voodoo->wake_render_thread[3] = 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->render_not_full_event[2] = thread_create_event(); + voodoo->render_not_full_event[3] = thread_create_event(); + voodoo->fifo_thread = thread_create(voodoo_fifo_thread, voodoo); + voodoo->render_thread[0] = thread_create(voodoo_render_thread_1, voodoo); + if (voodoo->render_threads >= 2) + voodoo->render_thread[1] = thread_create(voodoo_render_thread_2, voodoo); + if (voodoo->render_threads == 4) + { + voodoo->render_thread[2] = thread_create(voodoo_render_thread_3, voodoo); + voodoo->render_thread[3] = thread_create(voodoo_render_thread_4, voodoo); + } + voodoo->swap_mutex = thread_create_mutex(); + timer_add(&voodoo->wake_timer, voodoo_wake_timer, (void *)voodoo, 0); + + 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 + + voodoo->disp_buffer = 0; + voodoo->draw_buffer = 1; + + return voodoo; +} + +void *voodoo_init() +{ + voodoo_set_t *voodoo_set = malloc(sizeof(voodoo_set_t)); + uint32_t tmuConfig = 1; + int type; + memset(voodoo_set, 0, sizeof(voodoo_set_t)); + + type = device_get_config_int("type"); + + voodoo_set->nr_cards = device_get_config_int("sli") ? 2 : 1; + voodoo_set->voodoos[0] = voodoo_card_init(); + voodoo_set->voodoos[0]->set = voodoo_set; + if (voodoo_set->nr_cards == 2) + { + voodoo_set->voodoos[1] = voodoo_card_init(); + + voodoo_set->voodoos[1]->set = voodoo_set; + + if (type == VOODOO_2) + { + voodoo_set->voodoos[0]->fbiInit5 |= FBIINIT5_MULTI_CVG; + voodoo_set->voodoos[1]->fbiInit5 |= FBIINIT5_MULTI_CVG; + } + else + { + voodoo_set->voodoos[0]->fbiInit1 |= FBIINIT1_MULTI_SST; + voodoo_set->voodoos[1]->fbiInit1 |= FBIINIT1_MULTI_SST; + } + } + + switch (type) + { + case VOODOO_1: + if (voodoo_set->nr_cards == 2) + tmuConfig = 1 | (3 << 3); + else + tmuConfig = 1; + break; + case VOODOO_SB50: + if (voodoo_set->nr_cards == 2) + tmuConfig = 1 | (3 << 3) | (3 << 6) | (2 << 9); + else + tmuConfig = 1 | (3 << 6); + break; + case VOODOO_2: + tmuConfig = 1 | (3 << 6); + break; + } + + voodoo_set->voodoos[0]->tmuConfig = tmuConfig; + if (voodoo_set->nr_cards == 2) + voodoo_set->voodoos[1]->tmuConfig = tmuConfig; + + mem_mapping_add(&voodoo_set->snoop_mapping, 0, 0, NULL, voodoo_snoop_readw, voodoo_snoop_readl, NULL, voodoo_snoop_writew, voodoo_snoop_writel, NULL, MEM_MAPPING_EXTERNAL, voodoo_set); + + return voodoo_set; +} + +void voodoo_card_close(voodoo_t *voodoo) +{ +#ifndef RELEASE_BUILD FILE *f; - voodoo_t *voodoo = (voodoo_t *)p; +#endif int c; #ifndef RELEASE_BUILD - f = romfopen("texram.dmp", "wb"); - fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); - fclose(f); - if (voodoo->dual_tmus) + if (voodoo->tex_mem[0]) { - f = romfopen("texram2.dmp", "wb"); - fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); + f = romfopen("texram.dmp", "wb"); + fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); fclose(f); + if (voodoo->dual_tmus) + { + f = romfopen("texram2.dmp", "wb"); + fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); + fclose(f); + } } #endif thread_kill(voodoo->fifo_thread); thread_kill(voodoo->render_thread[0]); - if (voodoo->render_threads == 2) + if (voodoo->render_threads >= 2) thread_kill(voodoo->render_thread[1]); + if (voodoo->render_threads == 4) + { + thread_kill(voodoo->render_thread[2]); + thread_kill(voodoo->render_thread[3]); + } thread_destroy_event(voodoo->fifo_not_full_event); thread_destroy_event(voodoo->wake_main_thread); thread_destroy_event(voodoo->wake_fifo_thread); @@ -7179,13 +1317,27 @@ void voodoo_close(void *p) #ifndef NO_CODEGEN voodoo_codegen_close(voodoo); #endif - free(voodoo->fb_mem); - if (voodoo->dual_tmus) - free(voodoo->tex_mem[1]); - free(voodoo->tex_mem[0]); + if (voodoo->type < VOODOO_BANSHEE && voodoo->fb_mem) + { + free(voodoo->fb_mem); + if (voodoo->dual_tmus) + free(voodoo->tex_mem[1]); + free(voodoo->tex_mem[0]); + } free(voodoo); } +void voodoo_close(void *p) +{ + voodoo_set_t *voodoo_set = (voodoo_set_t *)p; + + if (voodoo_set->nr_cards == 2) + voodoo_card_close(voodoo_set->voodoos[1]); + voodoo_card_close(voodoo_set->voodoos[0]); + + free(voodoo_set); +} + static device_config_t voodoo_config[] = { { @@ -7258,6 +1410,12 @@ static device_config_t voodoo_config[] = .type = CONFIG_BINARY, .default_int = 1 }, + { + .name = "dithersub", + .description = "Dither subtraction", + .type = CONFIG_BINARY, + .default_int = 1 + }, { .name = "dacfilter", .description = "Screen Filter", @@ -7278,12 +1436,22 @@ static device_config_t voodoo_config[] = .description = "2", .value = 2 }, + { + .description = "4", + .value = 4 + }, { .description = "" } }, .default_int = 2 }, + { + .name = "sli", + .description = "SLI", + .type = CONFIG_BINARY, + .default_int = 0 + }, #ifndef NO_CODEGEN { .name = "recompiler", diff --git a/src/vid_voodoo_banshee.c b/src/vid_voodoo_banshee.c new file mode 100644 index 0000000..cf676a0 --- /dev/null +++ b/src/vid_voodoo_banshee.c @@ -0,0 +1,2900 @@ +#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_ddc.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_voodoo_banshee.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_display.h" +#include "vid_voodoo_fifo.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "x86.h" + +#ifdef CLAMP +#undef CLAMP +#endif + +static uint8_t vb_filter_v1_rb[256][256]; +static uint8_t vb_filter_v1_g [256][256]; + +static uint8_t vb_filter_bx_rb[256][256]; +static uint8_t vb_filter_bx_g [256][256]; + +enum +{ + TYPE_BANSHEE = 0, + TYPE_V3_2000, + TYPE_V3_3000 +}; + +typedef struct banshee_t +{ + svga_t svga; + + rom_t bios_rom; + + uint8_t pci_regs[256]; + + uint32_t memBaseAddr0; + uint32_t memBaseAddr1; + uint32_t ioBaseAddr; + + uint32_t agpInit0; + uint32_t dramInit0, dramInit1; + uint32_t lfbMemoryConfig; + uint32_t miscInit0, miscInit1; + uint32_t pciInit0; + uint32_t vgaInit0, vgaInit1; + + uint32_t command_2d; + uint32_t srcBaseAddr_2d; + + uint32_t pllCtrl0, pllCtrl1, pllCtrl2; + + uint32_t dacMode; + int dacAddr; + + uint32_t vidDesktopOverlayStride; + uint32_t vidDesktopStartAddr; + uint32_t vidProcCfg; + uint32_t vidScreenSize; + uint32_t vidSerialParallelPort; + + int overlay_pix_fmt; + + uint32_t hwCurPatAddr, hwCurLoc, hwCurC0, hwCurC1; + + uint32_t intrCtrl; + + uint32_t overlay_buffer[2][4096]; + + mem_mapping_t linear_mapping; + + mem_mapping_t reg_mapping_low; /*0000000-07fffff*/ + mem_mapping_t reg_mapping_high; /*0c00000-1ffffff - Windows 2000 puts the BIOS ROM in between these two areas*/ + + voodoo_t *voodoo; + + uint32_t desktop_addr; + int desktop_y; + uint32_t desktop_stride_tiled; + + int type; +} banshee_t; + +enum +{ + Init_status = 0x00, + Init_pciInit0 = 0x04, + Init_lfbMemoryConfig = 0x0c, + Init_miscInit0 = 0x10, + Init_miscInit1 = 0x14, + Init_dramInit0 = 0x18, + Init_dramInit1 = 0x1c, + Init_agpInit0 = 0x20, + Init_vgaInit0 = 0x28, + Init_vgaInit1 = 0x2c, + Init_2dCommand = 0x30, + Init_2dSrcBaseAddr = 0x34, + Init_strapInfo = 0x38, + + PLL_pllCtrl0 = 0x40, + PLL_pllCtrl1 = 0x44, + PLL_pllCtrl2 = 0x48, + + DAC_dacMode = 0x4c, + DAC_dacAddr = 0x50, + DAC_dacData = 0x54, + + Video_vidProcCfg = 0x5c, + Video_maxRgbDelta = 0x58, + Video_hwCurPatAddr = 0x60, + Video_hwCurLoc = 0x64, + Video_hwCurC0 = 0x68, + Video_hwCurC1 = 0x6c, + Video_vidSerialParallelPort = 0x78, + Video_vidScreenSize = 0x98, + Video_vidOverlayStartCoords = 0x9c, + Video_vidOverlayEndScreenCoords = 0xa0, + Video_vidOverlayDudx = 0xa4, + Video_vidOverlayDudxOffsetSrcWidth = 0xa8, + Video_vidOverlayDvdy = 0xac, + Video_vidOverlayDvdyOffset = 0xe0, + Video_vidDesktopStartAddr = 0xe4, + Video_vidDesktopOverlayStride = 0xe8 +}; + +enum +{ + cmdBaseAddr0 = 0x20, + cmdBaseSize0 = 0x24, + cmdBump0 = 0x28, + cmdRdPtrL0 = 0x2c, + cmdRdPtrH0 = 0x30, + cmdAMin0 = 0x34, + cmdAMax0 = 0x3c, + cmdFifoDepth0 = 0x44, + cmdHoleCnt0 = 0x48 +}; + +#define VGAINIT0_EXTENDED_SHIFT_OUT (1 << 12) + +#define VIDPROCCFG_VIDPROC_ENABLE (1 << 0) +#define VIDPROCCFG_CURSOR_MODE (1 << 1) +#define VIDPROCCFG_HALF_MODE (1 << 4) +#define VIDPROCCFG_OVERLAY_ENABLE (1 << 8) +#define VIDPROCCFG_OVERLAY_CLUT_BYPASS (1 << 11) +#define VIDPROCCFG_OVERLAY_CLUT_SEL (1 << 13) +#define VIDPROCCFG_H_SCALE_ENABLE (1 << 14) +#define VIDPROCCFG_V_SCALE_ENABLE (1 << 15) +#define VIDPROCCFG_FILTER_MODE_MASK (3 << 16) +#define VIDPROCCFG_FILTER_MODE_POINT (0 << 16) +#define VIDPROCCFG_FILTER_MODE_DITHER_2X2 (1 << 16) +#define VIDPROCCFG_FILTER_MODE_DITHER_4X4 (2 << 16) +#define VIDPROCCFG_FILTER_MODE_BILINEAR (3 << 16) +#define VIDPROCCFG_DESKTOP_PIX_FORMAT ((banshee->vidProcCfg >> 18) & 7) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT ((banshee->vidProcCfg >> 21) & 7) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT (21) +#define VIDPROCCFG_OVERLAY_PIX_FORMAT_MASK (7 << VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT) +#define VIDPROCCFG_DESKTOP_TILE (1 << 24) +#define VIDPROCCFG_OVERLAY_TILE (1 << 25) +#define VIDPROCCFG_2X_MODE (1 << 26) +#define VIDPROCCFG_HWCURSOR_ENA (1 << 27) + +#define OVERLAY_FMT_565 (1) +#define OVERLAY_FMT_YUYV422 (5) +#define OVERLAY_FMT_UYVY422 (6) +#define OVERLAY_FMT_565_DITHER (7) + +#define OVERLAY_START_X_MASK (0xfff) +#define OVERLAY_START_Y_SHIFT (12) +#define OVERLAY_START_Y_MASK (0xfff << OVERLAY_START_Y_SHIFT) + +#define OVERLAY_END_X_MASK (0xfff) +#define OVERLAY_END_Y_SHIFT (12) +#define OVERLAY_END_Y_MASK (0xfff << OVERLAY_END_Y_SHIFT) + +#define OVERLAY_SRC_WIDTH_SHIFT (19) +#define OVERLAY_SRC_WIDTH_MASK (0x1fff << OVERLAY_SRC_WIDTH_SHIFT) + +#define VID_STRIDE_OVERLAY_SHIFT (16) +#define VID_STRIDE_OVERLAY_MASK (0x7fff << VID_STRIDE_OVERLAY_SHIFT) + +#define VID_DUDX_MASK (0xffffff) +#define VID_DVDY_MASK (0xffffff) + +#define PIX_FORMAT_8 0 +#define PIX_FORMAT_RGB565 1 +#define PIX_FORMAT_RGB24 2 +#define PIX_FORMAT_RGB32 3 + +#define VIDSERIAL_DDC_DCK_W (1 << 19) +#define VIDSERIAL_DDC_DDA_W (1 << 20) +#define VIDSERIAL_DDC_DCK_R (1 << 21) +#define VIDSERIAL_DDC_DDA_R (1 << 22) +#define VIDSERIAL_I2C_SCK_W (1 << 24) +#define VIDSERIAL_I2C_SDA_W (1 << 25) +#define VIDSERIAL_I2C_SCK_R (1 << 26) +#define VIDSERIAL_I2C_SDA_R (1 << 27) + +#define MISCINIT0_Y_ORIGIN_SWAP_SHIFT (18) +#define MISCINIT0_Y_ORIGIN_SWAP_MASK (0xfff << MISCINIT0_Y_ORIGIN_SWAP_SHIFT) + +static uint32_t banshee_status(banshee_t *banshee); + +static void banshee_out(uint16_t addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + svga_t *svga = &banshee->svga; + uint8_t old; + +// /*if (addr != 0x3c9) */pclog("banshee_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 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]; + 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); +} + +static uint8_t banshee_in(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + svga_t *svga = &banshee->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("banshee_in : %04X ", addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x40) + 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; + } +// if (addr != 0x3da) pclog("%02X %04X:%04X %i\n", temp, CS,cpu_state.pc, ins); + return temp; +} + +static void banshee_updatemapping(banshee_t *banshee) +{ + svga_t *svga = &banshee->svga; + + if (!(banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { +// pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&banshee->linear_mapping); + mem_mapping_disable(&banshee->reg_mapping_low); + mem_mapping_disable(&banshee->reg_mapping_high); + 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 %08X ", banshee->memBaseAddr1); + mem_mapping_set_addr(&banshee->linear_mapping, banshee->memBaseAddr1, 32 << 20); + pclog("registers %08X\n", banshee->memBaseAddr0); + mem_mapping_set_addr(&banshee->reg_mapping_low, banshee->memBaseAddr0, 8 << 20); + mem_mapping_set_addr(&banshee->reg_mapping_high, banshee->memBaseAddr0 + 0xc00000, 20 << 20); +} + +static void banshee_render_16bpp_tiled(svga_t *svga) +{ + banshee_t *banshee = (banshee_t *)svga->p; + int x; + int offset = 32; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine])[offset]; + uint32_t addr; + int drawn = 0; + + if (banshee->vidProcCfg & VIDPROCCFG_HALF_MODE) + addr = banshee->desktop_addr + ((banshee->desktop_y >> 1) & 31) * 128 + ((banshee->desktop_y >> 6) * banshee->desktop_stride_tiled); + else + addr = banshee->desktop_addr + (banshee->desktop_y & 31) * 128 + ((banshee->desktop_y >> 5) * banshee->desktop_stride_tiled); + + for (x = 0; x <= svga->hdisp; x += 64) + { + if (svga->hwcursor_on || svga->overlay_on) + svga->changedvram[addr >> 12] = 2; + if (svga->changedvram[addr >> 12] || svga->fullchange) + { + uint16_t *vram_p = (uint16_t *)&svga->vram[addr & svga->vram_display_mask]; + int xx; + + for (xx = 0; xx < 64; xx++) + *p++ = video_16to32[*vram_p++]; + + drawn = 1; + } + else + p += 64; + addr += 128*32; + } + + if (drawn) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + } + + banshee->desktop_y++; +} + +static void banshee_recalctimings(svga_t *svga) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + +/*7 R/W Horizontal Retrace End bit 5. - + 6 R/W Horizontal Retrace Start bit 8 0x4 + 5 R/W Horizontal Blank End bit 6. - + 4 R/W Horizontal Blank Start bit 8. 0x3 + 3 R/W Reserved. - + 2 R/W Horizontal Display Enable End bit 8. 0x1 + 1 R/W Reserved. - + 0 R/W Horizontal Total bit 8. 0x0*/ + if (svga->crtc[0x1a] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x1a] & 0x04) svga->hdisp += 0x100; +/*6 R/W Vertical Retrace Start bit 10 0x10 + 5 R/W Reserved. - + 4 R/W Vertical Blank Start bit 10. 0x15 + 3 R/W Reserved. - + 2 R/W Vertical Display Enable End bit 10 0x12 + 1 R/W Reserved. - + 0 R/W Vertical Total bit 10. 0x6*/ + if (svga->crtc[0x1b] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x1b] & 0x04) svga->dispend += 0x400; + if (svga->crtc[0x1b] & 0x10) svga->vblankstart += 0x400; + if (svga->crtc[0x1b] & 0x40) svga->vsyncstart += 0x400; +// pclog("svga->hdisp=%i\n", svga->hdisp); + + if (banshee->vgaInit0 & VGAINIT0_EXTENDED_SHIFT_OUT) + { + switch (VIDPROCCFG_DESKTOP_PIX_FORMAT) + { + case PIX_FORMAT_8: + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + break; + case PIX_FORMAT_RGB565: + svga->render = (banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) ? banshee_render_16bpp_tiled : svga_render_16bpp_highres; + svga->bpp = 16; + break; + case PIX_FORMAT_RGB24: + svga->render = svga_render_24bpp_highres; + svga->bpp = 24; + break; + case PIX_FORMAT_RGB32: + svga->render = svga_render_32bpp_highres; + svga->bpp = 32; + break; + +#ifndef RELEASE_BUILD + default: + fatal("Unknown pixel format %08x\n", banshee->vgaInit0); +#endif + } + svga->rowcount = 0; + if (!(banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) && (banshee->vidProcCfg & VIDPROCCFG_HALF_MODE)) + svga->linedbl = 1; + else + svga->linedbl = 0; + if (banshee->vidProcCfg & VIDPROCCFG_DESKTOP_TILE) + svga->rowoffset = ((banshee->vidDesktopOverlayStride & 0x3fff) * 128) >> 3; + else + svga->rowoffset = (banshee->vidDesktopOverlayStride & 0x3fff) >> 3; + svga->ma_latch = banshee->vidDesktopStartAddr >> 2; + banshee->desktop_stride_tiled = (banshee->vidDesktopOverlayStride & 0x3fff) * 128 * 32; +// pclog("Extended shift out %i rowoffset=%i %02x\n", VIDPROCCFG_DESKTOP_PIX_FORMAT, svga->rowoffset, svga->crtc[1]); + + svga->char_width = 8; + svga->split = 99999; + + if (banshee->vidProcCfg & VIDPROCCFG_2X_MODE) + { + svga->hdisp *= 2; + svga->htotal *= 2; + } + + svga->overlay.ena = banshee->vidProcCfg & VIDPROCCFG_OVERLAY_ENABLE; + + svga->overlay.x = voodoo->overlay.start_x; + svga->overlay.y = voodoo->overlay.start_y; + svga->overlay.xsize = voodoo->overlay.size_x; + svga->overlay.ysize = voodoo->overlay.size_y; + svga->overlay.pitch = (banshee->vidDesktopOverlayStride & VID_STRIDE_OVERLAY_MASK) >> VID_STRIDE_OVERLAY_SHIFT; + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) + svga->overlay.pitch *= 128*32; + if (svga->overlay.xsize <= 0 || svga->overlay.ysize <= 0) + svga->overlay.ena = 0; + if (svga->overlay.ena) + { +/* pclog("Overlay enabled : start=%i,%i end=%i,%i size=%i,%i pitch=%x\n", + voodoo->overlay.start_x, voodoo->overlay.start_y, + voodoo->overlay.end_x, voodoo->overlay.end_y, + voodoo->overlay.size_x, voodoo->overlay.size_y, + svga->overlay.pitch);*/ + if (!voodoo->overlay.start_x && !voodoo->overlay.start_y && + svga->hdisp == voodoo->overlay.size_x && svga->dispend == voodoo->overlay.size_y) + { + /*Overlay is full screen, so don't bother rendering the desktop + behind it*/ + svga->render = svga_render_null; + svga->bpp = 0; + } + } + + svga->video_res_override = 1; + svga->video_res_x = svga->hdisp; + svga->video_res_y = svga->dispend; + svga->video_bpp = svga->bpp; + } + else + { +// pclog("Normal shift out\n"); + svga->bpp = 8; + svga->video_res_override = 0; + } + + svga->fb_only = (banshee->vidProcCfg & VIDPROCCFG_VIDPROC_ENABLE); + + if (((svga->miscout >> 2) & 3) == 3) + { + int k = banshee->pllCtrl0 & 3; + int m = (banshee->pllCtrl0 >> 2) & 0x3f; + int n = (banshee->pllCtrl0 >> 8) & 0xff; + double freq = (((double)n + 2) / (((double)m + 2) * (double)(1 << k))) * 14318184.0; + + svga->clock = (cpuclock * (float)(1ull << 32)) / freq; +// svga->clock = cpuclock / freq; + +// pclog("svga->clock = %g %g m=%i k=%i n=%i\n", freq, freq / 1000000.0, m, k, n); + } +} + +static void banshee_ext_out(uint16_t addr, uint8_t val, void *p) +{ +// banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + +// pclog("banshee_ext_out: addr=%04x val=%02x\n", addr, val); + + switch (addr & 0xff) + { + 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: + banshee_out((addr & 0xff)+0x300, val, p); + break; + + default: + pclog("bad banshee_ext_out: addr=%04x val=%02x\n", addr, val); + } +} +static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + +// pclog("banshee_ext_outl: addr=%04x val=%08x %04x(%08x):%08x\n", addr, val, CS,cs,cpu_state.pc); + + switch (addr & 0xff) + { + case Init_pciInit0: + banshee->pciInit0 = val; + voodoo->read_time = pci_nonburst_time + pci_burst_time * ((val & 0x100) ? 2 : 1); + voodoo->burst_time = pci_burst_time * ((val & 0x200) ? 1 : 0); + voodoo->write_time = pci_nonburst_time + voodoo->burst_time; + break; + + case Init_lfbMemoryConfig: + banshee->lfbMemoryConfig = val; +// pclog("lfbMemoryConfig=%08x\n", val); + voodoo->tile_base = (val & 0x1fff) << 12; + voodoo->tile_stride = 1024 << ((val >> 13) & 7); + voodoo->tile_stride_shift = 10 + ((val >> 13) & 7); + voodoo->tile_x = ((val >> 16) & 0x7f) * 128; + voodoo->tile_x_real = ((val >> 16) & 0x7f) * 128*32; + break; + + case Init_miscInit0: + banshee->miscInit0 = val; + voodoo->y_origin_swap = (val & MISCINIT0_Y_ORIGIN_SWAP_MASK) >> MISCINIT0_Y_ORIGIN_SWAP_SHIFT; + break; + case Init_miscInit1: + banshee->miscInit1 = val; + break; + case Init_dramInit0: + banshee->dramInit0 = val; + break; + case Init_dramInit1: + banshee->dramInit1 = val; + break; + case Init_agpInit0: + banshee->agpInit0 = val; + break; + + case Init_2dCommand: + banshee->command_2d = val; + break; + case Init_2dSrcBaseAddr: + banshee->srcBaseAddr_2d = val; + break; + case Init_vgaInit0: + banshee->vgaInit0 = val; + break; + case Init_vgaInit1: + banshee->vgaInit1 = val; + svga->write_bank = (val & 0x3ff) << 15; + svga->read_bank = ((val >> 10) & 0x3ff) << 15; + break; + + case PLL_pllCtrl0: + banshee->pllCtrl0 = val; + break; + case PLL_pllCtrl1: + banshee->pllCtrl1 = val; + break; + case PLL_pllCtrl2: + banshee->pllCtrl2 = val; + break; + + case DAC_dacMode: + banshee->dacMode = val; + break; + case DAC_dacAddr: + banshee->dacAddr = val & 0x1ff; + break; + case DAC_dacData: + svga->pallook[banshee->dacAddr] = val & 0xffffff; + svga->fullchange = changeframecount; + break; + + case Video_vidProcCfg: + banshee->vidProcCfg = val; +// pclog("vidProcCfg=%08x\n", val); + banshee->overlay_pix_fmt = (val & VIDPROCCFG_OVERLAY_PIX_FORMAT_MASK) >> VIDPROCCFG_OVERLAY_PIX_FORMAT_SHIFT; + svga->hwcursor.ena = val & VIDPROCCFG_HWCURSOR_ENA; + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + + case Video_maxRgbDelta: + banshee->voodoo->scrfilterThreshold = val; + if (val > 0x00) + banshee->voodoo->scrfilterEnabled = 1; + else + banshee->voodoo->scrfilterEnabled = 0; + voodoo_threshold_check(banshee->voodoo); + pclog("Banshee Filter: %06x\n", val); + + break; + + case Video_hwCurPatAddr: + banshee->hwCurPatAddr = val; + svga->hwcursor.addr = (val & 0xfffff0) + (svga->hwcursor.yoff * 16); + break; + case Video_hwCurLoc: + banshee->hwCurLoc = val; + svga->hwcursor.x = (val & 0x7ff) - 32; + svga->hwcursor.y = ((val >> 16) & 0x7ff) - 64; + if (svga->hwcursor.y < 0) + { + svga->hwcursor.yoff = -svga->hwcursor.y; + svga->hwcursor.y = 0; + } + else + svga->hwcursor.yoff = 0; + svga->hwcursor.addr = (banshee->hwCurPatAddr & 0xfffff0) + (svga->hwcursor.yoff * 16); + svga->hwcursor.xsize = 64; + svga->hwcursor.ysize = 64; +// pclog("hwCurLoc %08x %i\n", val, svga->hwcursor.y); + break; + case Video_hwCurC0: + banshee->hwCurC0 = val; + break; + case Video_hwCurC1: + banshee->hwCurC1 = val; + break; + + case Video_vidSerialParallelPort: + banshee->vidSerialParallelPort = val; +// pclog("vidSerialParallelPort: write %08x %08x %04x(%08x):%08x\n", val, val & (VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W), CS,cs,cpu_state.pc); + ddc_i2c_change((val & VIDSERIAL_DDC_DCK_W) ? 1 : 0, (val & VIDSERIAL_DDC_DDA_W) ? 1 : 0); + break; + + case Video_vidScreenSize: + banshee->vidScreenSize = val; + voodoo->h_disp = (val & 0xfff) + 1; + voodoo->v_disp = (val >> 12) & 0xfff; + break; + case Video_vidOverlayStartCoords: + voodoo->overlay.vidOverlayStartCoords = val; + voodoo->overlay.start_x = val & OVERLAY_START_X_MASK; + voodoo->overlay.start_y = (val & OVERLAY_START_Y_MASK) >> OVERLAY_START_Y_SHIFT; + voodoo->overlay.size_x = voodoo->overlay.end_x - voodoo->overlay.start_x; + voodoo->overlay.size_y = voodoo->overlay.end_y - voodoo->overlay.start_y; + svga_recalctimings(svga); + break; + case Video_vidOverlayEndScreenCoords: + voodoo->overlay.vidOverlayEndScreenCoords = val; + voodoo->overlay.end_x = val & OVERLAY_END_X_MASK; + voodoo->overlay.end_y = (val & OVERLAY_END_Y_MASK) >> OVERLAY_END_Y_SHIFT; + voodoo->overlay.size_x = (voodoo->overlay.end_x - voodoo->overlay.start_x) + 1; + voodoo->overlay.size_y = (voodoo->overlay.end_y - voodoo->overlay.start_y) + 1; + svga_recalctimings(svga); + break; + case Video_vidOverlayDudx: + voodoo->overlay.vidOverlayDudx = val & VID_DUDX_MASK; +// pclog("vidOverlayDudx=%08x\n", val); + break; + case Video_vidOverlayDudxOffsetSrcWidth: + voodoo->overlay.vidOverlayDudxOffsetSrcWidth = val; + voodoo->overlay.overlay_bytes = (val & OVERLAY_SRC_WIDTH_MASK) >> OVERLAY_SRC_WIDTH_SHIFT; +// pclog("vidOverlayDudxOffsetSrcWidth=%08x\n", val); + break; + case Video_vidOverlayDvdy: + voodoo->overlay.vidOverlayDvdy = val & VID_DVDY_MASK; +// pclog("vidOverlayDvdy=%08x\n", val); + break; + case Video_vidOverlayDvdyOffset: + voodoo->overlay.vidOverlayDvdyOffset = val; + break; + + + case Video_vidDesktopStartAddr: + banshee->vidDesktopStartAddr = val & 0xffffff; +// pclog("vidDesktopStartAddr=%08x\n", val); + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; + case Video_vidDesktopOverlayStride: + banshee->vidDesktopOverlayStride = val; +// pclog("vidDesktopOverlayStride=%08x\n", val); + svga->fullchange = changeframecount; + svga_recalctimings(svga); + break; +// default: +// fatal("bad banshee_ext_outl: addr=%04x val=%08x\n", addr, val); + } +} + +static uint8_t banshee_ext_in(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + uint8_t ret = 0xff; + + switch (addr & 0xff) + { + case Init_status: case Init_status+1: case Init_status+2: case Init_status+3: + ret = (banshee_status(banshee) >> ((addr & 3) * 8)) & 0xff; +// pclog("Read status reg! %04x(%08x):%08x\n", CS, cs, cpu_state.pc); + break; + + 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: + ret = banshee_in((addr & 0xff)+0x300, p); + break; + + default: + pclog("bad banshee_ext_in: addr=%04x\n", addr); + break; + } + +// pclog("banshee_ext_in: addr=%04x val=%02x\n", addr, ret); + + return ret; +} + +static uint32_t banshee_status(banshee_t *banshee) +{ + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + int fifo_entries = FIFO_ENTRIES; + int fifo_size = 0xffff - fifo_entries; + int swap_count = voodoo->swap_count; + int written = voodoo->cmd_written + voodoo->cmd_written_fifo; + int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) || + voodoo->render_voodoo_busy[0] || voodoo->render_voodoo_busy[1] || + voodoo->render_voodoo_busy[2] || voodoo->render_voodoo_busy[3] || + voodoo->voodoo_busy; + uint32_t ret; + + ret = 0; + if (fifo_size < 0x20) + ret |= fifo_size; + else + ret |= 0x1f; + if (fifo_size) + ret |= 0x20; + if (swap_count < 7) + ret |= (swap_count << 28); + else + ret |= (7 << 28); + if (!(svga->cgastat & 8)) + ret |= 0x40; + + if (busy) + ret |= 0x780; /*Busy*/ + + if (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) + ret |= (1 << 11); + + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_thread(voodoo); + +// pclog("banshee_status: busy %i %i (%i %i) %i %i %i %04x(%08x):%08x %08x\n", busy, written, voodoo->cmd_written, voodoo->cmd_written_fifo, voodoo->cmd_read, voodoo->cmdfifo_depth_rd, voodoo->cmdfifo_depth_wr, CS,cs,cpu_state.pc, ret); + + return ret; +} + +static uint32_t banshee_ext_inl(uint16_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + uint32_t ret = 0xffffffff; + + cycles -= voodoo->read_time; + + switch (addr & 0xff) + { + case Init_status: + ret = banshee_status(banshee); +// pclog("Read status reg! %04x(%08x):%08x\n", CS, cs, cpu_state.pc); + break; + case Init_pciInit0: + ret = banshee->pciInit0; + break; + case Init_lfbMemoryConfig: + ret = banshee->lfbMemoryConfig; + break; + + case Init_miscInit0: + ret = banshee->miscInit0; + break; + case Init_miscInit1: + ret = banshee->miscInit1; + break; + case Init_dramInit0: + ret = banshee->dramInit0; + break; + case Init_dramInit1: + ret = banshee->dramInit1; + break; + case Init_agpInit0: + ret = banshee->agpInit0; + break; + + case Init_vgaInit0: + ret = banshee->vgaInit0; + break; + case Init_vgaInit1: + ret = banshee->vgaInit1; + break; + + case Init_2dCommand: + ret = banshee->command_2d; + break; + case Init_2dSrcBaseAddr: + ret = banshee->srcBaseAddr_2d; + break; + case Init_strapInfo: + ret = 0x00000040; /*8 MB SGRAM, PCI, IRQ enabled, 32kB BIOS*/ + break; + + case PLL_pllCtrl0: + ret = banshee->pllCtrl0; + break; + case PLL_pllCtrl1: + ret = banshee->pllCtrl1; + break; + case PLL_pllCtrl2: + ret = banshee->pllCtrl2; + break; + + case DAC_dacMode: + ret = banshee->dacMode; + break; + case DAC_dacAddr: + ret = banshee->dacAddr; + break; + case DAC_dacData: + ret = svga->pallook[banshee->dacAddr]; + break; + + case Video_vidProcCfg: + ret = banshee->vidProcCfg; + break; + + case Video_hwCurPatAddr: + ret = banshee->hwCurPatAddr; + break; + case Video_hwCurLoc: + ret = banshee->hwCurLoc; + break; + case Video_hwCurC0: + ret = banshee->hwCurC0; + break; + case Video_hwCurC1: + ret = banshee->hwCurC1; + break; + + case Video_vidSerialParallelPort: + ret = banshee->vidSerialParallelPort & ~(VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R); + if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DCK_W) && ddc_read_clock()) + ret |= VIDSERIAL_DDC_DCK_R; + if ((banshee->vidSerialParallelPort & VIDSERIAL_DDC_DDA_W) && ddc_read_data()) + ret |= VIDSERIAL_DDC_DDA_R; + ret = ret & ~(VIDSERIAL_I2C_SCK_R | VIDSERIAL_I2C_SDA_R); + if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SCK_W) + ret |= VIDSERIAL_I2C_SCK_R; + if (banshee->vidSerialParallelPort & VIDSERIAL_I2C_SDA_W) + ret |= VIDSERIAL_I2C_SDA_R; +// pclog("vidSerialParallelPort: read %08x %08x %04x(%08x):%08x\n", ret, ret & (VIDSERIAL_DDC_DCK_R | VIDSERIAL_DDC_DDA_R), CS,cs,cpu_state.pc); + break; + + case Video_vidScreenSize: + ret = banshee->vidScreenSize; + break; + case Video_vidOverlayStartCoords: + ret = voodoo->overlay.vidOverlayStartCoords; + break; + case Video_vidOverlayEndScreenCoords: + ret = voodoo->overlay.vidOverlayEndScreenCoords; + break; + case Video_vidOverlayDudx: + ret = voodoo->overlay.vidOverlayDudx; + break; + case Video_vidOverlayDudxOffsetSrcWidth: + ret = voodoo->overlay.vidOverlayDudxOffsetSrcWidth; + break; + case Video_vidOverlayDvdy: + ret = voodoo->overlay.vidOverlayDvdy; + break; + case Video_vidOverlayDvdyOffset: + ret = voodoo->overlay.vidOverlayDvdyOffset; + break; + + case Video_vidDesktopStartAddr: + ret = banshee->vidDesktopStartAddr; + break; + case Video_vidDesktopOverlayStride: + ret = banshee->vidDesktopOverlayStride; + break; + + default: +// fatal("bad banshee_ext_inl: addr=%04x\n", addr); + break; + } + +// /*if (addr) */pclog("banshee_ext_inl: addr=%04x val=%08x\n", addr, ret); + + return ret; +} + + +static uint32_t banshee_reg_readl(uint32_t addr, void *p); + +static uint8_t banshee_reg_read(uint32_t addr, void *p) +{ +// pclog("banshee_reg_read: addr=%08x\n", addr); + return banshee_reg_readl(addr & ~3, p) >> (8*(addr & 3)); +} + +static uint16_t banshee_reg_readw(uint32_t addr, void *p) +{ +// pclog("banshee_reg_readw: addr=%08x\n", addr); + return banshee_reg_readl(addr & ~3, p) >> (8*(addr & 2)); +} + +static uint32_t banshee_cmd_read(banshee_t *banshee, uint32_t addr) +{ + voodoo_t *voodoo = banshee->voodoo; + uint32_t ret = 0xffffffff; + + switch (addr & 0x1fc) + { + case cmdBaseAddr0: + ret = voodoo->cmdfifo_base >> 12; +// pclog("Read cmdfifo_base %08x\n", ret); + break; + + case cmdRdPtrL0: + ret = voodoo->cmdfifo_rp; +// pclog("Read cmdfifo_rp %08x\n", ret); + break; + + case cmdFifoDepth0: + ret = voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd; +// pclog("Read cmdfifo_depth %08x\n", ret); + break; + + case 0x108: + break; + +#ifndef RELEASE_BUILD + default: + fatal("Unknown banshee_cmd_read %08x\n", addr); +#endif + } + + return ret; +} + +static uint32_t banshee_reg_readl(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + uint32_t ret = 0xffffffff; + + cycles -= voodoo->read_time; + + switch (addr & 0x1f00000) + { + case 0x0000000: /*IO remap*/ + if (!(addr & 0x80000)) + ret = banshee_ext_inl(addr & 0xff, banshee); + else + ret = banshee_cmd_read(banshee, addr); + break; + + case 0x0100000: /*2D registers*/ + voodoo_flush(voodoo); + switch (addr & 0x1fc) + { + case 0x08: + ret = voodoo->banshee_blt.clip0Min; + break; + case 0x0c: + ret = voodoo->banshee_blt.clip0Max; + break; + case 0x10: + ret = voodoo->banshee_blt.dstBaseAddr; + break; + case 0x14: + ret = voodoo->banshee_blt.dstFormat; + break; + case 0x34: + ret = voodoo->banshee_blt.srcBaseAddr; + break; + case 0x38: + ret = voodoo->banshee_blt.commandExtra; + break; + case 0x5c: + ret = voodoo->banshee_blt.srcXY; + break; + case 0x60: + ret = voodoo->banshee_blt.colorBack; + break; + case 0x64: + ret = voodoo->banshee_blt.colorFore; + break; + case 0x68: + ret = voodoo->banshee_blt.dstSize; + break; + case 0x6c: + ret = voodoo->banshee_blt.dstXY; + break; + case 0x70: + ret = voodoo->banshee_blt.command; + break; + default: + pclog("banshee_reg_readl: addr=%08x\n", addr); + } + break; + + case 0x0200000: case 0x0300000: case 0x0400000: case 0x0500000: /*3D registers*/ + switch (addr & 0x3fc) + { + case SST_status: + ret = banshee_status(banshee); + break; + + case SST_intrCtrl: + ret = banshee->intrCtrl & 0x0030003f; + break; + + case SST_fbzColorPath: + voodoo_flush(voodoo); + ret = voodoo->params.fbzColorPath; + break; + case SST_fogMode: + voodoo_flush(voodoo); + ret = voodoo->params.fogMode; + break; + case SST_alphaMode: + voodoo_flush(voodoo); + ret = voodoo->params.alphaMode; + break; + case SST_fbzMode: + voodoo_flush(voodoo); + ret = voodoo->params.fbzMode; + break; + case SST_lfbMode: + voodoo_flush(voodoo); + ret = voodoo->lfbMode; + break; + case SST_clipLeftRight: + ret = voodoo->params.clipRight | (voodoo->params.clipLeft << 16); + break; + case SST_clipLowYHighY: + ret = voodoo->params.clipHighY | (voodoo->params.clipLowY << 16); + break; + + case SST_clipLeftRight1: + ret = voodoo->params.clipRight1 | (voodoo->params.clipLeft1 << 16); + break; + case SST_clipTopBottom1: + ret = voodoo->params.clipHighY1 | (voodoo->params.clipLowY1 << 16); + break; + + case SST_stipple: + voodoo_flush(voodoo); + ret = voodoo->params.stipple; + break; + case SST_color0: + voodoo_flush(voodoo); + ret = voodoo->params.color0; + break; + case SST_color1: + voodoo_flush(voodoo); + ret = voodoo->params.color1; + break; + + case SST_fbiPixelsIn: + ret = voodoo->fbiPixelsIn & 0xffffff; + break; + case SST_fbiChromaFail: + ret = voodoo->fbiChromaFail & 0xffffff; + break; + case SST_fbiZFuncFail: + ret = voodoo->fbiZFuncFail & 0xffffff; + break; + case SST_fbiAFuncFail: + ret = voodoo->fbiAFuncFail & 0xffffff; + break; + case SST_fbiPixelsOut: + ret = voodoo->fbiPixelsOut & 0xffffff; + break; + + default: + pclog("banshee_reg_readl: 3D addr=%08x\n", addr); + break; + } + break; + } + +// /*if (addr != 0xe0000000) */pclog("banshee_reg_readl: addr=%08x ret=%08x %04x(%08x):%08x\n", addr, ret, CS,cs,cpu_state.pc); +// if (cpu_state.pc == 0x1000e437) +// output = 3; + return ret; +} + +static void banshee_reg_write(uint32_t addr, uint8_t val, void *p) +{ +// pclog("banshee_reg_writeb: addr=%08x val=%02x\n", addr, val); +} + +static void banshee_reg_writew(uint32_t addr, uint16_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + + cycles -= voodoo->write_time; + +// pclog("banshee_reg_writew: addr=%08x val=%04x\n", addr, val); + switch (addr & 0x1f00000) + { + case 0x1000000: case 0x1100000: case 0x1200000: case 0x1300000: /*3D LFB*/ + case 0x1400000: case 0x1500000: case 0x1600000: case 0x1700000: + case 0x1800000: case 0x1900000: case 0x1a00000: case 0x1b00000: + case 0x1c00000: case 0x1d00000: case 0x1e00000: case 0x1f00000: + voodoo_queue_command(voodoo, (addr & 0xffffff) | FIFO_WRITEW_FB, val); + break; + } +} + +static void banshee_cmd_write(banshee_t *banshee, uint32_t addr, uint32_t val) +{ + voodoo_t *voodoo = banshee->voodoo; +// pclog("banshee_cmd_write: addr=%03x val=%08x\n", addr & 0x1fc, val); + switch (addr & 0x1fc) + { + case cmdBaseAddr0: + voodoo->cmdfifo_base = (val & 0xfff) << 12; + voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12); +// pclog("cmdfifo_base=%08x cmdfifo_end=%08x %08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end, val); + break; + + case cmdBaseSize0: + voodoo->cmdfifo_size = val; + voodoo->cmdfifo_end = voodoo->cmdfifo_base + (((voodoo->cmdfifo_size & 0xff) + 1) << 12); + voodoo->cmdfifo_enabled = val & 0x100; + if (!voodoo->cmdfifo_enabled) + voodoo->cmdfifo_in_sub = 0; /*Not sure exactly when this should be reset*/ +// pclog("cmdfifo_base=%08x cmdfifo_end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); + break; + +// voodoo->cmdfifo_end = ((val >> 16) & 0x3ff) << 12; +// pclog("CMDFIFO base=%08x end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); +// break; + + case cmdRdPtrL0: + voodoo->cmdfifo_rp = val; + break; + case cmdAMin0: + voodoo->cmdfifo_amin = val; + break; + case cmdAMax0: + voodoo->cmdfifo_amax = val; + break; + case cmdFifoDepth0: + voodoo->cmdfifo_depth_rd = 0; + voodoo->cmdfifo_depth_wr = val & 0xffff; + break; + + default: + pclog("Unknown banshee_cmd_write: addr=%08x val=%08x\n", addr, val); + break; + } + +/* cmdBaseSize0 = 0x24, + cmdBump0 = 0x28, + cmdRdPtrL0 = 0x2c, + cmdRdPtrH0 = 0x30, + cmdAMin0 = 0x34, + cmdAMax0 = 0x3c, + cmdFifoDepth0 = 0x44, + cmdHoleCnt0 = 0x48 + }*/ +} + +static void banshee_reg_writel(uint32_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + + if (addr == voodoo->last_write_addr+4) + cycles -= voodoo->burst_time; + else + cycles -= voodoo->write_time; + voodoo->last_write_addr = addr; + +// pclog("banshee_reg_writel: addr=%08x val=%08x\n", addr, val); + + switch (addr & 0x1f00000) + { + case 0x0000000: /*IO remap*/ + if (!(addr & 0x80000)) + banshee_ext_outl(addr & 0xff, val, banshee); + else + banshee_cmd_write(banshee, addr, val); +// pclog("CMD!!! write %08x %08x\n", addr, val); + break; + + case 0x0100000: /*2D registers*/ + voodoo_queue_command(voodoo, (addr & 0x1fc) | FIFO_WRITEL_2DREG, val); + break; + + case 0x0200000: case 0x0300000: case 0x0400000: case 0x0500000: /*3D registers*/ + switch (addr & 0x3fc) + { + case SST_intrCtrl: + banshee->intrCtrl = val & 0x0030003f; +// pclog("intrCtrl=%08x\n", val); + break; + + case SST_userIntrCMD: +#ifndef RELEASE_BUILD + fatal("userIntrCMD write %08x\n", val); +#endif + break; + + case SST_swapbufferCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); +// pclog("SST_swapbufferCMD write: %i %i\n", voodoo->cmd_written, voodoo->cmd_written_fifo); + break; + case SST_triangleCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_ftriangleCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_fastfillCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_nopCMD: + voodoo->cmd_written++; + voodoo_queue_command(voodoo, (addr & 0x3fc) | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + voodoo_wake_fifo_threads(voodoo->set, voodoo); + break; + + case SST_swapPending: + thread_lock_mutex(voodoo->swap_mutex); + voodoo->swap_count++; + thread_unlock_mutex(voodoo->swap_mutex); +// voodoo->cmd_written++; + break; + + default: + voodoo_queue_command(voodoo, (addr & 0x3ffffc) | FIFO_WRITEL_REG, val); + break; + } + break; + + case 0x0600000: case 0x0700000: /*Texture download*/ + voodoo->tex_count++; + voodoo_queue_command(voodoo, (addr & 0x1ffffc) | FIFO_WRITEL_TEX, val); + break; + + case 0x1000000: case 0x1100000: case 0x1200000: case 0x1300000: /*3D LFB*/ + case 0x1400000: case 0x1500000: case 0x1600000: case 0x1700000: + case 0x1800000: case 0x1900000: case 0x1a00000: case 0x1b00000: + case 0x1c00000: case 0x1d00000: case 0x1e00000: case 0x1f00000: + voodoo_queue_command(voodoo, (addr & 0xfffffc) | FIFO_WRITEL_FB, val); + break; + } +} + +static uint8_t banshee_read_linear(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->read_time; + cycles_lost += voodoo->read_time; + + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + egareads++; + cycles -= video_timing_read_b; + cycles_lost += video_timing_read_b; + +// pclog("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return svga->vram[addr & svga->vram_mask]; +} + +static uint16_t banshee_read_linear_w(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + if (addr & 1) + return banshee_read_linear(addr, p) | (banshee_read_linear(addr+1, p) << 8); + + cycles -= voodoo->read_time; + cycles_lost += voodoo->read_time; + + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + egareads++; + cycles -= video_timing_read_w; + cycles_lost += video_timing_read_w; + +// pclog("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; +} + +static uint32_t banshee_read_linear_l(uint32_t addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + if (addr & 3) + return banshee_read_linear_w(addr, p) | (banshee_read_linear_w(addr+2, p) << 16); + + cycles -= voodoo->read_time; + cycles_lost += voodoo->read_time; + + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// pclog(" Tile rb %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return 0xff; + + egareads++; + cycles -= video_timing_read_l; + cycles_lost += video_timing_read_l; + +// pclog("read_linear: addr=%08x val=%02x\n", addr, svga->vram[addr & svga->vram_mask]); + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + +static void banshee_write_linear(uint32_t addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + cycles -= voodoo->write_time; + cycles_lost += voodoo->write_time; + +// pclog("write_linear: addr=%08x val=%02x\n", addr, val); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// pclog(" Tile b %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return; + + egawrites++; + + cycles -= video_timing_write_b; + cycles_lost += video_timing_write_b; + + svga->changedvram[addr >> 12] = changeframecount; + svga->vram[addr & svga->vram_mask] = val; +} + +static void banshee_write_linear_w(uint32_t addr, uint16_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + + if (addr & 1) + { + banshee_write_linear(addr, val, p); + banshee_write_linear(addr + 1, val >> 8, p); + return; + } + + cycles -= voodoo->write_time; + cycles_lost += voodoo->write_time; + +// pclog("write_linear: addr=%08x val=%02x\n", addr, val); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// pclog(" Tile b %08x->%08x %i %i\n", old_addr, addr, x, y); + } + if (addr >= svga->vram_max) + return; + + egawrites++; + + cycles -= video_timing_write_w; + cycles_lost += video_timing_write_w; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr & svga->vram_mask] = val; +} + +static void banshee_write_linear_l(uint32_t addr, uint32_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + svga_t *svga = &banshee->svga; + int timing; + + if (addr & 3) + { + banshee_write_linear_w(addr, val, p); + banshee_write_linear_w(addr + 2, val >> 16, p); + return; + } + + if (addr == voodoo->last_write_addr+4) + timing = voodoo->burst_time; + else + timing = voodoo->write_time; + cycles -= timing; + cycles_lost += timing; + voodoo->last_write_addr = addr; + +// /*if (val) */pclog("write_linear_l: addr=%08x val=%08x %08x\n", addr, val, voodoo->tile_base); + addr &= svga->decode_mask; + if (addr >= voodoo->tile_base) + { + int x, y; + + addr -= voodoo->tile_base; + x = addr & (voodoo->tile_stride-1); + y = addr >> voodoo->tile_stride_shift; + + addr = voodoo->tile_base + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*voodoo->tile_x_real; +// pclog(" Tile %08x->%08x->%08x->%08x %i %i tile_x=%i\n", old_addr, addr_off, addr2, addr, x, y, voodoo->tile_x_real); + } + + if (addr >= svga->vram_max) + return; + + egawrites += 4; + + cycles -= video_timing_write_l; + cycles_lost += video_timing_write_l; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr & svga->vram_mask] = val; + if (voodoo->cmdfifo_enabled && addr >= voodoo->cmdfifo_base && addr < voodoo->cmdfifo_end) + { +// pclog("CMDFIFO write %08x %08x old amin=%08x amax=%08x hlcnt=%i depth_wr=%i rp=%08x\n", addr, val, voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount, voodoo->cmdfifo_depth_wr, voodoo->cmdfifo_rp); + if (addr == voodoo->cmdfifo_base && !voodoo->cmdfifo_holecount) + { +// if (voodoo->cmdfifo_holecount) +// fatal("CMDFIFO reset pointers while outstanding holes\n"); + /*Reset pointers*/ + voodoo->cmdfifo_amin = voodoo->cmdfifo_base; + voodoo->cmdfifo_amax = voodoo->cmdfifo_base; + voodoo->cmdfifo_depth_wr++; + voodoo_wake_fifo_thread(voodoo); + } + else if (voodoo->cmdfifo_holecount) + { +// if ((addr <= voodoo->cmdfifo_amin && voodoo->cmdfifo_amin != -4) || addr >= voodoo->cmdfifo_amax) +// fatal("CMDFIFO holecount write outside of amin/amax - amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); +// pclog("holecount %i\n", voodoo->cmdfifo_holecount); + voodoo->cmdfifo_holecount--; + if (!voodoo->cmdfifo_holecount) + { + /*Filled in holes, resume normal operation*/ + voodoo->cmdfifo_depth_wr += ((voodoo->cmdfifo_amax - voodoo->cmdfifo_amin) >> 2); + voodoo->cmdfifo_amin = voodoo->cmdfifo_amax; + voodoo_wake_fifo_thread(voodoo); +// pclog("hole filled! amin=%08x amax=%08x added %i words\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, words_to_add); + } + } + else if (addr == voodoo->cmdfifo_amax+4) + { + /*In-order write*/ + voodoo->cmdfifo_amin = addr; + voodoo->cmdfifo_amax = addr; + voodoo->cmdfifo_depth_wr++; + voodoo_wake_fifo_thread(voodoo); + } + else + { + /*Out-of-order write*/ + if (addr < voodoo->cmdfifo_amin) + { + /*Reset back to start. Note that write is still out of order!*/ + voodoo->cmdfifo_amin = voodoo->cmdfifo_base-4; + + } +// else if (addr < voodoo->cmdfifo_amax) +// fatal("Out-of-order write really out of order\n"); + voodoo->cmdfifo_amax = addr; + voodoo->cmdfifo_holecount = ((voodoo->cmdfifo_amax - voodoo->cmdfifo_amin) >> 2) - 1; +// pclog("CMDFIFO out of order: amin=%08x amax=%08x holecount=%i\n", voodoo->cmdfifo_amin, voodoo->cmdfifo_amax, voodoo->cmdfifo_holecount); + } + } +} + +void banshee_hwcursor_draw(svga_t *svga, int displine) +{ + banshee_t *banshee = (banshee_t *)svga->p; + int x, c; + int x_off; + uint32_t col0 = banshee->hwCurC0; + uint32_t col1 = banshee->hwCurC1; + uint8_t plane0[8], plane1[8]; + + for (c = 0; c < 8; c++) + plane0[c] = svga->vram[svga->hwcursor_latch.addr + c]; + for (c = 0; c < 8; c++) + plane1[c] = svga->vram[svga->hwcursor_latch.addr + c + 8]; + svga->hwcursor_latch.addr += 16; + + x_off = svga->hwcursor_latch.x; + + if (banshee->vidProcCfg & VIDPROCCFG_CURSOR_MODE) + { + /*X11 mode*/ + for (x = 0; x < 64; x += 8) + { + if (x_off > (32-8)) + { + int xx; + + for (xx = 0; xx < 8; xx++) + { + if (plane0[x >> 3] & (1 << 7)) + ((uint32_t *)buffer32->line[displine])[x_off + xx] = (plane1[x >> 3] & (1 << 7)) ? col1 : col0; + + plane0[x >> 3] <<= 1; + plane1[x >> 3] <<= 1; + } + } + + x_off += 8; + } + } + else + { + /*Windows mode*/ + for (x = 0; x < 64; x += 8) + { + if (x_off > (32-8)) + { + int xx; + + for (xx = 0; xx < 8; xx++) + { + if (!(plane0[x >> 3] & (1 << 7))) + ((uint32_t *)buffer32->line[displine])[x_off + xx] = (plane1[x >> 3] & (1 << 7)) ? col1 : col0; + else if (plane1[x >> 3] & (1 << 7)) + ((uint32_t *)buffer32->line[displine])[x_off + xx] ^= 0xffffff; + + plane0[x >> 3] <<= 1; + plane1[x >> 3] <<= 1; + } + } + + x_off += 8; + } + } +} + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_RGB565(buf) \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 2) \ + { \ + uint16_t data = *(uint16_t *)src; \ + int r = data & 0x1f; \ + int g = (data >> 5) & 0x3f; \ + int b = data >> 11; \ + \ + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \ + buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ + else \ + buf[wp++] = (clut[r << 3] & 0x0000ff) | \ + (clut[g << 2] & 0x00ff00) | \ + (clut[b << 3] & 0xff0000); \ + src += 2; \ + } \ + } while (0) + +#define DECODE_RGB565_TILED(buf) \ + do \ + { \ + int c; \ + int wp = 0; \ + uint32_t base_addr = (buf == banshee->overlay_buffer[1]) ? src_addr2 : src_addr; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 2) \ + { \ + uint16_t data = *(uint16_t *)&svga->vram[(base_addr + (c & 127) + (c >> 7)*128*32) & svga->vram_mask]; \ + int r = data & 0x1f; \ + int g = (data >> 5) & 0x3f; \ + int b = data >> 11; \ + \ + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_BYPASS) \ + buf[wp++] = (r << 3) | (g << 10) | (b << 19); \ + else \ + buf[wp++] = (clut[r << 3] & 0x0000ff) | \ + (clut[g << 2] & 0x00ff00) | \ + (clut[b << 3] & 0xff0000); \ + } \ + } while (0) + +#define DECODE_YUYV422(buf) \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 4) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + 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 = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + buf[wp++] = r | (g << 8) | (b << 16); \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + buf[wp++] = r | (g << 8) | (b << 16); \ + } \ + } while (0) + +#define DECODE_UYUV422(buf) \ + do \ + { \ + int c; \ + int wp = 0; \ + \ + for (c = 0; c < voodoo->overlay.overlay_bytes; c += 4) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + Cr = src[0] - 0x80; \ + y1 = src[1]; \ + Cb = src[2] - 0x80; \ + y2 = src[3]; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + buf[wp++] = r | (g << 8) | (b << 16); \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + buf[wp++] = r | (g << 8) | (b << 16); \ + } \ + } while (0) + + +#define OVERLAY_SAMPLE(buf) \ + do \ + { \ + switch (banshee->overlay_pix_fmt) \ + { \ + case 0: \ + break; \ + \ + case OVERLAY_FMT_YUYV422: \ + DECODE_YUYV422(buf); \ + break; \ + \ + case OVERLAY_FMT_UYVY422: \ + DECODE_UYUV422(buf); \ + break; \ + \ + case OVERLAY_FMT_565: \ + case OVERLAY_FMT_565_DITHER: \ + if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) \ + DECODE_RGB565_TILED(buf); \ + else \ + DECODE_RGB565(buf); \ + break; \ + } \ + } while (0) + +/* generate both filters for the static table here */ +void voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg) +{ + int g, h; + float difference, diffg; + float thiscol, thiscolg; + float clr, clg = 0; + float hack = 1.0f; + // pre-clamping + + fcr *= hack; + fcg *= hack; + + + /* box prefilter */ + for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into + { + for (h=0;h<256;h++) // pixel 2 - our main pixel + { + float avg; + float avgdiff; + + difference = (float)(g - h); + avg = g; + avgdiff = avg - h; + + avgdiff = avgdiff * 0.75f; + if (avgdiff < 0) avgdiff *= -1; + if (difference < 0) difference *= -1; + + thiscol = thiscolg = g; + + if (h > g) + { + clr = clg = avgdiff; + + if (clr>fcr) clr=fcr; + if (clg>fcg) clg=fcg; + + thiscol = g; + thiscolg = g; + + if (thiscol>g+fcr) + thiscol=g+fcr; + if (thiscolg>g+fcg) + thiscolg=g+fcg; + + if (thiscol>g+difference) + thiscol=g+difference; + if (thiscolg>g+difference) + thiscolg=g+difference; + + // hmm this might not be working out.. + int ugh = g - h; + if (ugh < fcr) + thiscol = h; + if (ugh < fcg) + thiscolg = h; + } + + if (difference > fcr) + thiscol = g; + if (difference > fcg) + thiscolg = g; + + // clamp + if (thiscol < 0) thiscol = 0; + if (thiscolg < 0) thiscolg = 0; + + if (thiscol > 255) thiscol = 255; + if (thiscolg > 255) thiscolg = 255; + + vb_filter_bx_rb[g][h] = (thiscol); + vb_filter_bx_g [g][h] = (thiscolg); + + } + float lined = g + 4; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][2] = lined; + + lined = g + 0; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][1] = lined; + } + + /* 4x1 and 2x2 filter */ + //fcr *= 5; + //fcg *= 6; + + for (g=0;g<256;g++) // pixel 1 + { + for (h=0;h<256;h++) // pixel 2 + { + difference = (float)(h - g); + diffg = difference; + + thiscol = thiscolg = g; + + if (difference > fcr) + difference = fcr; + if (difference < -fcr) + difference = -fcr; + + if (diffg > fcg) + diffg = fcg; + if (diffg < -fcg) + diffg = -fcg; + + if ((difference < fcr) || (-difference > -fcr)) + thiscol = g + (difference / 2); + if ((diffg < fcg) || (-diffg > -fcg)) + thiscolg = g + (diffg / 2); + + if (thiscol < 0) + thiscol = 0; + if (thiscol > 255) + thiscol = 255; + + if (thiscolg < 0) + thiscolg = 0; + if (thiscolg > 255) + thiscolg = 255; + + vb_filter_v1_rb[g][h] = thiscol; + vb_filter_v1_g [g][h] = thiscolg; + + } + } + +} + + +static void banshee_overlay_draw(svga_t *svga, int displine) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + uint32_t *p; + int x; + int y = voodoo->overlay.src_y >> 20; + uint32_t src_addr = svga->overlay_latch.addr + ((banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) ? + ((y & 31) * 128 + (y >> 5) * svga->overlay_latch.pitch) : + y * svga->overlay_latch.pitch); + uint32_t src_addr2 = svga->overlay_latch.addr + ((banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) ? + (((y + 1) & 31) * 128 + ((y + 1) >> 5) * svga->overlay_latch.pitch) : + (y + 1) * svga->overlay_latch.pitch); + uint8_t *src = &svga->vram[src_addr & svga->vram_mask]; + uint32_t src_x = 0; + unsigned int y_coeff = (voodoo->overlay.src_y & 0xfffff) >> 4; + int skip_filtering; + uint32_t *clut = &svga->pallook[(banshee->vidProcCfg & VIDPROCCFG_OVERLAY_CLUT_SEL) ? 256 : 0]; + + if (svga->render == svga_render_null && + !svga->changedvram[src_addr >> 12] && !svga->changedvram[src_addr2 >> 12] && + !svga->fullchange && + ((voodoo->overlay.src_y >> 20) < 2048 && !voodoo->dirty_line[voodoo->overlay.src_y >> 20]) && + !(banshee->vidProcCfg & VIDPROCCFG_V_SCALE_ENABLE)) + { + voodoo->overlay.src_y += (1 << 20); + return; + } + + if ((voodoo->overlay.src_y >> 20) < 2048) + voodoo->dirty_line[voodoo->overlay.src_y >> 20] = 0; +// pclog("displine=%i addr=%08x %08x %08x %08x\n", displine, svga->overlay_latch.addr, src_addr, voodoo->overlay.vidOverlayDvdy, *(uint32_t *)src); +// if (src_addr >= 0x800000) +// fatal("overlay out of range!\n"); + p = &((uint32_t *)buffer32->line[displine])[svga->overlay_latch.x + 32]; + + if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) + skip_filtering = ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) != VIDPROCCFG_FILTER_MODE_BILINEAR && + !(banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) && !(banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_DITHER_4X4) && + !(banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_DITHER_2X2)); + else + skip_filtering = ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) != VIDPROCCFG_FILTER_MODE_BILINEAR && + !(banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)); + + if (skip_filtering) + { + /*No scaling or filtering required, just write straight to output buffer*/ + OVERLAY_SAMPLE(p); + } + else + { + OVERLAY_SAMPLE(banshee->overlay_buffer[0]); + + switch (banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) + { + case VIDPROCCFG_FILTER_MODE_BILINEAR: + src = &svga->vram[src_addr2 & svga->vram_mask]; + OVERLAY_SAMPLE(banshee->overlay_buffer[1]); + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + { + unsigned int x_coeff = (src_x & 0xfffff) >> 4; + unsigned int coeffs[4] = { + ((0x10000 - x_coeff) * (0x10000 - y_coeff)) >> 16, + ( x_coeff * (0x10000 - y_coeff)) >> 16, + ((0x10000 - x_coeff) * y_coeff) >> 16, + ( x_coeff * y_coeff) >> 16 + }; + uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20]; + uint32_t samp1 = banshee->overlay_buffer[0][(src_x >> 20) + 1]; + uint32_t samp2 = banshee->overlay_buffer[1][src_x >> 20]; + uint32_t samp3 = banshee->overlay_buffer[1][(src_x >> 20) + 1]; + int r = (((samp0 >> 16) & 0xff) * coeffs[0] + + ((samp1 >> 16) & 0xff) * coeffs[1] + + ((samp2 >> 16) & 0xff) * coeffs[2] + + ((samp3 >> 16) & 0xff) * coeffs[3]) >> 16; + int g = (((samp0 >> 8) & 0xff) * coeffs[0] + + ((samp1 >> 8) & 0xff) * coeffs[1] + + ((samp2 >> 8) & 0xff) * coeffs[2] + + ((samp3 >> 8) & 0xff) * coeffs[3]) >> 16; + int b = ((samp0 & 0xff) * coeffs[0] + + (samp1 & 0xff) * coeffs[1] + + (samp2 & 0xff) * coeffs[2] + + (samp3 & 0xff) * coeffs[3]) >> 16; + p[x] = (r << 16) | (g << 8) | b; + + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + { + uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20]; + uint32_t samp1 = banshee->overlay_buffer[1][src_x >> 20]; + int r = (((samp0 >> 16) & 0xff) * (0x10000 - y_coeff) + + ((samp1 >> 16) & 0xff) * y_coeff) >> 16; + int g = (((samp0 >> 8) & 0xff) * (0x10000 - y_coeff) + + ((samp1 >> 8) & 0xff) * y_coeff) >> 16; + int b = ((samp0 & 0xff) * (0x10000 - y_coeff) + + (samp1 & 0xff) * y_coeff) >> 16; + p[x] = (r << 16) | (g << 8) | b; + } + } + break; + + case VIDPROCCFG_FILTER_MODE_DITHER_4X4: + if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) + { + uint8_t fil[(svga->overlay_latch.xsize) * 3]; + uint8_t fil3[(svga->overlay_latch.xsize) * 3]; + + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* leilei HACK - don't know of real 4x1 hscaled behavior yet, double for now */ + { + for (x=0; xoverlay_latch.xsize;x++) + { + fil[x*3] = ((banshee->overlay_buffer[0][src_x >> 20])); + fil[x*3+1] = ((banshee->overlay_buffer[0][src_x >> 20] >> 8)); + fil[x*3+2] = ((banshee->overlay_buffer[0][src_x >> 20] >> 16)); + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x=0; xoverlay_latch.xsize;x++) + { + fil[x*3] = ((banshee->overlay_buffer[0][x])); + fil[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); + fil[x*3+2] = ((banshee->overlay_buffer[0][x] >> 16)); + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; + } + } + if (y % 2 == 0) + { + for (x=0; xoverlay_latch.xsize;x++) + { + fil[x*3] = banshee->voodoo->purpleline[fil[x*3+0]][0]; + fil[x*3+1] = banshee->voodoo->purpleline[fil[x*3+1]][1]; + fil[x*3+2] = banshee->voodoo->purpleline[fil[x*3+2]][2]; + } + } + + for (x=1; xoverlay_latch.xsize;x++) + { + fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; + fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; + fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; + } + for (x=1; xoverlay_latch.xsize;x++) + { + fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x-1) *3]]; + fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x-1) *3+1]]; + fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x-1) *3+2]]; + } + for (x=1; xoverlay_latch.xsize;x++) + { + fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; + fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; + fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; + } + for (x=0; xoverlay_latch.xsize;x++) + { + fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x+1) *3]]; + fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x+1) *3+1]]; + fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x+1) *3+2]]; + p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3]; + } + } + else /* filter disabled by emulator option */ + { + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + { + p[x] = banshee->overlay_buffer[0][src_x >> 20]; + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + p[x] = banshee->overlay_buffer[0][x]; + } + } + break; + + case VIDPROCCFG_FILTER_MODE_DITHER_2X2: + if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) + { + uint8_t fil[(svga->overlay_latch.xsize) * 3]; + uint8_t soak[(svga->overlay_latch.xsize) * 3]; + uint8_t soak2[(svga->overlay_latch.xsize) * 3]; + + uint8_t samp1[(svga->overlay_latch.xsize) * 3]; + uint8_t samp2[(svga->overlay_latch.xsize) * 3]; + uint8_t samp3[(svga->overlay_latch.xsize) * 3]; + uint8_t samp4[(svga->overlay_latch.xsize) * 3]; + + src = &svga->vram[src_addr2 & svga->vram_mask]; + OVERLAY_SAMPLE(banshee->overlay_buffer[1]); + for (x=0; xoverlay_latch.xsize;x++) + { + samp1[x*3] = ((banshee->overlay_buffer[0][x])); + samp1[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); + samp1[x*3+2] = ((banshee->overlay_buffer[0][x] >> 16)); + + samp2[x*3+0] = ((banshee->overlay_buffer[0][x+1])); + samp2[x*3+1] = ((banshee->overlay_buffer[0][x+1] >> 8)); + samp2[x*3+2] = ((banshee->overlay_buffer[0][x+1] >> 16)); + + samp3[x*3+0] = ((banshee->overlay_buffer[1][x])); + samp3[x*3+1] = ((banshee->overlay_buffer[1][x] >> 8)); + samp3[x*3+2] = ((banshee->overlay_buffer[1][x] >> 16)); + + samp4[x*3+0] = ((banshee->overlay_buffer[1][x+1])); + samp4[x*3+1] = ((banshee->overlay_buffer[1][x+1] >> 8)); + samp4[x*3+2] = ((banshee->overlay_buffer[1][x+1] >> 16)); + + /* sample two lines */ + + soak[x*3+0] = vb_filter_bx_rb [samp1[x*3+0]] [samp2[x*3+0]]; + soak[x*3+1] = vb_filter_bx_g [samp1[x*3+1]] [samp2[x*3+1]]; + soak[x*3+2] = vb_filter_bx_rb [samp1[x*3+2]] [samp2[x*3+2]]; + + soak2[x*3+0] = vb_filter_bx_rb[samp3[x*3+0]] [samp4[x*3+0]]; + soak2[x*3+1] = vb_filter_bx_g [samp3[x*3+1]] [samp4[x*3+1]]; + soak2[x*3+2] = vb_filter_bx_rb[samp3[x*3+2]] [samp4[x*3+2]]; + + /* then pour it on the rest */ + + fil[x*3+0] = vb_filter_v1_rb[soak[x*3+0]] [soak2[x*3+0]]; + fil[x*3+1] = vb_filter_v1_g [soak[x*3+1]] [soak2[x*3+1]]; + fil[x*3+2] = vb_filter_v1_rb[soak[x*3+2]] [soak2[x*3+2]]; + } + + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* 2x2 on a scaled low res */ + { + for (x=0; xoverlay_latch.xsize;x++) + { + p[x] = (fil[(src_x >> 20)*3+2] << 16) | (fil[(src_x >> 20)*3+1] << 8) | fil[(src_x >> 20)*3]; + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x=0; xoverlay_latch.xsize;x++) + { + p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3]; + } + } + } + else /* filter disabled by emulator option */ + { + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + { + p[x] = banshee->overlay_buffer[0][src_x >> 20]; + + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + p[x] = banshee->overlay_buffer[0][x]; + } + } + break; + + case VIDPROCCFG_FILTER_MODE_POINT: + default: + if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + { + p[x] = banshee->overlay_buffer[0][src_x >> 20]; + + src_x += voodoo->overlay.vidOverlayDudx; + } + } + else + { + for (x = 0; x < svga->overlay_latch.xsize; x++) + p[x] = banshee->overlay_buffer[0][x]; + } + break; + } + } + + if (banshee->vidProcCfg & VIDPROCCFG_V_SCALE_ENABLE) + voodoo->overlay.src_y += voodoo->overlay.vidOverlayDvdy; + else + voodoo->overlay.src_y += (1 << 20); +} + +void banshee_set_overlay_addr(void *p, uint32_t addr) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + + banshee->svga.overlay.addr = banshee->voodoo->leftOverlayBuf & 0xfffffff; + banshee->svga.overlay_latch.addr = banshee->voodoo->leftOverlayBuf & 0xfffffff; + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); +} + +static void banshee_vsync_callback(svga_t *svga) +{ + banshee_t *banshee = (banshee_t *)svga->p; + voodoo_t *voodoo = banshee->voodoo; + + voodoo->retrace_count++; + thread_lock_mutex(voodoo->swap_mutex); + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_unlock_mutex(voodoo->swap_mutex); + + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); + voodoo->retrace_count = 0; + banshee_set_overlay_addr(banshee, voodoo->swap_offset); + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + else + thread_unlock_mutex(voodoo->swap_mutex); + + voodoo->overlay.src_y = 0; + banshee->desktop_addr = banshee->vidDesktopStartAddr; + banshee->desktop_y = 0; +} + +static uint8_t banshee_pci_read(int func, int addr, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + uint8_t ret = 0; + + if (func) + return 0xff; +// pclog("Banshee PCI read %08X ", addr); + switch (addr) + { + case 0x00: ret = 0x1a; break; /*3DFX*/ + case 0x01: ret = 0x12; break; + + case 0x02: ret = (banshee->type == TYPE_BANSHEE) ? 0x03 : 0x05; break; + case 0x03: ret = 0x00; break; + + case 0x04: ret = banshee->pci_regs[0x04] & 0x27; break; + + case 0x07: ret = banshee->pci_regs[0x07] & 0x36; break; + + case 0x08: ret = (banshee->type == TYPE_BANSHEE) ? 3 : 1; 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 = banshee->pci_regs[0x0d] & 0xf8; break; + + case 0x10: ret = 0x00; break; /*memBaseAddr0*/ + case 0x11: ret = 0x00; break; + case 0x12: ret = 0x00; break; + case 0x13: ret = banshee->memBaseAddr0 >> 24; break; + + case 0x14: ret = 0x00; break; /*memBaseAddr1*/ + case 0x15: ret = 0x00; break; + case 0x16: ret = 0x00; break; + case 0x17: ret = banshee->memBaseAddr1 >> 24; break; + + case 0x18: ret = 0x01; break; /*ioBaseAddr*/ + case 0x19: ret = banshee->ioBaseAddr >> 8; break; + case 0x1a: ret = 0x00; break; + case 0x1b: ret = 0x00; break; + + /*Subsystem vendor ID*/ + case 0x2c: ret = banshee->pci_regs[0x2c]; break; + case 0x2d: ret = banshee->pci_regs[0x2d]; break; + case 0x2e: ret = banshee->pci_regs[0x2e]; break; + case 0x2f: ret = banshee->pci_regs[0x2f]; break; + + case 0x30: ret = banshee->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ + case 0x31: ret = 0x00; break; + case 0x32: ret = banshee->pci_regs[0x32]; break; + case 0x33: ret = banshee->pci_regs[0x33]; break; + + case 0x3c: ret = banshee->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 banshee_pci_write(int func, int addr, uint8_t val, void *p) +{ + banshee_t *banshee = (banshee_t *)p; +// svga_t *svga = &banshee->svga; + + if (func) + return; +// pclog("Banshee write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.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 (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + if (banshee->ioBaseAddr) + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + + io_sethandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + if (banshee->ioBaseAddr) + io_sethandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + } + else + { + io_removehandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + } + banshee->pci_regs[PCI_REG_COMMAND] = val & 0x27; + banshee_updatemapping(banshee); + return; + case 0x07: + banshee->pci_regs[0x07] = val & 0x3e; + return; + case 0x0d: + banshee->pci_regs[0x0d] = val & 0xf8; + return; + + case 0x13: + banshee->memBaseAddr0 = (val & 0xfe) << 24; + banshee_updatemapping(banshee); + return; + + case 0x17: + banshee->memBaseAddr1 = (val & 0xfe) << 24; + banshee_updatemapping(banshee); + return; + + case 0x19: + if (banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + io_removehandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + banshee->ioBaseAddr = val << 8; + if ((banshee->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) && banshee->ioBaseAddr) + io_sethandler(banshee->ioBaseAddr, 0x0100, banshee_ext_in, NULL, banshee_ext_inl, banshee_ext_out, NULL, banshee_ext_outl, banshee); + pclog("Banshee ioBaseAddr=%08x\n", banshee->ioBaseAddr); +// s3_virge_updatemapping(virge); + return; + + case 0x30: case 0x32: case 0x33: + banshee->pci_regs[addr] = val; + if (banshee->pci_regs[0x30] & 0x01) + { + uint32_t addr = (banshee->pci_regs[0x32] << 16) | (banshee->pci_regs[0x33] << 24); + pclog("Banshee bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&banshee->bios_rom.mapping, addr, 0x10000); + mem_mapping_enable(&banshee->bios_rom.mapping); + } + else + { + pclog("Banshee bios_rom disabled\n"); + mem_mapping_disable(&banshee->bios_rom.mapping); + } + return; + case 0x3c: + banshee->pci_regs[0x3c] = val; + return; + } +} + +static device_config_t banshee_sgram_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "8 MB", + .value = 8 + }, + { + .description = "16 MB", + .value = 16 + }, + { + .description = "" + } + }, + .default_int = 16 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithersub", + .description = "Dither subtraction", + .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 = "4", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = -1 + } +}; + +static device_config_t banshee_sdram_config[] = +{ + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithersub", + .description = "Dither subtraction", + .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 = "4", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = -1 + } +}; + +static void *banshee_init_common(char *fn, int has_sgram, int type, int voodoo_type) +{ + int mem_size; + banshee_t *banshee = malloc(sizeof(banshee_t)); + memset(banshee, 0, sizeof(banshee_t)); + + banshee->type = type; + + rom_init(&banshee->bios_rom, fn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&banshee->bios_rom.mapping); + + if (has_sgram) + mem_size = device_get_config_int("memory"); + else + mem_size = 16; /*SDRAM Banshee only supports 16 MB*/ + + svga_init(&banshee->svga, banshee, mem_size << 20, + banshee_recalctimings, + banshee_in, banshee_out, + banshee_hwcursor_draw, + banshee_overlay_draw); + banshee->svga.vsync_callback = banshee_vsync_callback; + + mem_mapping_add(&banshee->linear_mapping, 0, 0, banshee_read_linear, + banshee_read_linear_w, + banshee_read_linear_l, + banshee_write_linear, + banshee_write_linear_w, + banshee_write_linear_l, + NULL, + MEM_MAPPING_EXTERNAL, + &banshee->svga); + mem_mapping_add(&banshee->reg_mapping_low, 0, 0,banshee_reg_read, + banshee_reg_readw, + banshee_reg_readl, + banshee_reg_write, + banshee_reg_writew, + banshee_reg_writel, + NULL, + MEM_MAPPING_EXTERNAL, + banshee); + mem_mapping_add(&banshee->reg_mapping_high, 0,0,banshee_reg_read, + banshee_reg_readw, + banshee_reg_readl, + banshee_reg_write, + banshee_reg_writew, + banshee_reg_writel, + NULL, + MEM_MAPPING_EXTERNAL, + banshee); + +// io_sethandler(0x03c0, 0x0020, banshee_in, NULL, NULL, banshee_out, NULL, NULL, banshee); + + banshee->svga.bpp = 8; + banshee->svga.miscout = 1; + + banshee->dramInit0 = 1 << 27; + if (has_sgram && mem_size == 16) + banshee->dramInit0 |= (1 << 26); /*2xSGRAM = 16 MB*/ + if (!has_sgram) + banshee->dramInit1 = 1 << 30; /*SDRAM*/ + banshee->svga.decode_mask = 0x1ffffff; + + pci_add(banshee_pci_read, banshee_pci_write, banshee); + + banshee->voodoo = voodoo_2d3d_card_init(voodoo_type); + banshee->voodoo->p = banshee; + banshee->voodoo->vram = banshee->svga.vram; + banshee->voodoo->changedvram = banshee->svga.changedvram; + banshee->voodoo->fb_mem = banshee->svga.vram; + banshee->voodoo->fb_mask = banshee->svga.vram_mask; + banshee->voodoo->tex_mem[0] = banshee->svga.vram; + banshee->voodoo->tex_mem_w[0] = (uint16_t *)banshee->svga.vram; + banshee->voodoo->tex_mem[1] = banshee->svga.vram; + banshee->voodoo->tex_mem_w[1] = (uint16_t *)banshee->svga.vram; + banshee->voodoo->texture_mask = banshee->svga.vram_mask; + voodoo_generate_filter_v1(banshee->voodoo); + + banshee->vidSerialParallelPort = VIDSERIAL_DDC_DCK_W | VIDSERIAL_DDC_DDA_W; + + ddc_init(); + + switch (type) + { + case TYPE_BANSHEE: + if (has_sgram) + { + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x04; + banshee->pci_regs[0x2f] = 0x00; + } + else + { + banshee->pci_regs[0x2c] = 0x02; + banshee->pci_regs[0x2d] = 0x11; + banshee->pci_regs[0x2e] = 0x17; + banshee->pci_regs[0x2f] = 0x10; + } + break; + + case TYPE_V3_2000: + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x30; + banshee->pci_regs[0x2f] = 0x00; + break; + + case TYPE_V3_3000: + banshee->pci_regs[0x2c] = 0x1a; + banshee->pci_regs[0x2d] = 0x12; + banshee->pci_regs[0x2e] = 0x3a; + banshee->pci_regs[0x2f] = 0x00; + break; + } + + return banshee; +} + +static void *banshee_init() +{ + return banshee_init_common("pci_sg.rom", 1, TYPE_BANSHEE, VOODOO_BANSHEE); +} +static void *creative_banshee_init() +{ + return banshee_init_common("blasterpci.rom", 0, TYPE_BANSHEE, VOODOO_BANSHEE); +} +static void *v3_2000_init() +{ + return banshee_init_common("voodoo3_2000/2k11sd.rom", 0, TYPE_V3_2000, VOODOO_3); +} +static void *v3_3000_init() +{ + return banshee_init_common("voodoo3_3000/3k12sd.rom", 0, TYPE_V3_3000, VOODOO_3); +} + +static int banshee_available() +{ + return rom_present("pci_sg.rom"); +} +static int creative_banshee_available() +{ + return rom_present("blasterpci.rom"); +} +static int v3_2000_available() +{ + return rom_present("voodoo3_2000/2k11sd.rom"); +} +static int v3_3000_available() +{ + return rom_present("voodoo3_3000/3k12sd.rom"); +} + +static void banshee_close(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + voodoo_card_close(banshee->voodoo); + svga_close(&banshee->svga); + + free(banshee); +} + +static void banshee_speed_changed(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + svga_recalctimings(&banshee->svga); +} + +static void banshee_force_redraw(void *p) +{ + banshee_t *banshee = (banshee_t *)p; + + banshee->svga.fullchange = changeframecount; +} + +static uint64_t status_time = 0; + +static void banshee_add_status_info(char *s, int max_len, void *p) +{ + banshee_t *banshee = (banshee_t *)p; + voodoo_t *voodoo = banshee->voodoo; + char temps[512]; + int pixel_count_current[4]; + int pixel_count_total; + int texel_count_current[4]; + int texel_count_total; + int render_time[4]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + int c; + status_time = new_time; + + svga_add_status_info(s, max_len, &banshee->svga); + + + for (c = 0; c < 4; c++) + { + pixel_count_current[c] = voodoo->pixel_count[c]; + texel_count_current[c] = voodoo->texel_count[c]; + render_time[c] = voodoo->render_time[c]; + } + + pixel_count_total = (pixel_count_current[0] + pixel_count_current[1] + pixel_count_current[2] + pixel_count_current[3]) - + (voodoo->pixel_count_old[0] + voodoo->pixel_count_old[1] + voodoo->pixel_count_old[2] + voodoo->pixel_count_old[3]); + texel_count_total = (texel_count_current[0] + texel_count_current[1] + texel_count_current[2] + texel_count_current[3]) - + (voodoo->texel_count_old[0] + voodoo->texel_count_old[1] + voodoo->texel_count_old[2] + voodoo->texel_count_old[3]); + sprintf(temps, "%f Mpixels/sec (%f)\n%f Mtexels/sec (%f)\n%f ktris/sec\n%f%% CPU (%f%% real)\n%d frames/sec (%i)\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)render_time[0] / status_diff), + (double)texel_count_total/1000000.0, + ((double)texel_count_total/1000000.0) / ((double)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); + if (voodoo->render_threads >= 2) + { + char temps2[512]; + sprintf(temps2, "%f%% CPU (%f%% real)\n", + ((double)voodoo->render_time[1] * 100.0) / timer_freq, ((double)voodoo->render_time[1] * 100.0) / status_diff); + strncat(temps, temps2, sizeof(temps)-1); + } + if (voodoo->render_threads == 4) + { + char temps2[512]; + sprintf(temps2, "%f%% CPU (%f%% real)\n%f%% CPU (%f%% real)\n", + ((double)voodoo->render_time[2] * 100.0) / timer_freq, ((double)voodoo->render_time[2] * 100.0) / status_diff, + ((double)voodoo->render_time[3] * 100.0) / timer_freq, ((double)voodoo->render_time[3] * 100.0) / status_diff); + strncat(temps, temps2, sizeof(temps)-1); + } + + strncat(s, temps, max_len); + + strncat(s, "Overlay mode: ", max_len); /* leilei debug additions */ + if ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) == VIDPROCCFG_FILTER_MODE_DITHER_2X2) + strncat(s, "2x2 box filter\n", max_len); + if ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) == VIDPROCCFG_FILTER_MODE_DITHER_4X4) + strncat(s, "4x1 tap filter\n", max_len); + if ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) == VIDPROCCFG_FILTER_MODE_POINT) + strncat(s, "Nearest neighbor\n", max_len); + if ((banshee->vidProcCfg & VIDPROCCFG_FILTER_MODE_MASK) == VIDPROCCFG_FILTER_MODE_BILINEAR) + strncat(s, "Bilinear filtered\n", max_len); + if ((banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE)) + strncat(s, "H scaled \n", max_len); + if ((banshee->vidProcCfg & VIDPROCCFG_V_SCALE_ENABLE)) + strncat(s, "V scaled \n", max_len); + if ((banshee->vidProcCfg & VIDPROCCFG_2X_MODE)) + strncat(s, "2X mode\n", max_len); + + strncat(s, "\n", max_len); + + for (c = 0; c < 4; c++) + { + voodoo->pixel_count_old[c] = pixel_count_current[c]; + voodoo->texel_count_old[c] = texel_count_current[c]; + voodoo->render_time[c] = 0; + } + + voodoo->tri_count = voodoo->frame_count = 0; + voodoo->rd_count = voodoo->wr_count = voodoo->tex_count = 0; + voodoo->time = 0; + + voodoo->read_time = pci_nonburst_time + pci_burst_time; + + voodoo_recomp = 0; +} + +device_t voodoo_banshee_device = +{ + "Voodoo Banshee PCI (reference)", + DEVICE_PCI, + banshee_init, + banshee_close, + banshee_available, + banshee_speed_changed, + banshee_force_redraw, + banshee_add_status_info, + banshee_sgram_config +}; + +device_t creative_voodoo_banshee_device = +{ + "Creative Labs 3D Blaster Banshee PCI", + DEVICE_PCI, + creative_banshee_init, + banshee_close, + creative_banshee_available, + banshee_speed_changed, + banshee_force_redraw, + banshee_add_status_info, + banshee_sdram_config +}; + +device_t voodoo_3_2000_device = +{ + "Voodoo 3 2000 PCI", + DEVICE_PCI, + v3_2000_init, + banshee_close, + v3_2000_available, + banshee_speed_changed, + banshee_force_redraw, + banshee_add_status_info, + banshee_sdram_config +}; + +device_t voodoo_3_3000_device = +{ + "Voodoo 3 3000 PCI", + DEVICE_PCI, + v3_3000_init, + banshee_close, + v3_3000_available, + banshee_speed_changed, + banshee_force_redraw, + banshee_add_status_info, + banshee_sdram_config +}; diff --git a/src/vid_voodoo_banshee.h b/src/vid_voodoo_banshee.h new file mode 100644 index 0000000..ddd7e3f --- /dev/null +++ b/src/vid_voodoo_banshee.h @@ -0,0 +1,6 @@ +extern device_t voodoo_banshee_device; +extern device_t creative_voodoo_banshee_device; +extern device_t voodoo_3_2000_device; +extern device_t voodoo_3_3000_device; + +void banshee_set_overlay_addr(void *p, uint32_t addr); diff --git a/src/vid_voodoo_banshee_blitter.c b/src/vid_voodoo_banshee_blitter.c new file mode 100644 index 0000000..f6f0d03 --- /dev/null +++ b/src/vid_voodoo_banshee_blitter.c @@ -0,0 +1,1450 @@ +/*Current issues : + - missing screen->screen scaled blits with format conversion + - missing YUV blits + - missing linestyle + - missing wait for vsync + - missing reversible lines + + Notes : + - 16 bpp runs with tiled framebuffer - to aid 3D? + 8 and 32 bpp use linear +*/ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_banshee_blitter.h" +#include "vid_voodoo_render.h" + +#define COMMAND_CMD_MASK (0xf) +#define COMMAND_CMD_NOP (0 << 0) +#define COMMAND_CMD_SCREEN_TO_SCREEN_BLT (1 << 0) +#define COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT (2 << 0) +#define COMMAND_CMD_HOST_TO_SCREEN_BLT (3 << 0) +#define COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT (4 << 0) +#define COMMAND_CMD_RECTFILL (5 << 0) +#define COMMAND_CMD_LINE (6 << 0) +#define COMMAND_CMD_POLYLINE (7 << 0) +#define COMMAND_CMD_POLYFILL (8 << 0) +#define COMMAND_INITIATE (1 << 8) +#define COMMAND_INC_X_START (1 << 10) +#define COMMAND_INC_Y_START (1 << 11) +#define COMMAND_STIPPLE_LINE (1 << 12) +#define COMMAND_PATTERN_MONO (1 << 13) +#define COMMAND_DX (1 << 14) +#define COMMAND_DY (1 << 15) +#define COMMAND_TRANS_MONO (1 << 16) +#define COMMAND_PATOFF_X_MASK (7 << 17) +#define COMMAND_PATOFF_X_SHIFT (17) +#define COMMAND_PATOFF_Y_MASK (7 << 20) +#define COMMAND_PATOFF_Y_SHIFT (20) +#define COMMAND_CLIP_SEL (1 << 23) + +#define CMDEXTRA_SRC_COLORKEY (1 << 0) +#define CMDEXTRA_DST_COLORKEY (1 << 1) +#define CMDEXTRA_FORCE_PAT_ROW0 (1 << 3) + +#define SRC_FORMAT_STRIDE_MASK (0x1fff) +#define SRC_FORMAT_COL_MASK (0xf << 16) +#define SRC_FORMAT_COL_1_BPP (0 << 16) +#define SRC_FORMAT_COL_8_BPP (1 << 16) +#define SRC_FORMAT_COL_16_BPP (3 << 16) +#define SRC_FORMAT_COL_24_BPP (4 << 16) +#define SRC_FORMAT_COL_32_BPP (5 << 16) +#define SRC_FORMAT_COL_YUYV (8 << 16) +#define SRC_FORMAT_COL_UYVY (9 << 16) +#define SRC_FORMAT_BYTE_SWIZZLE (1 << 20) +#define SRC_FORMAT_WORD_SWIZZLE (1 << 21) +#define SRC_FORMAT_PACKING_MASK (3 << 22) +#define SRC_FORMAT_PACKING_STRIDE (0 << 22) +#define SRC_FORMAT_PACKING_BYTE (1 << 22) +#define SRC_FORMAT_PACKING_WORD (2 << 22) +#define SRC_FORMAT_PACKING_DWORD (3 << 22) + +#define DST_FORMAT_STRIDE_MASK (0x1fff) +#define DST_FORMAT_COL_MASK (0xf << 16) +#define DST_FORMAT_COL_8_BPP (1 << 16) +#define DST_FORMAT_COL_16_BPP (3 << 16) +#define DST_FORMAT_COL_24_BPP (4 << 16) +#define DST_FORMAT_COL_32_BPP (5 << 16) + +#define BRES_ERROR_MASK (0xffff) +#define BRES_ERROR_USE (1 << 31) + +enum +{ + COLORKEY_8, + COLORKEY_16, + COLORKEY_32 +}; + +static int colorkey(voodoo_t *voodoo, uint32_t src, int src_notdst, int color_format) +{ + uint32_t min = src_notdst ? voodoo->banshee_blt.srcColorkeyMin : voodoo->banshee_blt.dstColorkeyMin; + uint32_t max = src_notdst ? voodoo->banshee_blt.srcColorkeyMax : voodoo->banshee_blt.dstColorkeyMax; + + if (!(voodoo->banshee_blt.commandExtra & (src_notdst ? CMDEXTRA_SRC_COLORKEY : CMDEXTRA_DST_COLORKEY))) + return 0; + + switch (color_format) + { + case COLORKEY_8: + return ((src & 0xff) >= (min & 0xff)) && ((src & 0xff) <= (max & 0xff)); + + case COLORKEY_16: + { + int r = (src >> 11) & 0x1f, r_min = (min >> 11) & 0x1f, r_max = (max >> 11) & 0x1f; + int g = (src >> 5) & 0x3f, g_min = (min >> 5) & 0x3f, g_max = (max >> 5) & 0x3f; + int b = src & 0x1f, b_min = min & 0x1f, b_max = max & 0x1f; + + return (r >= r_min) && (r <= r_max) && (g >= g_min) && (g <= g_max) && + (b >= b_min) && (b <= b_max); + } + + case COLORKEY_32: + { + int r = (src >> 16) & 0xff, r_min = (min >> 16) & 0xff, r_max = (max >> 16) & 0xff; + int g = (src >> 8) & 0xff, g_min = (min >> 8) & 0xff, g_max = (max >> 8) & 0xff; + int b = src & 0xff, b_min = min & 0xff, b_max = max & 0xff; + + return (r >= r_min) && (r <= r_max) && (g >= g_min) && (g <= g_max) && + (b >= b_min) && (b <= b_max); + } + + default: + return 0; + } +} + +static uint32_t MIX(voodoo_t *voodoo, uint32_t dest, uint32_t src, uint32_t pattern, int colour_format_src, int colour_format_dest) +{ + int rop_nr = 0; + uint32_t result = 0; + uint32_t rop; + + if (colorkey(voodoo, src, 1, colour_format_src)) + rop_nr |= 2; + if (colorkey(voodoo, dest, 0, colour_format_dest)) + rop_nr |= 1; + + rop = voodoo->banshee_blt.rops[rop_nr]; + + if (rop & 0x01) + result |= (~pattern & ~src & ~dest); + if (rop & 0x02) + result |= (~pattern & ~src & dest); + if (rop & 0x04) + result |= (~pattern & src & ~dest); + if (rop & 0x08) + result |= (~pattern & src & dest); + if (rop & 0x10) + result |= ( pattern & ~src & ~dest); + if (rop & 0x20) + result |= ( pattern & ~src & dest); + if (rop & 0x40) + result |= ( pattern & src & ~dest); + if (rop & 0x80) + result |= ( pattern & src & dest); + + return result; +} + +static uint32_t get_addr(voodoo_t *voodoo, int x, int y, int src_notdst, uint32_t src_stride) +{ + uint32_t stride = src_notdst ? src_stride : voodoo->banshee_blt.dst_stride; + uint32_t base_addr = src_notdst ? voodoo->banshee_blt.srcBaseAddr : voodoo->banshee_blt.dstBaseAddr; + + if (src_notdst ? voodoo->banshee_blt.srcBaseAddr_tiled : voodoo->banshee_blt.dstBaseAddr_tiled) + return (base_addr + (x & 127) + ((x >> 7) * 128*32) + ((y & 31) * 128) + (y >> 5)*stride) & voodoo->fb_mask; + else + return (base_addr + x + y*stride) & voodoo->fb_mask; +} + +static void PLOT(voodoo_t *voodoo, int x, int y, int pat_x, int pat_y, uint8_t pattern_mask, uint8_t rop, uint32_t src, int src_colorkey) +{ + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t addr = get_addr(voodoo, x, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern8[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_8); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t addr = get_addr(voodoo, x*2, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint16_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern16[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_16); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t addr = get_addr(voodoo, x*3, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern24[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[addr] = (MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t addr = get_addr(voodoo, x*4, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[addr] = MIX(voodoo, dest, src, pattern, src_colorkey, COLORKEY_32); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + } +} + +static void PLOT_LINE(voodoo_t *voodoo, int x, int y, uint8_t rop, uint32_t pattern, int src_colorkey) +{ + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t addr = get_addr(voodoo, x, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = voodoo->vram[addr]; + + voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_8); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t addr = get_addr(voodoo, x*2, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*2 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint16_t *)&voodoo->vram[addr]; + + *(uint16_t *)&voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_16); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t addr = get_addr(voodoo, x*3, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*3 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + + *(uint32_t *)&voodoo->vram[addr] = (MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t addr = get_addr(voodoo, x*4, y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + x*4 + y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t dest = *(uint32_t *)&voodoo->vram[addr]; + + *(uint32_t *)&voodoo->vram[addr] = MIX(voodoo, dest, voodoo->banshee_blt.colorFore, pattern, src_colorkey, COLORKEY_32); + voodoo->changedvram[addr >> 12] = changeframecount; + break; + } + } +} + +static void update_src_stride(voodoo_t *voodoo) +{ + int bpp; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_1_BPP: + bpp = 1; + break; + case SRC_FORMAT_COL_8_BPP: + bpp = 8; + break; + case SRC_FORMAT_COL_16_BPP: + bpp = 16; + break; + case SRC_FORMAT_COL_24_BPP: + bpp = 24; + break; + case SRC_FORMAT_COL_32_BPP: + bpp = 32; + break; + + default: + bpp = 16; + break; + } + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) + { + case SRC_FORMAT_PACKING_STRIDE: + voodoo->banshee_blt.src_stride_src = voodoo->banshee_blt.src_stride; //voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + voodoo->banshee_blt.src_stride_dest = voodoo->banshee_blt.src_stride; //voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + voodoo->banshee_blt.host_data_size_src = (voodoo->banshee_blt.srcSizeX * bpp + 7) >> 3; + voodoo->banshee_blt.host_data_size_dest = (voodoo->banshee_blt.dstSizeX * bpp + 7) >> 3; +// pclog("Stride packing %08x %08x bpp=%i dstSizeX=%i\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest, bpp, voodoo->banshee_blt.dstSizeX); + break; + + case SRC_FORMAT_PACKING_BYTE: + voodoo->banshee_blt.src_stride_src = (voodoo->banshee_blt.srcSizeX * bpp + 7) >> 3; + voodoo->banshee_blt.src_stride_dest = (voodoo->banshee_blt.dstSizeX * bpp + 7) >> 3; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// pclog("Byte packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + + case SRC_FORMAT_PACKING_WORD: + voodoo->banshee_blt.src_stride_src = ((voodoo->banshee_blt.srcSizeX * bpp + 15) >> 4) * 2; + voodoo->banshee_blt.src_stride_dest = ((voodoo->banshee_blt.dstSizeX * bpp + 15) >> 4) * 2; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// pclog("Word packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + + case SRC_FORMAT_PACKING_DWORD: + voodoo->banshee_blt.src_stride_src = ((voodoo->banshee_blt.srcSizeX * bpp + 31) >> 5) * 4; + voodoo->banshee_blt.src_stride_dest = ((voodoo->banshee_blt.dstSizeX * bpp + 31) >> 5) * 4; + voodoo->banshee_blt.host_data_size_src = voodoo->banshee_blt.src_stride_src; + voodoo->banshee_blt.host_data_size_dest = voodoo->banshee_blt.src_stride_dest; +// pclog("Dword packing %08x %08x\n", voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + break; + } +} + +static void end_command(voodoo_t *voodoo) +{ + /*Update dest coordinates if required*/ + if (voodoo->banshee_blt.command & COMMAND_INC_X_START) + { + voodoo->banshee_blt.dstXY &= ~0x0000ffff; + voodoo->banshee_blt.dstXY |= (voodoo->banshee_blt.dstX & 0xffff); + } + + if (voodoo->banshee_blt.command & COMMAND_INC_Y_START) + { + voodoo->banshee_blt.dstXY &= ~0xffff0000; + voodoo->banshee_blt.dstXY |= (voodoo->banshee_blt.dstY << 16); + } +} + +static void banshee_do_rectfill(voodoo_t *voodoo) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + int dst_y = voodoo->banshee_blt.dstY; + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + +// pclog("banshee_do_rectfill: size=%i,%i dst=%i,%i\n", voodoo->banshee_blt.dstSizeX, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.dstX, voodoo->banshee_blt.dstY); +// pclog("clipping: %i,%i -> %i,%i\n", clip->x_min, clip->y_min, clip->x_max, clip->y_max); +// pclog("colorFore=%08x\n", voodoo->banshee_blt.colorFore); + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + int dst_x = voodoo->banshee_blt.dstX; + + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + } + dst_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + if (!(voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0)) + pat_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } + + end_command(voodoo); +} + +static void do_screen_to_screen_line(voodoo_t *voodoo, uint8_t *src_p, int use_x_dir, int src_x, int src_tiled) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + int dst_y = voodoo->banshee_blt.dstY; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + int src_colorkey; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_8_BPP: + src_colorkey = COLORKEY_8; + break; + case SRC_FORMAT_COL_16_BPP: + src_colorkey = COLORKEY_16; + break; + default: + src_colorkey = COLORKEY_32; + break; + } +// pclog("do_screen_to_screen_line: srcFormat=%08x dst=%08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.dstFormat); + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == + (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK)) + { + /*No conversion required*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + int src_x_real = (src_x * voodoo->banshee_blt.src_bpp) >> 3; + + if (src_tiled) + src_x_real = (src_x_real & 127) + ((src_x_real >> 7) * 128*32); + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = src_p[src_x_real]; + uint32_t dest = voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern8[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_8, COLORKEY_8); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*2, dst_y, 0, 0);//dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*2 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint16_t *)&src_p[src_x_real]; + uint32_t dest = *(uint16_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern16[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_16, COLORKEY_16); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*3, dst_y, 0, 0);//dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*3 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x_real]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern24[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (dest & 0xff000000); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*4, dst_y, 0, 0);//dst_addr = (voodoo->banshee_blt.dstBaseAddr + dst_x*4 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x_real]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + voodoo->banshee_blt.colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + } + } + if (use_x_dir) + { + src_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + else + { + src_x++; + dst_x++; + pat_x++; + } + } + } + voodoo->banshee_blt.srcY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } + else + { + /*Conversion required*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { +// int src_x = voodoo->banshee_blt.srcX; + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + int src_x_real = (src_x * voodoo->banshee_blt.src_bpp) >> 3; + + if (src_tiled) + src_x_real = (src_x_real & 127) + ((src_x_real >> 7) * 128*32); + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + uint32_t src_data = 0; + int transparent = 0; + + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_1_BPP: + { + uint8_t src_byte = src_p[src_x_real]; + src_data = (src_byte & (0x80 >> (src_x & 7))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack; + if (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) + transparent = !(src_byte & (0x80 >> (src_x & 7))); +// pclog(" 1bpp src_byte=%02x src_x=%i src_data=%x transparent=%i\n", src_byte, src_x, src_data, transparent); + break; + } + case SRC_FORMAT_COL_8_BPP: + { + src_data = src_p[src_x_real]; + break; + } + case SRC_FORMAT_COL_16_BPP: + { + uint16_t src_16 = *(uint16_t *)&src_p[src_x_real]; + int r = (src_16 >> 11); + int g = (src_16 >> 5) & 0x3f; + int b = src_16 & 0x1f; + + r = (r << 3) | (r >> 2); + g = (g << 2) | (g >> 4); + b = (b << 3) | (b >> 2); + src_data = (r << 16) | (g << 8) | b; + break; + } + case SRC_FORMAT_COL_24_BPP: + { + src_data = *(uint32_t *)&src_p[src_x_real]; + break; + } + case SRC_FORMAT_COL_32_BPP: + { + src_data = *(uint32_t *)&src_p[src_x_real]; + break; + } +#ifndef RELEASE_BUILD + default: + fatal("banshee_do_screen_to_screen_blt: unknown srcFormat %08x\n", voodoo->banshee_blt.srcFormat); +#endif + } + + if ((voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) == DST_FORMAT_COL_16_BPP && + (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) != SRC_FORMAT_COL_1_BPP) + { + int r = src_data >> 16; + int g = (src_data >> 8) & 0xff; + int b = src_data & 0xff; + + src_data = (b >> 3) | ((g >> 2) << 5) | ((r >> 3) << 11); + } + + if (!transparent) + PLOT(voodoo, dst_x, dst_y, pat_x, pat_y, pattern_mask, rop, src_data, src_colorkey); + } + if (use_x_dir) + { + src_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + dst_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + pat_x += (voodoo->banshee_blt.command & COMMAND_DX) ? -1 : 1; + } + else + { + src_x++; + dst_x++; + pat_x++; + } + } + } + voodoo->banshee_blt.srcY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } +} + +static void banshee_do_screen_to_screen_blt(voodoo_t *voodoo) +{ +// pclog("screen_to_screen: %08x %08x %08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.src_stride, voodoo->banshee_blt.src_stride_dest); +// return; + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + uint32_t src_addr = get_addr(voodoo, 0, voodoo->banshee_blt.srcY, 1, voodoo->banshee_blt.src_stride_dest); +// if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) +// pclog(" srcY=%i src_addr=%08x\n", voodoo->banshee_blt.srcY, src_addr); + do_screen_to_screen_line(voodoo, &voodoo->vram[src_addr], 1, voodoo->banshee_blt.srcX, voodoo->banshee_blt.srcBaseAddr_tiled); + } + end_command(voodoo); +} + +static void banshee_do_host_to_screen_blt(voodoo_t *voodoo, int count, uint32_t data) +{ +// if (voodoo->banshee_blt.dstBaseAddr == 0xee5194) +// pclog("banshee_do_host_to_screen_blt: data=%08x host_data_count=%i src_stride_dest=%i host_data_size_dest=%i\n", data, voodoo->banshee_blt.host_data_count, voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_BYTE_SWIZZLE) + data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_WORD_SWIZZLE) + data = (data >> 16) | (data << 16); + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) == SRC_FORMAT_PACKING_STRIDE) + { + int last_byte; + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + last_byte = ((voodoo->banshee_blt.srcX & 31) + voodoo->banshee_blt.dstSizeX + 7) >> 3; + else + last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_dest; + + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + if (voodoo->banshee_blt.host_data_count >= last_byte) + { +// pclog(" %i %i srcX=%i srcFormat=%08x\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.srcX); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + do_screen_to_screen_line(voodoo, &voodoo->banshee_blt.host_data[(voodoo->banshee_blt.srcX >> 3) & 3], 0, voodoo->banshee_blt.srcX & 7, 0); + else + do_screen_to_screen_line(voodoo, &voodoo->banshee_blt.host_data[voodoo->banshee_blt.srcX & 3], 0, 0, 0); + voodoo->banshee_blt.cur_y++; + if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) + end_command(voodoo); + } + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) << 3; + else + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK); + + voodoo->banshee_blt.host_data_count = 0; + } + } + else + { + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + while (voodoo->banshee_blt.host_data_count >= voodoo->banshee_blt.src_stride_dest) + { + voodoo->banshee_blt.host_data_count -= voodoo->banshee_blt.src_stride_dest; + +// pclog(" %i %i\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + do_screen_to_screen_line(voodoo, voodoo->banshee_blt.host_data, 0, 0, 0); + voodoo->banshee_blt.cur_y++; + if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) + end_command(voodoo); + } + + if (voodoo->banshee_blt.host_data_count) + { +// pclog(" remaining=%i\n", voodoo->banshee_blt.host_data_count); + *(uint32_t *)&voodoo->banshee_blt.host_data[0] = data >> (4-voodoo->banshee_blt.host_data_count)*8; + } + } + } +} + +static void do_screen_to_screen_stretch_line(voodoo_t *voodoo,uint8_t *src_p, int src_x, int *src_y) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; +// int src_y = voodoo->banshee_blt.srcY; + int dst_y = voodoo->banshee_blt.dstY; + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + voodoo->banshee_blt.dstY); + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint32_t *colorPattern = voodoo->banshee_blt.colorPattern; + + //int error_y = voodoo->banshee_blt.dstSizeY / 2; + +/* pclog("banshee_do_screen_to_screen_stretch_blt:\n"); + pclog(" srcXY=%i,%i srcsizeXY=%i,%i\n", voodoo->banshee_blt.srcX, voodoo->banshee_blt.srcY, voodoo->banshee_blt.srcSizeX, voodoo->banshee_blt.srcSizeY); + pclog(" dstXY=%i,%i dstsizeXY=%i,%i\n", voodoo->banshee_blt.dstX, voodoo->banshee_blt.dstY, voodoo->banshee_blt.dstSizeX, voodoo->banshee_blt.dstSizeY);*/ + if (dst_y >= clip->y_min && dst_y < clip->y_max) + { +// int src_x = voodoo->banshee_blt.srcX; + int dst_x = voodoo->banshee_blt.dstX; + int pat_x = voodoo->banshee_blt.patoff_x + voodoo->banshee_blt.dstX; + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + int error_x = voodoo->banshee_blt.dstSizeX / 2; + +// pclog(" Plot dest line %03i : src line %03i\n", dst_y, src_y); + for (voodoo->banshee_blt.cur_x = 0; voodoo->banshee_blt.cur_x < voodoo->banshee_blt.dstSizeX; voodoo->banshee_blt.cur_x++) + { + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (dst_x >= clip->x_min && dst_x < clip->x_max && pattern_trans) + { + switch (voodoo->banshee_blt.dstFormat & DST_FORMAT_COL_MASK) + { + case DST_FORMAT_COL_8_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = src_p[src_x]; + uint32_t dest = voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_8, COLORKEY_8); +// pclog("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_16_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*2, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x*2 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint16_t *)&src_p[src_x*2]; + uint32_t dest = *(uint16_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint16_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_16, COLORKEY_16); +// pclog("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, *(uint16_t *)&voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_24_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*3, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x*3 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x*3]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = (MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32) & 0xffffff) | (*(uint32_t *)&voodoo->vram[dst_addr] & 0xff000000); +// pclog("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + case DST_FORMAT_COL_32_BPP: + { + uint32_t dst_addr = get_addr(voodoo, dst_x*4, dst_y, 0, 0);//(voodoo->banshee_blt.dstBaseAddr + dst_x*4 + dst_y*voodoo->banshee_blt.dst_stride) & voodoo->fb_mask; + uint32_t src = *(uint32_t *)&src_p[src_x*4]; + uint32_t dest = *(uint32_t *)&voodoo->vram[dst_addr]; + uint32_t pattern = (voodoo->banshee_blt.command & COMMAND_PATTERN_MONO) ? + ((pattern_mask & (1 << (7-(pat_x & 7)))) ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack) : + colorPattern[(pat_x & 7) + (pat_y & 7)*8]; + + *(uint32_t *)&voodoo->vram[dst_addr] = MIX(voodoo, dest, src, pattern, COLORKEY_32, COLORKEY_32); +// pclog("%i,%i : sdp=%02x,%02x,%02x res=%02x\n", voodoo->banshee_blt.cur_x, voodoo->banshee_blt.cur_y, src, dest, pattern, voodoo->vram[dst_addr]); + voodoo->changedvram[dst_addr >> 12] = changeframecount; + break; + } + } + } + + error_x -= voodoo->banshee_blt.srcSizeX; + while (error_x < 0) + { + error_x += voodoo->banshee_blt.dstSizeX; + src_x++; + } + dst_x++; + pat_x++; + } + } + + voodoo->banshee_blt.bres_error_0 -= voodoo->banshee_blt.srcSizeY; + while (voodoo->banshee_blt.bres_error_0 < 0) + { + voodoo->banshee_blt.bres_error_0 += voodoo->banshee_blt.dstSizeY; + if (src_y) + (*src_y) += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; + } + voodoo->banshee_blt.dstY += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; +// pat_y += (voodoo->banshee_blt.command & COMMAND_DY) ? -1 : 1; +} + +static void banshee_do_screen_to_screen_stretch_blt(voodoo_t *voodoo) +{ +// pclog("screen_to_screen: %08x %08x %08x\n", voodoo->banshee_blt.srcFormat, voodoo->banshee_blt.src_stride, voodoo->banshee_blt.src_stride_dest); +// return; + for (voodoo->banshee_blt.cur_y = 0; voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY; voodoo->banshee_blt.cur_y++) + { + uint32_t src_addr = get_addr(voodoo, 0, voodoo->banshee_blt.srcY, 1, voodoo->banshee_blt.src_stride_src);//(voodoo->banshee_blt.srcBaseAddr + voodoo->banshee_blt.srcY*voodoo->banshee_blt.src_stride_src) & voodoo->fb_mask; +// pclog("scale_blit %i %08x %08x\n", voodoo->banshee_blt.cur_y, src_addr, voodoo->banshee_blt.command); +// if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) +// pclog(" srcY=%i src_addr=%08x\n", voodoo->banshee_blt.srcY, src_addr); + do_screen_to_screen_stretch_line(voodoo, &voodoo->vram[src_addr], voodoo->banshee_blt.srcX, &voodoo->banshee_blt.srcY); + } + end_command(voodoo); +} + +static void banshee_do_host_to_screen_stretch_blt(voodoo_t *voodoo, int count, uint32_t data) +{ +// if (voodoo->banshee_blt.dstBaseAddr == 0xee5194) +// pclog("banshee_do_host_to_screen_blt: data=%08x host_data_count=%i src_stride_dest=%i host_data_size_dest=%i\n", data, voodoo->banshee_blt.host_data_count, voodoo->banshee_blt.src_stride_dest, voodoo->banshee_blt.host_data_size_dest); + + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_BYTE_SWIZZLE) + data = (data >> 24) | ((data >> 8) & 0xff00) | ((data << 8) & 0xff0000) | (data << 24); + if (voodoo->banshee_blt.srcFormat & SRC_FORMAT_WORD_SWIZZLE) + data = (data >> 16) | (data << 16); + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_PACKING_MASK) == SRC_FORMAT_PACKING_STRIDE) + { + int last_byte = (voodoo->banshee_blt.srcX & 3) + voodoo->banshee_blt.host_data_size_src; + + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + if (voodoo->banshee_blt.host_data_count >= last_byte) + { +// pclog(" %i %i srcX=%i srcFormat=%08x\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY, voodoo->banshee_blt.srcX); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + do_screen_to_screen_stretch_line(voodoo, &voodoo->banshee_blt.host_data[(voodoo->banshee_blt.srcX >> 3) & 3], voodoo->banshee_blt.srcX & 7, NULL); + else + do_screen_to_screen_stretch_line(voodoo, &voodoo->banshee_blt.host_data[voodoo->banshee_blt.srcX & 3], 0, NULL); + voodoo->banshee_blt.cur_y++; + if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) + end_command(voodoo); + } + + if ((voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) == SRC_FORMAT_COL_1_BPP) + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) << 3; + else + voodoo->banshee_blt.srcX += (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK); + + voodoo->banshee_blt.host_data_count = 0; + } + } + else + { + *(uint32_t *)&voodoo->banshee_blt.host_data[voodoo->banshee_blt.host_data_count] = data; + voodoo->banshee_blt.host_data_count += 4; + while (voodoo->banshee_blt.host_data_count >= voodoo->banshee_blt.src_stride_src) + { + voodoo->banshee_blt.host_data_count -= voodoo->banshee_blt.src_stride_src; + +// pclog(" %i %i\n", voodoo->banshee_blt.cur_y, voodoo->banshee_blt.dstSizeY); + if (voodoo->banshee_blt.cur_y < voodoo->banshee_blt.dstSizeY) + { + do_screen_to_screen_stretch_line(voodoo, voodoo->banshee_blt.host_data, 0, NULL); + voodoo->banshee_blt.cur_y++; + if (voodoo->banshee_blt.cur_y == voodoo->banshee_blt.dstSizeY) + end_command(voodoo); + } + + if (voodoo->banshee_blt.host_data_count) + { +// pclog(" remaining=%i\n", voodoo->banshee_blt.host_data_count); + *(uint32_t *)&voodoo->banshee_blt.host_data[0] = data >> (4-voodoo->banshee_blt.host_data_count)*8; + } + } + } +} + +static void step_line(voodoo_t *voodoo) +{ + if (voodoo->banshee_blt.line_pix_pos == voodoo->banshee_blt.line_rep_cnt) + { + voodoo->banshee_blt.line_pix_pos = 0; + if (voodoo->banshee_blt.line_bit_pos == voodoo->banshee_blt.line_bit_mask_size) + voodoo->banshee_blt.line_bit_pos = 0; + else + voodoo->banshee_blt.line_bit_pos++; + } + else + voodoo->banshee_blt.line_pix_pos++; +} + +static void banshee_do_line(voodoo_t *voodoo, int draw_last_pixel) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + uint8_t rop = voodoo->banshee_blt.command >> 24; + int dx = ABS(voodoo->banshee_blt.dstX - voodoo->banshee_blt.srcX); + int dy = ABS(voodoo->banshee_blt.dstY - voodoo->banshee_blt.srcY); + int x_inc = (voodoo->banshee_blt.dstX > voodoo->banshee_blt.srcX) ? 1 : -1; + int y_inc = (voodoo->banshee_blt.dstY > voodoo->banshee_blt.srcY) ? 1 : -1; + int x = voodoo->banshee_blt.srcX; + int y = voodoo->banshee_blt.srcY; + int error; + uint32_t stipple = (voodoo->banshee_blt.command & COMMAND_STIPPLE_LINE) ? + voodoo->banshee_blt.lineStipple : ~0; + + if (dx > dy) /*X major*/ + { + error = dx/2; + while (x != voodoo->banshee_blt.dstX) + { + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); + + error -= dy; + if (error < 0) + { + error += dx; + y += y_inc; + } + x += x_inc; + step_line(voodoo); + } + } + else /*Y major*/ + { + error = dy/2; + while (y != voodoo->banshee_blt.dstY) + { + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); + + error -= dx; + if (error < 0) + { + error += dy; + x += x_inc; + } + y += y_inc; + step_line(voodoo); + } + } + + if (draw_last_pixel) + { + int mask = stipple & (1 << voodoo->banshee_blt.line_bit_pos); + int pattern_trans = (voodoo->banshee_blt.command & COMMAND_TRANS_MONO) ? mask : 1; + + if (y >= clip->y_min && y < clip->y_max && x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT_LINE(voodoo, x, y, rop, mask ? voodoo->banshee_blt.colorFore : voodoo->banshee_blt.colorBack, COLORKEY_32); + } + + voodoo->banshee_blt.srcXY = (x & 0xffff) | (y << 16); + voodoo->banshee_blt.srcX = x; + voodoo->banshee_blt.srcY = y; +} + +static void banshee_polyfill_start(voodoo_t *voodoo) +{ + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.srcY; + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.dstX; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.dstY; + voodoo->banshee_blt.lx[1] = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.ly[1] = voodoo->banshee_blt.srcY; + voodoo->banshee_blt.rx[1] = voodoo->banshee_blt.dstX; + voodoo->banshee_blt.ry[1] = voodoo->banshee_blt.dstY; + voodoo->banshee_blt.lx_cur = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.rx_cur = voodoo->banshee_blt.dstX; +} + +static void banshee_polyfill_continue(voodoo_t *voodoo, uint32_t data) +{ + clip_t *clip = &voodoo->banshee_blt.clip[(voodoo->banshee_blt.command & COMMAND_CLIP_SEL) ? 1 : 0]; + uint8_t *pattern_mono = (uint8_t *)voodoo->banshee_blt.colorPattern; + int use_pattern_trans = (voodoo->banshee_blt.command & (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO)) == + (COMMAND_PATTERN_MONO | COMMAND_TRANS_MONO); + uint8_t rop = voodoo->banshee_blt.command >> 24; + int y = MAX(voodoo->banshee_blt.ly[0], voodoo->banshee_blt.ry[0]); + int y_end; + +// pclog("Polyfill : data %08x\n", data); + + /*if r1.y>=l1.y, next vertex is left*/ + if (voodoo->banshee_blt.ry[1] >= voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[1] = ((int32_t)(data << 19)) >> 19; + voodoo->banshee_blt.ly[1] = ((int32_t)(data << 3)) >> 19; + voodoo->banshee_blt.dx[0] = ABS(voodoo->banshee_blt.lx[1] - voodoo->banshee_blt.lx[0]); + voodoo->banshee_blt.dy[0] = ABS(voodoo->banshee_blt.ly[1] - voodoo->banshee_blt.ly[0]); + voodoo->banshee_blt.x_inc[0] = (voodoo->banshee_blt.lx[1] > voodoo->banshee_blt.lx[0]) ? 1 : -1; + voodoo->banshee_blt.error[0] = voodoo->banshee_blt.dy[0] / 2; + } + else + { + voodoo->banshee_blt.rx[1] = ((int32_t)(data << 19)) >> 19; + voodoo->banshee_blt.ry[1] = ((int32_t)(data << 3)) >> 19; + voodoo->banshee_blt.dx[1] = ABS(voodoo->banshee_blt.rx[1] - voodoo->banshee_blt.rx[0]); + voodoo->banshee_blt.dy[1] = ABS(voodoo->banshee_blt.ry[1] - voodoo->banshee_blt.ry[0]); + voodoo->banshee_blt.x_inc[1] = (voodoo->banshee_blt.rx[1] > voodoo->banshee_blt.rx[0]) ? 1 : -1; + voodoo->banshee_blt.error[1] = voodoo->banshee_blt.dy[1] / 2; + } + +/* pclog(" verts now : %03i,%03i %03i,%03i\n", voodoo->banshee_blt.lx[0], voodoo->banshee_blt.ly[0], voodoo->banshee_blt.rx[0], voodoo->banshee_blt.ry[0]); + pclog(" %03i,%03i %03i,%03i\n", voodoo->banshee_blt.lx[1], voodoo->banshee_blt.ly[1], voodoo->banshee_blt.rx[1], voodoo->banshee_blt.ry[1]); + pclog(" left dx=%i dy=%i x_inc=%i error=%i\n", voodoo->banshee_blt.dx[0],voodoo->banshee_blt.dy[0],voodoo->banshee_blt.x_inc[0],voodoo->banshee_blt.error[0]); + pclog(" right dx=%i dy=%i x_inc=%i error=%i\n", voodoo->banshee_blt.dx[1],voodoo->banshee_blt.dy[1],voodoo->banshee_blt.x_inc[1],voodoo->banshee_blt.error[1]);*/ + y_end = MIN(voodoo->banshee_blt.ly[1], voodoo->banshee_blt.ry[1]); +// pclog("Polyfill : draw spans from %i-%i\n", y, y_end); + for (; y < y_end; y++) + { +// pclog(" %i: %i %i\n", y, voodoo->banshee_blt.lx_cur, voodoo->banshee_blt.rx_cur); + /*Draw span from lx_cur to rx_cur*/ + if (y >= clip->y_min && y < clip->y_max) + { + int pat_y = (voodoo->banshee_blt.commandExtra & CMDEXTRA_FORCE_PAT_ROW0) ? 0 : (voodoo->banshee_blt.patoff_y + y); + uint8_t pattern_mask = pattern_mono[pat_y & 7]; + int x; + + for (x = voodoo->banshee_blt.lx_cur; x < voodoo->banshee_blt.rx_cur; x++) + { + int pat_x = voodoo->banshee_blt.patoff_x + x; + int pattern_trans = use_pattern_trans ? (pattern_mask & (1 << (7-(pat_x & 7)))) : 1; + + if (x >= clip->x_min && x < clip->x_max && pattern_trans) + PLOT(voodoo, x, y, pat_x, pat_y, pattern_mask, rop, voodoo->banshee_blt.colorFore, COLORKEY_32); + } + } + + voodoo->banshee_blt.error[0] -= voodoo->banshee_blt.dx[0]; + while (voodoo->banshee_blt.error[0] < 0) + { + voodoo->banshee_blt.error[0] += voodoo->banshee_blt.dy[0]; + voodoo->banshee_blt.lx_cur += voodoo->banshee_blt.x_inc[0]; + } + voodoo->banshee_blt.error[1] -= voodoo->banshee_blt.dx[1]; + while (voodoo->banshee_blt.error[1] < 0) + { + voodoo->banshee_blt.error[1] += voodoo->banshee_blt.dy[1]; + voodoo->banshee_blt.rx_cur += voodoo->banshee_blt.x_inc[1]; + } + } + + if (voodoo->banshee_blt.ry[1] == voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.lx[1]; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.ly[1]; + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.rx[1]; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.ry[1]; + } + else if (voodoo->banshee_blt.ry[1] >= voodoo->banshee_blt.ly[1]) + { + voodoo->banshee_blt.lx[0] = voodoo->banshee_blt.lx[1]; + voodoo->banshee_blt.ly[0] = voodoo->banshee_blt.ly[1]; + } + else + { + voodoo->banshee_blt.rx[0] = voodoo->banshee_blt.rx[1]; + voodoo->banshee_blt.ry[0] = voodoo->banshee_blt.ry[1]; + } +} + +static void banshee_do_2d_blit(voodoo_t *voodoo, int count, uint32_t data) +{ + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { + case COMMAND_CMD_NOP: + break; + + case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: + banshee_do_screen_to_screen_blt(voodoo); + break; + + case COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT: + banshee_do_screen_to_screen_stretch_blt(voodoo); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_BLT: + banshee_do_host_to_screen_blt(voodoo, count, data); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: + banshee_do_host_to_screen_stretch_blt(voodoo, count, data); + break; + + case COMMAND_CMD_RECTFILL: + banshee_do_rectfill(voodoo); + break; + + case COMMAND_CMD_LINE: + banshee_do_line(voodoo, 1); + break; + + case COMMAND_CMD_POLYLINE: + banshee_do_line(voodoo, 0); + break; + +#ifndef RELEASE_BUILD + default: + fatal("banshee_do_2d_blit: unknown command=%08x\n", voodoo->banshee_blt.command); +#endif + } +} + +void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val) +{ +// /*if ((addr & 0x1fc) != 0x80) */pclog("2D reg write %03x %08x\n", addr & 0x1fc, val); + switch (addr & 0x1fc) + { + case 0x08: + voodoo->banshee_blt.clip0Min = val; + voodoo->banshee_blt.clip[0].x_min = val & 0xfff; + voodoo->banshee_blt.clip[0].y_min = (val >> 16) & 0xfff; + break; + case 0x0c: + voodoo->banshee_blt.clip0Max = val; + voodoo->banshee_blt.clip[0].x_max = val & 0xfff; + voodoo->banshee_blt.clip[0].y_max = (val >> 16) & 0xfff; + break; + case 0x10: + voodoo->banshee_blt.dstBaseAddr = val & 0xffffff; + voodoo->banshee_blt.dstBaseAddr_tiled = val & 0x80000000; + if (voodoo->banshee_blt.dstBaseAddr_tiled) + voodoo->banshee_blt.dst_stride = (voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK) * 128*32; + else + voodoo->banshee_blt.dst_stride = voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK; +// pclog("dstBaseAddr=%08x\n", val); + break; + case 0x14: + voodoo->banshee_blt.dstFormat = val; + if (voodoo->banshee_blt.dstBaseAddr_tiled) + voodoo->banshee_blt.dst_stride = (voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK) * 128*32; + else + voodoo->banshee_blt.dst_stride = voodoo->banshee_blt.dstFormat & DST_FORMAT_STRIDE_MASK; +// pclog("dstFormat=%08x\n", val); + break; + + case 0x18: + voodoo->banshee_blt.srcColorkeyMin = val & 0xffffff; + break; + case 0x1c: + voodoo->banshee_blt.srcColorkeyMax = val & 0xffffff; + break; + case 0x20: + voodoo->banshee_blt.dstColorkeyMin = val & 0xffffff; + break; + case 0x24: + voodoo->banshee_blt.dstColorkeyMax = val & 0xffffff; + break; + + case 0x28: + voodoo->banshee_blt.bresError0 = val; + voodoo->banshee_blt.bres_error_0 = val & 0xffff; + break; + case 0x2c: + voodoo->banshee_blt.bresError1 = val; + voodoo->banshee_blt.bres_error_1 = val & 0xffff; + break; + + case 0x30: + voodoo->banshee_blt.rop = val; + voodoo->banshee_blt.rops[1] = val & 0xff; + voodoo->banshee_blt.rops[2] = (val >> 8) & 0xff; + voodoo->banshee_blt.rops[3] = (val >> 16) & 0xff; +// pclog("rop=%08x\n", val); + break; + case 0x34: + voodoo->banshee_blt.srcBaseAddr = val & 0xffffff; + voodoo->banshee_blt.srcBaseAddr_tiled = val & 0x80000000; + if (voodoo->banshee_blt.srcBaseAddr_tiled) + voodoo->banshee_blt.src_stride = (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) * 128*32; + else + voodoo->banshee_blt.src_stride = voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + update_src_stride(voodoo); +// pclog("srcBaseAddr=%08x\n", val); + break; + case 0x38: + voodoo->banshee_blt.commandExtra = val; +// pclog("commandExtra=%08x\n", val); + break; + case 0x3c: + voodoo->banshee_blt.lineStipple = val; + break; + case 0x40: + voodoo->banshee_blt.lineStyle = val; + voodoo->banshee_blt.line_rep_cnt = val & 0xff; + voodoo->banshee_blt.line_bit_mask_size = (val >> 8) & 0x1f; + voodoo->banshee_blt.line_pix_pos = (val >> 16) & 0xff; + voodoo->banshee_blt.line_bit_pos = (val >> 24) & 0x1f; + break; + case 0x44: + voodoo->banshee_blt.colorPattern[0] = val; +// pclog("colorPattern0=%08x\n", val); + voodoo->banshee_blt.colorPattern24[0] = val & 0xffffff; + voodoo->banshee_blt.colorPattern24[1] = (voodoo->banshee_blt.colorPattern24[1] & 0xffff00) | (val >> 24); + voodoo->banshee_blt.colorPattern16[0] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[1] = (val >> 16) & 0xffff; + voodoo->banshee_blt.colorPattern8[0] = val & 0xff; + voodoo->banshee_blt.colorPattern8[1] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[2] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[3] = (val >> 24) & 0xff; + break; + case 0x48: + voodoo->banshee_blt.colorPattern[1] = val; +// pclog("colorPattern1=%08x\n", val); + voodoo->banshee_blt.colorPattern24[1] = (voodoo->banshee_blt.colorPattern24[1] & 0xff) | ((val & 0xffff) << 8); + voodoo->banshee_blt.colorPattern24[2] = (voodoo->banshee_blt.colorPattern24[2] & 0xff0000) | (val >> 16); + voodoo->banshee_blt.colorPattern16[2] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[3] = (val >> 16) & 0xffff; + voodoo->banshee_blt.colorPattern8[4] = val & 0xff; + voodoo->banshee_blt.colorPattern8[5] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[6] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[7] = (val >> 24) & 0xff; + break; + case 0x4c: + voodoo->banshee_blt.clip1Min = val; + voodoo->banshee_blt.clip[1].x_min = val & 0xfff; + voodoo->banshee_blt.clip[1].y_min = (val >> 16) & 0xfff; + break; + case 0x50: + voodoo->banshee_blt.clip1Max = val; + voodoo->banshee_blt.clip[1].x_max = val & 0xfff; + voodoo->banshee_blt.clip[1].y_max = (val >> 16) & 0xfff; + break; + case 0x54: + voodoo->banshee_blt.srcFormat = val; + if (voodoo->banshee_blt.srcBaseAddr_tiled) + voodoo->banshee_blt.src_stride = (voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK) * 128*32; + else + voodoo->banshee_blt.src_stride = voodoo->banshee_blt.srcFormat & SRC_FORMAT_STRIDE_MASK; + update_src_stride(voodoo); + switch (voodoo->banshee_blt.srcFormat & SRC_FORMAT_COL_MASK) + { + case SRC_FORMAT_COL_1_BPP: + voodoo->banshee_blt.src_bpp = 1; + break; + case SRC_FORMAT_COL_8_BPP: + voodoo->banshee_blt.src_bpp = 8; + break; + case SRC_FORMAT_COL_24_BPP: + voodoo->banshee_blt.src_bpp = 24; + break; + case SRC_FORMAT_COL_32_BPP: + voodoo->banshee_blt.src_bpp = 32; + break; + case SRC_FORMAT_COL_16_BPP: default: + voodoo->banshee_blt.src_bpp = 16; + break; + } +// pclog("srcFormat=%08x\n", val); + break; + case 0x58: + voodoo->banshee_blt.srcSize = val; + voodoo->banshee_blt.srcSizeX = voodoo->banshee_blt.srcSize & 0x1fff; + voodoo->banshee_blt.srcSizeY = (voodoo->banshee_blt.srcSize >> 16) & 0x1fff; + update_src_stride(voodoo); +// pclog("srcSize=%08x\n", val); + break; + case 0x5c: + voodoo->banshee_blt.srcXY = val; + voodoo->banshee_blt.srcX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(val << 3)) >> 19; + update_src_stride(voodoo); +// pclog("srcXY=%08x\n", val); + break; + case 0x60: + voodoo->banshee_blt.colorBack = val; + break; + case 0x64: + voodoo->banshee_blt.colorFore = val; + break; + case 0x68: + voodoo->banshee_blt.dstSize = val; + voodoo->banshee_blt.dstSizeX = voodoo->banshee_blt.dstSize & 0x1fff; + voodoo->banshee_blt.dstSizeY = (voodoo->banshee_blt.dstSize >> 16) & 0x1fff; + update_src_stride(voodoo); +// pclog("dstSize=%08x\n", val); + break; + case 0x6c: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; +// pclog("dstXY=%08x\n", val); + break; + case 0x70: + voodoo_wait_for_render_thread_idle(voodoo); + voodoo->banshee_blt.command = val; + voodoo->banshee_blt.rops[0] = val >> 24; +// pclog("command=%x %08x\n", voodoo->banshee_blt.command & COMMAND_CMD_MASK, val); + voodoo->banshee_blt.patoff_x = (val & COMMAND_PATOFF_X_MASK) >> COMMAND_PATOFF_X_SHIFT; + voodoo->banshee_blt.patoff_y = (val & COMMAND_PATOFF_Y_MASK) >> COMMAND_PATOFF_Y_SHIFT; + voodoo->banshee_blt.cur_x = 0; + voodoo->banshee_blt.cur_y = 0; + voodoo->banshee_blt.dstX = ((int32_t)(voodoo->banshee_blt.dstXY << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(voodoo->banshee_blt.dstXY << 3)) >> 19; + voodoo->banshee_blt.srcX = ((int32_t)(voodoo->banshee_blt.srcXY << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(voodoo->banshee_blt.srcXY << 3)) >> 19; + voodoo->banshee_blt.old_srcX = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.host_data_remainder = 0; + voodoo->banshee_blt.host_data_count = 0; + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { +/* case COMMAND_CMD_SCREEN_TO_SCREEN_STRETCH_BLT: + if (voodoo->banshee_blt.bresError0 & BRES_ERROR_USE) + voodoo->banshee_blt.bres_error_0 = (int32_t)(int16_t)(voodoo->banshee_blt.bresError0 & BRES_ERROR_MASK); + else + voodoo->banshee_blt.bres_error_0 = voodoo->banshee_blt.dstSizeY / 2; + if (voodoo->banshee_blt.bresError1 & BRES_ERROR_USE) + voodoo->banshee_blt.bres_error_1 = (int32_t)(int16_t)(voodoo->banshee_blt.bresError1 & BRES_ERROR_MASK); + else + voodoo->banshee_blt.bres_error_1 = voodoo->banshee_blt.dstSizeX / 2; + + if (val & COMMAND_INITIATE) + banshee_do_2d_blit(voodoo, -1, 0); + break;*/ + + case COMMAND_CMD_POLYFILL: + if (val & COMMAND_INITIATE) + { + voodoo->banshee_blt.dstXY = voodoo->banshee_blt.srcXY; + voodoo->banshee_blt.dstX = voodoo->banshee_blt.srcX; + voodoo->banshee_blt.dstY = voodoo->banshee_blt.srcY; + } + banshee_polyfill_start(voodoo); + break; + + default: + if (val & COMMAND_INITIATE) + { + banshee_do_2d_blit(voodoo, -1, 0); + // fatal("Initiate command!\n"); + } + break; + } + break; + + case 0x80: case 0x84: case 0x88: case 0x8c: + case 0x90: case 0x94: case 0x98: case 0x9c: + case 0xa0: case 0xa4: case 0xa8: case 0xac: + case 0xb0: case 0xb4: case 0xb8: case 0xbc: + case 0xc0: case 0xc4: case 0xc8: case 0xcc: + case 0xd0: case 0xd4: case 0xd8: case 0xdc: + case 0xe0: case 0xe4: case 0xe8: case 0xec: + case 0xf0: case 0xf4: case 0xf8: case 0xfc: +// pclog("launch %08x %08x %08x %08x\n", voodoo->banshee_blt.command, voodoo->banshee_blt.commandExtra, voodoo->banshee_blt.srcColorkeyMin, voodoo->banshee_blt.srcColorkeyMax); + switch (voodoo->banshee_blt.command & COMMAND_CMD_MASK) + { + case COMMAND_CMD_SCREEN_TO_SCREEN_BLT: + voodoo->banshee_blt.srcXY = val; + voodoo->banshee_blt.srcX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.srcY = ((int32_t)(val << 3)) >> 19; + banshee_do_screen_to_screen_blt(voodoo); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_BLT: + banshee_do_2d_blit(voodoo, 32, val); + break; + + case COMMAND_CMD_HOST_TO_SCREEN_STRETCH_BLT: + banshee_do_2d_blit(voodoo, 32, val); + break; + + case COMMAND_CMD_RECTFILL: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_rectfill(voodoo); + break; + + case COMMAND_CMD_LINE: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_line(voodoo, 1); + break; + + case COMMAND_CMD_POLYLINE: + voodoo->banshee_blt.dstXY = val; + voodoo->banshee_blt.dstX = ((int32_t)(val << 19)) >> 19; + voodoo->banshee_blt.dstY = ((int32_t)(val << 3)) >> 19; + banshee_do_line(voodoo, 0); + break; + + case COMMAND_CMD_POLYFILL: + banshee_polyfill_continue(voodoo, val); + break; + +#ifndef RELEASE_BUILD + default: + fatal("launch area write, command=%08x\n", voodoo->banshee_blt.command); +#endif + } + break; + + case 0x100: case 0x104: case 0x108: case 0x10c: + case 0x110: case 0x114: case 0x118: case 0x11c: + case 0x120: case 0x124: case 0x128: case 0x12c: + case 0x130: case 0x134: case 0x138: case 0x13c: + case 0x140: case 0x144: case 0x148: case 0x14c: + case 0x150: case 0x154: case 0x158: case 0x15c: + case 0x160: case 0x164: case 0x168: case 0x16c: + case 0x170: case 0x174: case 0x178: case 0x17c: + case 0x180: case 0x184: case 0x188: case 0x18c: + case 0x190: case 0x194: case 0x198: case 0x19c: + case 0x1a0: case 0x1a4: case 0x1a8: case 0x1ac: + case 0x1b0: case 0x1b4: case 0x1b8: case 0x1bc: + case 0x1c0: case 0x1c4: case 0x1c8: case 0x1cc: + case 0x1d0: case 0x1d4: case 0x1d8: case 0x1dc: + case 0x1e0: case 0x1e4: case 0x1e8: case 0x1ec: + case 0x1f0: case 0x1f4: case 0x1f8: case 0x1fc: + voodoo->banshee_blt.colorPattern[(addr >> 2) & 63] = val; + if ((addr & 0x1fc) < 0x1c0) + { + int base_addr = (addr & 0xfc) / 0xc; + uintptr_t src_p = (uintptr_t)&voodoo->banshee_blt.colorPattern[base_addr * 3]; + int col24 = base_addr * 4; + + voodoo->banshee_blt.colorPattern24[col24] = *(uint32_t *)src_p & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 1] = *(uint32_t *)(src_p + 3) & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 2] = *(uint32_t *)(src_p + 6) & 0xffffff; + voodoo->banshee_blt.colorPattern24[col24 + 3] = *(uint32_t *)(src_p + 9) & 0xffffff; + } + if ((addr & 0x1fc) < 0x180) + { + voodoo->banshee_blt.colorPattern16[(addr >> 1) & 62] = val & 0xffff; + voodoo->banshee_blt.colorPattern16[((addr >> 1) & 62) + 1] = (val >> 16) & 0xffff; + } + if ((addr & 0x1fc) < 0x140) + { + voodoo->banshee_blt.colorPattern8[addr & 60] = val & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 1] = (val >> 8) & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 2] = (val >> 16) & 0xff; + voodoo->banshee_blt.colorPattern8[(addr & 60) + 3] = (val >> 24) & 0xff; + } +// pclog("colorPattern%02x=%08x\n", (addr >> 2) & 63, val); + break; + +#ifndef RELEASE_BUILD + default: + fatal("Unknown 2D reg write %03x %08x\n", addr & 0x1fc, val); +#endif + } +} diff --git a/src/vid_voodoo_banshee_blitter.h b/src/vid_voodoo_banshee_blitter.h new file mode 100644 index 0000000..cc7a8f2 --- /dev/null +++ b/src/vid_voodoo_banshee_blitter.h @@ -0,0 +1 @@ +void voodoo_2d_reg_writel(voodoo_t *voodoo, uint32_t addr, uint32_t val); diff --git a/src/vid_voodoo_blitter.c b/src/vid_voodoo_blitter.c new file mode 100644 index 0000000..af7e204 --- /dev/null +++ b/src/vid_voodoo_blitter.c @@ -0,0 +1,509 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_blitter.h" +#include "vid_voodoo_dither.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" + +enum +{ + BLIT_COMMAND_SCREEN_TO_SCREEN = 0, + BLIT_COMMAND_CPU_TO_SCREEN = 1, + BLIT_COMMAND_RECT_FILL = 2, + BLIT_COMMAND_SGRAM_FILL = 3 +}; + +enum +{ + BLIT_SRC_1BPP = (0 << 3), + BLIT_SRC_1BPP_BYTE_PACKED = (1 << 3), + BLIT_SRC_16BPP = (2 << 3), + BLIT_SRC_24BPP = (3 << 3), + BLIT_SRC_24BPP_DITHER_2X2 = (4 << 3), + BLIT_SRC_24BPP_DITHER_4X4 = (5 << 3) +}; + +enum +{ + BLIT_SRC_RGB_ARGB = (0 << 6), + BLIT_SRC_RGB_ABGR = (1 << 6), + BLIT_SRC_RGB_RGBA = (2 << 6), + BLIT_SRC_RGB_BGRA = (3 << 6) +}; + +enum +{ + BLIT_COMMAND_MASK = 7, + BLIT_SRC_FORMAT = (7 << 3), + BLIT_SRC_RGB_FORMAT = (3 << 6), + BLIT_SRC_CHROMA = (1 << 10), + BLIT_DST_CHROMA = (1 << 12), + BLIT_CLIPPING_ENABLED = (1 << 16) +}; + +enum +{ + BLIT_ROP_DST_PASS = (1 << 0), + BLIT_ROP_SRC_PASS = (1 << 1) +}; + +#define MIX(src_dat, dst_dat, rop) \ + switch (rop) \ + { \ + case 0x0: dst_dat = 0; break; \ + case 0x1: dst_dat = ~(src_dat | dst_dat); break; \ + case 0x2: dst_dat = ~src_dat & dst_dat; break; \ + case 0x3: dst_dat = ~src_dat; break; \ + case 0x4: dst_dat = src_dat & ~dst_dat; break; \ + case 0x5: dst_dat = ~dst_dat; break; \ + case 0x6: dst_dat = src_dat ^ dst_dat; break; \ + case 0x7: dst_dat = ~(src_dat & dst_dat); break; \ + case 0x8: dst_dat = src_dat & dst_dat; break; \ + case 0x9: dst_dat = ~(src_dat ^ dst_dat); break; \ + case 0xa: dst_dat = dst_dat; break; \ + case 0xb: dst_dat = ~src_dat | dst_dat; break; \ + case 0xc: dst_dat = src_dat; break; \ + case 0xd: dst_dat = src_dat | ~dst_dat; break; \ + case 0xe: dst_dat = src_dat | dst_dat; break; \ + case 0xf: dst_dat = 0xffff; break; \ + } + +void voodoo_v2_blit_start(voodoo_t *voodoo) +{ + uint64_t dat64; + int size_x = ABS(voodoo->bltSizeX), size_y = ABS(voodoo->bltSizeY); + int x_dir = (voodoo->bltSizeX > 0) ? 1 : -1; + int y_dir = (voodoo->bltSizeY > 0) ? 1 : -1; + int dst_x; + int src_y = voodoo->bltSrcY & 0x7ff, dst_y = voodoo->bltDstY & 0x7ff; + int src_stride = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcXYStride & 0x3f) * 32*2) : (voodoo->bltSrcXYStride & 0xff8); + int dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); + uint32_t src_base_addr = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcBaseAddr & 0x3ff) << 12) : (voodoo->bltSrcBaseAddr & 0x3ffff8); + uint32_t dst_base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + int x, y; + +/* pclog("blit_start: command=%08x srcX=%i srcY=%i dstX=%i dstY=%i sizeX=%i sizeY=%i color=%04x,%04x\n", + voodoo->bltCommand, voodoo->bltSrcX, voodoo->bltSrcY, voodoo->bltDstX, voodoo->bltDstY, voodoo->bltSizeX, voodoo->bltSizeY, voodoo->bltColorFg, voodoo->bltColorBg);*/ + + voodoo_wait_for_render_thread_idle(voodoo); + + switch (voodoo->bltCommand & BLIT_COMMAND_MASK) + { + case BLIT_COMMAND_SCREEN_TO_SCREEN: + for (y = 0; y <= size_y; y++) + { + uint16_t *src = (uint16_t *)&voodoo->fb_mem[src_base_addr + src_y*src_stride]; + uint16_t *dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; + int src_x = voodoo->bltSrcX, dst_x = voodoo->bltDstX; + + for (x = 0; x <= size_x; x++) + { + uint16_t src_dat = src[src_x]; + uint16_t dst_dat = dst[dst_x]; + int rop = 0; + + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || + dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) + goto skip_pixel_blit; + } + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + int r = (src_dat >> 11); + int g = (src_dat >> 5) & 0x3f; + int b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + int r = (dst_dat >> 11); + int g = (dst_dat >> 5) & 0x3f; + int b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); + + dst[dst_x] = dst_dat; +skip_pixel_blit: + src_x += x_dir; + dst_x += x_dir; + } + + src_y += y_dir; + dst_y += y_dir; + } + break; + + case BLIT_COMMAND_CPU_TO_SCREEN: + voodoo->blt.dst_x = voodoo->bltDstX; + voodoo->blt.dst_y = voodoo->bltDstY; + voodoo->blt.cur_x = 0; + voodoo->blt.size_x = size_x; + voodoo->blt.size_y = size_y; + voodoo->blt.x_dir = x_dir; + voodoo->blt.y_dir = y_dir; + voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); + break; + + case BLIT_COMMAND_RECT_FILL: + for (y = 0; y <= size_y; y++) + { + uint16_t *dst; + int dst_x = voodoo->bltDstX; + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + goto skip_line_fill; + dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + (dst_y >> 1) * dst_stride]; + } + else + dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; + + for (x = 0; x <= size_x; x++) + { + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || + dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) + goto skip_pixel_fill; + } + + dst[dst_x] = voodoo->bltColorFg; +skip_pixel_fill: + dst_x += x_dir; + } +skip_line_fill: + dst_y += y_dir; + } + break; + + case BLIT_COMMAND_SGRAM_FILL: + /*32x32 tiles - 2kb*/ + dst_y = voodoo->bltDstY & 0x3ff; + size_x = voodoo->bltSizeX & 0x1ff; //512*8 = 4kb + size_y = voodoo->bltSizeY & 0x3ff; + + dat64 = voodoo->bltColorFg | ((uint64_t)voodoo->bltColorFg << 16) | + ((uint64_t)voodoo->bltColorFg << 32) | ((uint64_t)voodoo->bltColorFg << 48); + + for (y = 0; y <= size_y; y++) + { + uint64_t *dst; + + /*This may be wrong*/ + if (!y) + { + dst_x = voodoo->bltDstX & 0x1ff; + size_x = 511 - dst_x; + } + else if (y < size_y) + { + dst_x = 0; + size_x = 511; + } + else + { + dst_x = 0; + size_x = voodoo->bltSizeX & 0x1ff; + } + + dst = (uint64_t *)&voodoo->fb_mem[(dst_y*512*8 + dst_x*8) & voodoo->fb_mask]; + + for (x = 0; x <= size_x; x++) + dst[x] = dat64; + + dst_y++; + } + break; + + default: + fatal("bad blit command %08x\n", voodoo->bltCommand); + } +} + +void voodoo_v2_blit_data(voodoo_t *voodoo, uint32_t data) +{ + int src_bits = 32; + uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + uint32_t addr; + uint16_t *dst; + + if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN) + return; + + if (SLI_ENABLED) + { + addr = base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + else + { + addr = base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + + if (addr >= voodoo->front_offset && voodoo->row_width) + { + int y = (addr - voodoo->front_offset) / voodoo->row_width; + if (y < voodoo->v_disp) + voodoo->dirty_line[y] = 2; + } + + while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x) + { + int r = 0, g = 0, b = 0; + uint16_t src_dat = 0, dst_dat; + int x = (voodoo->blt.x_dir > 0) ? (voodoo->blt.dst_x + voodoo->blt.cur_x) : (voodoo->blt.dst_x - voodoo->blt.cur_x); + int rop = 0; + + switch (voodoo->bltCommand & BLIT_SRC_FORMAT) + { + case BLIT_SRC_1BPP: case BLIT_SRC_1BPP_BYTE_PACKED: + src_dat = (data & 1) ? voodoo->bltColorFg : voodoo->bltColorBg; + data >>= 1; + src_bits--; + break; + case BLIT_SRC_16BPP: + switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) + { + case BLIT_SRC_RGB_ARGB: case BLIT_SRC_RGB_RGBA: + src_dat = data & 0xffff; + break; + case BLIT_SRC_RGB_ABGR: case BLIT_SRC_RGB_BGRA: + src_dat = ((data & 0xf800) >> 11) | (data & 0x07c0) | ((data & 0x0038) << 11); + break; + } + data >>= 16; + src_bits -= 16; + break; + case BLIT_SRC_24BPP: case BLIT_SRC_24BPP_DITHER_2X2: case BLIT_SRC_24BPP_DITHER_4X4: + switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) + { + case BLIT_SRC_RGB_ARGB: + r = (data >> 16) & 0xff; + g = (data >> 8) & 0xff; + b = data & 0xff; + break; + case BLIT_SRC_RGB_ABGR: + r = data & 0xff; + g = (data >> 8) & 0xff; + b = (data >> 16) & 0xff; + break; + case BLIT_SRC_RGB_RGBA: + r = (data >> 24) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 8) & 0xff; + break; + case BLIT_SRC_RGB_BGRA: + r = (data >> 8) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 24) & 0xff; + break; + } + switch (voodoo->bltCommand & BLIT_SRC_FORMAT) + { + case BLIT_SRC_24BPP: + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + case BLIT_SRC_24BPP_DITHER_2X2: + r = dither_rb2x2[r][voodoo->blt.dst_y & 1][x & 1]; + g = dither_g2x2[g][voodoo->blt.dst_y & 1][x & 1]; + b = dither_rb2x2[b][voodoo->blt.dst_y & 1][x & 1]; + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + case BLIT_SRC_24BPP_DITHER_4X4: + r = dither_rb[r][voodoo->blt.dst_y & 3][x & 3]; + g = dither_g[g][voodoo->blt.dst_y & 3][x & 3]; + b = dither_rb[b][voodoo->blt.dst_y & 3][x & 3]; + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + } + src_bits = 0; + break; + } + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + goto skip_pixel; + } + + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (x < voodoo->bltClipLeft || x >= voodoo->bltClipRight || + voodoo->blt.dst_y < voodoo->bltClipLowY || voodoo->blt.dst_y >= voodoo->bltClipHighY) + goto skip_pixel; + } + + dst_dat = dst[x]; + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + r = (src_dat >> 11); + g = (src_dat >> 5) & 0x3f; + b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + r = (dst_dat >> 11); + g = (dst_dat >> 5) & 0x3f; + b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); + + dst[x] = dst_dat; + +skip_pixel: + voodoo->blt.cur_x++; + } + + if (voodoo->blt.cur_x > voodoo->blt.size_x) + { + voodoo->blt.size_y--; + if (voodoo->blt.size_y >= 0) + { + voodoo->blt.cur_x = 0; + voodoo->blt.dst_y += voodoo->blt.y_dir; + } + } +} + + +void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) +{ + int y; + int low_y, high_y; + + if (params->fbzMode & (1 << 17)) + { + int y_origin = (voodoo->type >= VOODOO_BANSHEE) ? (voodoo->y_origin_swap+1) : voodoo->v_disp; + + high_y = y_origin - params->clipLowY; + low_y = y_origin - params->clipHighY; + } + else + { + low_y = params->clipLowY; + high_y = params->clipHighY; + } + + 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); + + if (SLI_ENABLED) + { + for (y = low_y; y < high_y; y += 2) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + else + { + for (y = low_y; y < high_y; y++) + { + if (voodoo->col_tiled) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 5) * voodoo->row_width + (y & 31) * 128) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + { + int x2 = (x & 63) | ((x >> 6) * 128*32/2); + cbuf[x2] = col; + } + } + else + { + 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) + { + if (SLI_ENABLED) + { + for (y = low_y; y < high_y; y += 2) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } + else + { + for (y = low_y; y < high_y; y++) + { + if (voodoo->aux_tiled) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 5) * voodoo->aux_row_width + (y & 31) * 128) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + { + int x2 = (x & 63) | ((x >> 6) * 128*32/2); + abuf[x2] = params->zaColor & 0xffff; + } + } + else + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y * voodoo->aux_row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } + } + } +} diff --git a/src/vid_voodoo_blitter.h b/src/vid_voodoo_blitter.h new file mode 100644 index 0000000..8d315df --- /dev/null +++ b/src/vid_voodoo_blitter.h @@ -0,0 +1,3 @@ +void voodoo_v2_blit_start(voodoo_t *voodoo); +void voodoo_v2_blit_data(voodoo_t *voodoo, uint32_t data); +void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params); diff --git a/src/vid_voodoo_codegen_x86-64.h b/src/vid_voodoo_codegen_x86-64.h index 1e940a7..0177631 100644 --- a/src/vid_voodoo_codegen_x86-64.h +++ b/src/vid_voodoo_codegen_x86-64.h @@ -5,7 +5,7 @@ fbzColorPath */ -#ifdef __linux__ +#if defined(__linux__) || defined(__APPLE__) #include #include #endif @@ -34,43 +34,50 @@ typedef struct voodoo_x86_data_t uint32_t textureMode[2]; uint32_t tLOD[2]; uint32_t trexInit1; + int is_tiled; } 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}; +static int last_block[4] = {0, 0}; +static int next_block_to_write[4] = {0, 0}; -#define addbyte(val) \ - code_block[block_pos++] = val; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addbyte(val) \ + do { \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addword(val) \ - *(uint16_t *)&code_block[block_pos] = val; \ - block_pos += 2; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addword(val) \ + do { \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addlong(val) \ - *(uint32_t *)&code_block[block_pos] = val; \ - block_pos += 4; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addlong(val) \ + do { \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addquad(val) \ - *(uint64_t *)&code_block[block_pos] = val; \ - block_pos += 8; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addquad(val) \ + do { \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) static __m128i xmm_01_w;// = 0x0001000100010001ull; static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; static __m128i xmm_ff_b;// = 0x00000000ffffffffull; -static uint32_t zero = 0; - static __m128i alookup[257], aminuslookup[256]; static __m128i minus_254;// = 0xff02ff02ff02ff02ull; static __m128i bilinear_lookup[256*2]; @@ -157,10 +164,11 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x89); /*MOV state->tex_s, EBX*/ addbyte(0x9f); addlong(offsetof(voodoo_state_t, tex_s)); - addbyte(0x0f); /*MOVZX EAX, logtable[RAX]*/ + addbyte(0x41); /*MOVZX EAX, R9(logtable)[RAX]*/ + addbyte(0x0f); addbyte(0xb6); - addbyte(0x80); - addlong((uint32_t)(uintptr_t)logtable); + addbyte(0x04); + addbyte(0x01); addbyte(0x09); /*OR EAX, EDX*/ addbyte(0xd0); addbyte(0x03); /*ADD EAX, state->lod*/ @@ -334,11 +342,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(1); if (state->clamp_t[tmu]) { - addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x41); /*CMOVS EDX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x14); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x12); addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ addbyte(0x96); addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); @@ -348,11 +355,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); addbyte(0x85); /*TEST EBX,EBX*/ addbyte(0xdb); - addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x41); /*CMOVS EBX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x1a); addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); @@ -395,11 +401,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v addbyte(0x8b); /*MOV ebp_store2, RSI*/ addbyte(0xb7); addlong(offsetof(voodoo_state_t, ebp_store)); - addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x41); /*CMOVS EAX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x02); addbyte(0x78); /*JS + - clamp on 0*/ addbyte(2+3+2+ 5+5+2); addbyte(0x3b); /*CMP EAX, EBP*/ @@ -610,11 +615,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v { addbyte(0x85); /*TEST EAX, EAX*/ addbyte(0xc0); - addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x41); /*CMOVS EAX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x02); addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ addbyte(0x84); addbyte(0x8e); @@ -637,11 +641,10 @@ static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, v { addbyte(0x85); /*TEST EBX, EBX*/ addbyte(0xdb); - addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x41); /*CMOVS EBX, R10(alookup[0](zero))*/ + addbyte(0x0f); addbyte(0x48); - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x1a); addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ addbyte(0x9c); addbyte(0x8e); @@ -707,11 +710,48 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x57); /*PUSH RDI*/ addbyte(0x56); /*PUSH RSI*/ addbyte(0x53); /*PUSH RBX*/ + 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(0x49); /*MOV R15, xmm_01_w*/ + addbyte(0xbf); + addquad((uint64_t)(uintptr_t)&xmm_01_w); + addbyte(0x66); /*MOVDQA XMM8, [R15]*/ + addbyte(0x45); + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x07 | (0 << 3)); + addbyte(0x49); /*MOV R15, xmm_ff_w*/ + addbyte(0xbf); + addquad((uint64_t)(uintptr_t)&xmm_ff_w); + addbyte(0x66); /*MOVDQA XMM9, [R15]*/ + addbyte(0x45); + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x07 | (1 << 3)); + addbyte(0x49); /*MOV R15, xmm_ff_b*/ + addbyte(0xbf); + addquad((uint64_t)(uintptr_t)&xmm_ff_b); + addbyte(0x66); /*MOVDQA XMM10, [R15]*/ + addbyte(0x45); + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x07 | (2 << 3)); + addbyte(0x49); /*MOV R15, minus_254*/ + addbyte(0xbf); + addquad((uint64_t)(uintptr_t)&minus_254); + addbyte(0x66); /*MOVDQA XMM11, [R15]*/ + addbyte(0x45); + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x07 | (3 << 3)); + #if WIN64 addbyte(0x48); /*MOV RDI, RCX (voodoo_state)*/ addbyte(0x89); @@ -723,17 +763,56 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x89); addbyte(0xce); #else - addbyte(0x49); /*MOV R9, RCX (real_y)*/ + addbyte(0x49); /*MOV R14, RCX (real_y)*/ addbyte(0x89); - addbyte(0xc9); + addbyte(0xce); addbyte(0x49); /*MOV R15, RSI (voodoo_state)*/ addbyte(0x89); addbyte(0xf7); #endif + + addbyte(0x49); /*MOV R9, logtable*/ + addbyte(0xb8 | (9 & 7)); + addquad((uint64_t)(uintptr_t)&logtable); + addbyte(0x49); /*MOV R10, alookup*/ + addbyte(0xb8 | (10 & 7)); + addquad((uint64_t)(uintptr_t)&alookup); + addbyte(0x49); /*MOV R11, aminuslookup*/ + addbyte(0xb8 | (11 & 7)); + addquad((uint64_t)(uintptr_t)&aminuslookup); + addbyte(0x49); /*MOV R12, xmm_00_ff_w*/ + addbyte(0xb8 | (12 & 7)); + addquad((uint64_t)(uintptr_t)&xmm_00_ff_w); + addbyte(0x49); /*MOV R13, i_00_ff_w*/ + addbyte(0xb8 | (13 & 7)); + addquad((uint64_t)(uintptr_t)&i_00_ff_w); + loop_jump_pos = block_pos; addbyte(0x4c); /*MOV RSI, R15*/ addbyte(0x89); addbyte(0xfe); + if (params->col_tiled || params->aux_tiled) + { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*AND EAX, 63*/ + addbyte(0xe0); + addbyte(63); + addbyte(0xc1); /*SHR EBX, 6*/ + addbyte(0xeb); + addbyte(6); + addbyte(0xc1); /*SHL EBX, 11 - tile is 128*32, << 12, div 2 because word index*/ + addbyte(0xe3); + addbyte(11); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + addbyte(0x89); /*MOV state->x_tiled[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x_tiled)); + } addbyte(0x66); /*PXOR XMM2, XMM2*/ addbyte(0x0f); addbyte(0xef); @@ -800,10 +879,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo 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 (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) { @@ -851,7 +930,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ addbyte(0x9f); - addlong(offsetof(voodoo_state_t, x)); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x48); /*MOV RCX, aux_mem[RDI]*/ addbyte(0x8b); addbyte(0x8f); @@ -1047,8 +1129,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(params->detail_scale[1]); addbyte(0x39); /*CMP EAX, EDX*/ addbyte(0xd0); - addbyte(0x0f); /*CMOVA EAX, EDX*/ - addbyte(0x47); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); addbyte(0xc2); addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); @@ -1075,27 +1157,26 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) { - addbyte(0x66); /*PXOR XMM0, xmm_00_ff_w[EBX]*/ - addbyte(0x0f); - addbyte(0xef); - addbyte(0x83); - addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); - } - else if (!tc_reverse_blend_1) - { - addbyte(0x66); /*PXOR XMM0, xmm_ff_w*/ + addbyte(0x66); /*PXOR XMM0, R12(xmm_00_ff_w)[EBX]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0x1c); } - addbyte(0x66); /*PADDW XMM0, xmm_01_w*/ + else if (!tc_reverse_blend_1) + { + addbyte(0x66); /*PXOR XMM0, XMM9(xmm_ff_w)*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc1); + } + addbyte(0x66); /*PADDW XMM0, XMM8(xmm_01_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xc0); addbyte(0xf3); /*MOVQ XMM1, XMM2*/ addbyte(0x0f); addbyte(0x7e); @@ -1201,8 +1282,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(params->detail_scale[1]); addbyte(0x39); /*CMP EAX, EDX*/ addbyte(0xd0); - addbyte(0x0f); /*CMOVA EAX, EDX*/ - addbyte(0x47); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); addbyte(0xc2); break; case TCA_MSELECT_LOD_FRAC: @@ -1213,10 +1294,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) { - addbyte(0x33); /*XOR EAX, i_00_ff_w[ECX*4]*/ - addbyte(0x04); + addbyte(0x41); /*XOR EAX, R13(i_00_ff_w)[ECX*4]*/ + addbyte(0x33); + addbyte(0x44); addbyte(0x8d); - addlong((uint32_t)(uintptr_t)i_00_ff_w); + addbyte(0); } else if (!tc_reverse_blend_1) { @@ -1371,8 +1453,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(params->detail_scale[0]); addbyte(0x39); /*CMP EAX, EDX*/ addbyte(0xd0); - addbyte(0x0f); /*CMOVA EAX, EDX*/ - addbyte(0x47); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); addbyte(0xc2); addbyte(0x66); /*MOVD XMM4, EAX*/ addbyte(0x0f); @@ -1399,27 +1481,26 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) { - addbyte(0x66); /*PXOR XMM4, xmm_00_ff_w[EBX]*/ - addbyte(0x0f); - addbyte(0xef); - addbyte(0xa3); - addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); - } - else if (!tc_reverse_blend) - { - addbyte(0x66); /*PXOR XMM4, FF*/ + addbyte(0x66); /*PXOR XMM4, R12(xmm_00_ff_w)[EBX]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0x1c); } - addbyte(0x66); /*PADDW XMM4, 1*/ + else if (!tc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM4, XMM9(xmm_ff_w)*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe1); + } + addbyte(0x66); /*PADDW XMM4, XMM8(xmm_01_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xe0); addbyte(0xf3); /*MOVQ XMM5, XMM1*/ addbyte(0x0f); addbyte(0x7e); @@ -1483,11 +1564,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (tc_invert_output) { - addbyte(0x66); /*PXOR XMM1, FF*/ + addbyte(0x66); /*PXOR XMM1, XMM9(xmm_ff_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); - addbyte(0x0d); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0xc9); } addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ @@ -1569,8 +1650,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(params->detail_scale[1]); addbyte(0x39); /*CMP EBX, EDX*/ addbyte(0xd3); - addbyte(0x0f); /*CMOVA EBX, EDX*/ - addbyte(0x47); + addbyte(0x0f); /*CMOVNL EBX, EDX*/ + addbyte(0x4d); addbyte(0xda); break; case TCA_MSELECT_LOD_FRAC: @@ -1581,10 +1662,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) { - addbyte(0x33); /*XOR EBX, i_00_ff_w[ECX*4]*/ - addbyte(0x1c); + addbyte(0x41); /*XOR EBX, R13(i_00_ff_w)[ECX*4]*/ + addbyte(0x33); + addbyte(0x5c); addbyte(0x8d); - addlong((uint32_t)(uintptr_t)i_00_ff_w); + addbyte(0); } else if (!tca_reverse_blend) { @@ -1651,10 +1733,44 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & FBZ_CHROMAKEY)) { - addbyte(0x66); /*MOVD EAX, XMM0*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0xc0); + switch (_rgb_sel) + { + case 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); + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + case CC_LOCALSELECT_COLOR1: + addbyte(0x8b); /*MOV EAX, params->color1[RSI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + break; + case CC_LOCALSELECT_TEX: + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + } addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, chromaKey)); @@ -1671,15 +1787,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if (voodoo->trexInit1[0] & (1 << 18)) { - addbyte(0xb8); /*MOV EAX, 0x000001*/ - if (voodoo->dual_tmus) - { - addlong(0x0000c1); - } - else - { - addlong(0x000001); - } + addbyte(0xb8); /*MOV EAX, tmuConfig*/ + addlong(voodoo->tmuConfig); addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); addbyte(0x6e); @@ -1861,7 +1970,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x6e); addbyte(0x8e); addlong(offsetof(voodoo_params_t, color0)); - /*JMP +*/ + addbyte(0xeb); /*JMP +*/ + addbyte(8+5+4+4); /*!cc_localselect:*/ addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ addbyte(0x0f); @@ -2137,19 +2247,17 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xe0); if (!cc_reverse_blend) { - addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x66); /*PXOR XMM3, XMM9(xmm_ff_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0xd9); } - addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x66); /*PADDW XMM3, XMM8(xmm_01_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x1c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xd8); addbyte(0x66); /*PMULLW XMM0, XMM3*/ addbyte(0x0f); addbyte(0xd5); @@ -2188,12 +2296,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if (cc_invert_output) { - addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x66); /*PXOR XMM0, XMM10(xmm_ff_b)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xef); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_b); + addbyte(0xc2); } if (params->fogMode & FOG_ENABLE) @@ -2350,11 +2457,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc0); addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); - addbyte(0x1c); - addbyte(0xc5); - addlong(((uintptr_t)alookup) + 16); + addbyte(0x5c); + addbyte(0xc2); + addbyte(16); addbyte(0x66); /*PSRAW XMM3, 7*/ addbyte(0x0f); addbyte(0x71); @@ -2443,7 +2551,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addquad((uintptr_t)rgb565); addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ addbyte(0x87); - addlong(offsetof(voodoo_state_t, x)); + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x48); /*MOV RBP, fb_mem*/ addbyte(0x8b); addbyte(0xaf); @@ -2483,22 +2594,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xe4); break; case AFUNC_ASRC_ALPHA: - addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x66); /*PMULLW XMM4, R10(alookup)[EDX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); addbyte(0x24); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)alookup); + addbyte(0xd2); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xec); - addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM4, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2523,12 +2634,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x7e); addbyte(0xec); - addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM4, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2549,22 +2660,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo case AFUNC_AONE: break; case AFUNC_AOMSRC_ALPHA: - addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x66); /*PMULLW XMM4, R11(aminuslookup)[EDX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); addbyte(0x24); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)aminuslookup); + addbyte(0xd3); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xec); - addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM4, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2581,12 +2692,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(8); break; case AFUNC_AOM_COLOR: - addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0xf3); /*MOVQ XMM5, XMM9(xmm_ff_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0x7e); - addbyte(0x2c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0xe9); addbyte(0x66); /*PSUBW XMM5, XMM0*/ addbyte(0x0f); addbyte(0xf9); @@ -2600,11 +2710,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x7e); addbyte(0xec); addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2627,22 +2737,21 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xe4); break; case AFUNC_ASATURATE: - addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x66); /*PMULLW XMM4, XMM11(minus_254)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); - addbyte(0x24); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)&minus_254); + addbyte(0xe3); addbyte(0xf3); /*MOVQ XMM5, XMM4*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xec); addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x24); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x62); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2668,22 +2777,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xc0); break; case AFUNC_ASRC_ALPHA: - addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x66); /*PMULLW XMM0, R10(alookup)[EDX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); addbyte(0x04); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)alookup); + addbyte(0xd2); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xe8); - addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM0, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x42); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2708,12 +2817,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x7e); addbyte(0xe8); - addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x66); /*PADDW XMM0, R10(alookup)[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x42); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2734,22 +2843,22 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo case AFUNC_AONE: break; case AFUNC_AOMSRC_ALPHA: - addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x66); /*PMULLW XMM0, R11(aminuslookup)[EDX*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xd5); addbyte(0x04); - addbyte(0xd5); - addlong((uint32_t)(uintptr_t)aminuslookup); + addbyte(0xd3); addbyte(0xf3); /*MOVQ XMM5, XMM0*/ addbyte(0x0f); addbyte(0x7e); addbyte(0xe8); addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x42); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2766,12 +2875,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(8); break; case AFUNC_AOM_COLOR: - addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0xf3); /*MOVQ XMM5, XMM9(xmm_ff_w)*/ + addbyte(0x41); addbyte(0x0f); addbyte(0x7e); - addbyte(0x2c); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0xe9); addbyte(0x66); /*PSUBW XMM5, XMM6*/ addbyte(0x0f); addbyte(0xf9); @@ -2785,11 +2893,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x7e); addbyte(0xe8); addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x41); addbyte(0x0f); addbyte(0xfd); - addbyte(0x04); - addbyte(0x25); - addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x42); + addbyte(8*2); addbyte(0x66); /*PSRLW XMM5, 8*/ addbyte(0x0f); addbyte(0x71); @@ -2828,8 +2936,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); - addlong(offsetof(voodoo_state_t, x)); - + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x66); /*MOV EAX, XMM0*/ addbyte(0x0f); addbyte(0x7e); @@ -2895,7 +3006,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); - addlong(offsetof(voodoo_state_t, x)); + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x4c); /*ADD RSI, R8*/ addbyte(0x01); addbyte(0xc6); @@ -2981,6 +3095,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x66); /*MOV AX, new_depth*/ addbyte(0x8b); addbyte(0x87); @@ -3240,6 +3360,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x5f); addbyte(0x41); /*POP R14*/ addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); addbyte(0x5b); /*POP RBX*/ addbyte(0x5e); /*POP RSI*/ addbyte(0x5f); /*POP RDI*/ @@ -3247,7 +3371,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xC3); /*RET*/ } -static int voodoo_recomp = 0; +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; @@ -3257,7 +3381,7 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, for (c = 0; c < 8; c++) { - data = &voodoo_x86_data[odd_even + c*2]; //&voodoo_x86_data[odd_even][b]; + data = &voodoo_x86_data[odd_even + c*4]; //&voodoo_x86_data[odd_even][b]; if (state->xdir == data->xdir && params->alphaMode == data->alphaMode && @@ -3268,7 +3392,8 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, params->textureMode[0] == data->textureMode[0] && params->textureMode[1] == data->textureMode[1] && (params->tLOD[0] & LOD_MASK) == data->tLOD[0] && - (params->tLOD[1] & LOD_MASK) == data->tLOD[1]) + (params->tLOD[1] & LOD_MASK) == data->tLOD[1] && + ((params->col_tiled || params->aux_tiled) ? 1 : 0) == data->is_tiled) { last_block[odd_even] = b; return data->code_block; @@ -3277,7 +3402,7 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, b = (b + 1) & 7; } voodoo_recomp++; - data = &voodoo_x86_data[odd_even + next_block_to_write[odd_even]*2]; + data = &voodoo_x86_data[odd_even + next_block_to_write[odd_even]*4]; // code_block = data->code_block; voodoo_generate(data->code_block, voodoo, params, state, depth_op); @@ -3292,36 +3417,21 @@ voodoo_recomp++; data->textureMode[1] = params->textureMode[1]; data->tLOD[0] = params->tLOD[0] & LOD_MASK; data->tLOD[1] = params->tLOD[1] & LOD_MASK; + data->is_tiled = (params->col_tiled || params->aux_tiled) ? 1 : 0; 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) +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); + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM * 4, 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); - } + voodoo->codegen_data = mmap(0, sizeof(voodoo_x86_data_t) * BLOCK_NUM*4, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0); #endif for (c = 0; c < 256; c++) @@ -3346,12 +3456,12 @@ static void voodoo_codegen_init(voodoo_t *voodoo) xmm_00_ff_w[1] = _mm_set_epi32(0, 0, 0xff | (0xff << 16), 0xff | (0xff << 16)); } -static void voodoo_codegen_close(voodoo_t *voodoo) +void voodoo_codegen_close(voodoo_t *voodoo) { #if WIN64 VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); #else - free(voodoo->codegen_data); + munmap(voodoo->codegen_data, sizeof(voodoo_x86_data_t) * BLOCK_NUM*4); #endif } diff --git a/src/vid_voodoo_codegen_x86.h b/src/vid_voodoo_codegen_x86.h index 21ee944..3721f70 100644 --- a/src/vid_voodoo_codegen_x86.h +++ b/src/vid_voodoo_codegen_x86.h @@ -5,7 +5,7 @@ fbzColorPath */ -#ifdef __linux__ +#if defined(__linux__) || defined(__APPLE__) #include #include #endif @@ -34,33 +34,42 @@ typedef struct voodoo_x86_data_t uint32_t textureMode[2]; uint32_t tLOD[2]; uint32_t trexInit1; + int is_tiled; } voodoo_x86_data_t; -static int last_block[2] = {0, 0}; -static int next_block_to_write[2] = {0, 0}; +static int last_block[4] = {0, 0}; +static int next_block_to_write[4] = {0, 0}; -#define addbyte(val) \ - code_block[block_pos++] = val; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addbyte(val) \ + do { \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addword(val) \ - *(uint16_t *)&code_block[block_pos] = val; \ - block_pos += 2; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addword(val) \ + do { \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addlong(val) \ - *(uint32_t *)&code_block[block_pos] = val; \ - block_pos += 4; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addlong(val) \ + do { \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) -#define addquad(val) \ - *(uint64_t *)&code_block[block_pos] = val; \ - block_pos += 8; \ - if (block_pos >= BLOCK_SIZE) \ - fatal("Over!\n") +#define addquad(val) \ + do { \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n"); \ + } while (0) static __m128i xmm_01_w;// = 0x0001000100010001ull; @@ -694,6 +703,28 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x74); addbyte(0x24); addbyte(8+16); + if (params->col_tiled || params->aux_tiled) + { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*AND EAX, 63*/ + addbyte(0xe0); + addbyte(63); + addbyte(0xc1); /*SHR EBX, 6*/ + addbyte(0xeb); + addbyte(6); + addbyte(0xc1); /*SHL EBX, 11 - tile is 128*32, << 12, div 2 because word index*/ + addbyte(0xe3); + addbyte(11); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + addbyte(0x89); /*MOV state->x_tiled[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x_tiled)); + } addbyte(0x66); /*PXOR XMM2, XMM2*/ addbyte(0x0f); addbyte(0xef); @@ -759,10 +790,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo 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 (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) { @@ -826,7 +857,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ addbyte(0x9f); - addlong(offsetof(voodoo_state_t, x)); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x8b);/*MOV ECX, aux_mem[EDI]*/ addbyte(0x8f); addlong(offsetof(voodoo_state_t, aux_mem)); @@ -1030,8 +1064,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(params->detail_scale[1]); addbyte(0x39); /*CMP EAX, EDX*/ addbyte(0xd0); - addbyte(0x0f); /*CMOVA EAX, EDX*/ - addbyte(0x47); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); addbyte(0xc2); addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); @@ -1129,10 +1163,14 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xfd); addbyte(0xc8); } - addbyte(0x66); /*PACKUSWB XMM3, XMM1*/ + addbyte(0xf3); /*MOVD XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + addbyte(0x66); /*PACKUSWB XMM3, XMM3*/ addbyte(0x0f); addbyte(0x67); - addbyte(0xd9); + addbyte(0xdb); if (tca_sub_clocal_1) { addbyte(0x66); /*MOVD EBX, XMM3*/ @@ -1182,8 +1220,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(params->detail_scale[1]); addbyte(0x39); /*CMP EAX, EDX*/ addbyte(0xd0); - addbyte(0x0f); /*CMOVA EAX, EDX*/ - addbyte(0x47); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); addbyte(0xc2); break; case TCA_MSELECT_LOD_FRAC: @@ -1204,7 +1242,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x35); /*XOR EAX, 0xff*/ addlong(0xff); } - addbyte(0x8e); /*ADD EAX, 1*/ + addbyte(0x83); /*ADD EAX, 1*/ addbyte(0xc0); addbyte(1); addbyte(0x0f); /*IMUL EAX, EBX*/ @@ -1352,8 +1390,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(params->detail_scale[0]); addbyte(0x39); /*CMP EAX, EDX*/ addbyte(0xd0); - addbyte(0x0f); /*CMOVA EAX, EDX*/ - addbyte(0x47); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); addbyte(0xc2); addbyte(0x66); /*MOVD XMM4, EAX*/ addbyte(0x0f); @@ -1457,17 +1495,9 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0xff); addbyte(0x66); /*PADDW XMM1, XMM4*/ addbyte(0x0f); - addbyte(0xfc); + addbyte(0xfd); addbyte(0xcc); } - if (tc_invert_output) - { - addbyte(0x66); /*PXOR XMM1, FF*/ - addbyte(0x0f); - addbyte(0xef); - addbyte(0x0d); - addlong((uint32_t)&xmm_ff_w); - } addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ addbyte(0x0f); @@ -1481,6 +1511,14 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x0f); addbyte(0x67); addbyte(0xc9); + if (tc_invert_output) + { + addbyte(0x66); /*PXOR XMM1, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x0d); + addlong((uint32_t)&xmm_ff_b); + } if (tca_zero_other) { @@ -1548,8 +1586,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(params->detail_scale[1]); addbyte(0x39); /*CMP EBX, EDX*/ addbyte(0xd3); - addbyte(0x0f); /*CMOVA EBX, EDX*/ - addbyte(0x47); + addbyte(0x0f); /*CMOVNL EBX, EDX*/ + addbyte(0x4d); addbyte(0xda); break; case TCA_MSELECT_LOD_FRAC: @@ -1630,10 +1668,44 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & FBZ_CHROMAKEY)) { - addbyte(0x66); /*MOVD EAX, XMM0*/ - addbyte(0x0f); - addbyte(0x7e); - addbyte(0xc0); + switch (_rgb_sel) + { + case 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); + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + case CC_LOCALSELECT_COLOR1: + addbyte(0x8b); /*MOV EAX, params->color1[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + break; + case CC_LOCALSELECT_TEX: + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + } addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ addbyte(0x9e); addlong(offsetof(voodoo_params_t, chromaKey)); @@ -1650,22 +1722,15 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if (voodoo->trexInit1[0] & (1 << 18)) { - addbyte(0xb8); /*MOV EAX, 0x000001*/ - if (voodoo->dual_tmus) - { - addlong(0x0000c1); - } - else - { - addlong(0x000001); - } + addbyte(0xb8); /*MOV EAX, tmuConfig*/ + addlong(voodoo->tmuConfig); addbyte(0x66); /*MOVD XMM0, EAX*/ addbyte(0x0f); addbyte(0x6e); addbyte(0xc0); } - if (params->alphaMode & ((1 << 0) | (1 << 4))) + if ((params->alphaMode & ((1 << 0) | (1 << 4))) || (!(cc_mselect == 0 && cc_reverse_blend == 0) && (cc_mselect == CC_MSELECT_AOTHER || cc_mselect == CC_MSELECT_ALOCAL))) { /*EBX = a_other*/ switch (a_sel) @@ -1830,7 +1895,6 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { 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*/ @@ -1840,7 +1904,8 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x6e); addbyte(0x8e); addlong(offsetof(voodoo_params_t, color0)); - /*JMP +*/ + addbyte(0xeb); /*JMP +*/ + addbyte(8+5+4+4); /*!cc_localselect:*/ addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ addbyte(0x0f); @@ -2439,7 +2504,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo { addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ addbyte(0x87); - addlong(offsetof(voodoo_state_t, x)); + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x8b); /*MOV EBP, fb_mem*/ addbyte(0xaf); addlong(offsetof(voodoo_state_t, fb_mem)); @@ -2818,8 +2886,11 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); - addlong(offsetof(voodoo_state_t, x)); - + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x66); /*MOV EAX, XMM0*/ addbyte(0x0f); addbyte(0x7e); @@ -2887,7 +2958,10 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo } addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ addbyte(0x97); - addlong(offsetof(voodoo_state_t, x)); + if (params->col_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); if (dither2x2) { addbyte(0xc1); /*SHL ECX, 2*/ @@ -2971,6 +3045,12 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) { + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + if (params->aux_tiled) + addlong(offsetof(voodoo_state_t, x_tiled)); + else + addlong(offsetof(voodoo_state_t, x)); addbyte(0x66); /*MOV AX, new_depth*/ addbyte(0x8b); addbyte(0x87); @@ -3230,7 +3310,7 @@ static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) cs = cs; } -static int voodoo_recomp = 0; +int voodoo_recomp = 0; static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) { @@ -3241,7 +3321,7 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, for (c = 0; c < 8; c++) { - data = &codegen_data[odd_even + b*2]; + data = &codegen_data[odd_even + b*4]; if (state->xdir == data->xdir && params->alphaMode == data->alphaMode && @@ -3252,7 +3332,8 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, params->textureMode[0] == data->textureMode[0] && params->textureMode[1] == data->textureMode[1] && (params->tLOD[0] & LOD_MASK) == data->tLOD[0] && - (params->tLOD[1] & LOD_MASK) == data->tLOD[1]) + (params->tLOD[1] & LOD_MASK) == data->tLOD[1] && + ((params->col_tiled || params->aux_tiled) ? 1 : 0) == data->is_tiled) { last_block[odd_even] = b; return data->code_block; @@ -3261,7 +3342,7 @@ static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, b = (b + 1) & 7; } voodoo_recomp++; - data = &codegen_data[odd_even + next_block_to_write[odd_even]*2]; + data = &codegen_data[odd_even + next_block_to_write[odd_even]*4]; // code_block = data->code_block; voodoo_generate(data->code_block, voodoo, params, state, depth_op); @@ -3276,16 +3357,17 @@ voodoo_recomp++; data->textureMode[1] = params->textureMode[1]; data->tLOD[0] = params->tLOD[0] & LOD_MASK; data->tLOD[1] = params->tLOD[1] & LOD_MASK; + data->is_tiled = (params->col_tiled || params->aux_tiled) ? 1 : 0; 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) +void voodoo_codegen_init(voodoo_t *voodoo) { int c; -#ifdef __linux__ +#if defined(__linux__) || defined(__APPLE__) void *start; size_t len; long pagesize = sysconf(_SC_PAGESIZE); @@ -3293,19 +3375,9 @@ static void voodoo_codegen_init(voodoo_t *voodoo) #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); + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM*4, 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); - } + voodoo->codegen_data = mmap(0, sizeof(voodoo_x86_data_t) * BLOCK_NUM*4, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANON|MAP_PRIVATE, 0, 0); #endif for (c = 0; c < 256; c++) @@ -3330,11 +3402,11 @@ static void voodoo_codegen_init(voodoo_t *voodoo) xmm_00_ff_w[1] = _mm_set_epi32(0, 0, 0xff | (0xff << 16), 0xff | (0xff << 16)); } -static void voodoo_codegen_close(voodoo_t *voodoo) +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); + munmap(voodoo->codegen_data, sizeof(voodoo_x86_data_t) * BLOCK_NUM*4); #endif } diff --git a/src/vid_voodoo_common.h b/src/vid_voodoo_common.h new file mode 100644 index 0000000..bfd0f7f --- /dev/null +++ b/src/vid_voodoo_common.h @@ -0,0 +1,512 @@ +#ifdef MIN +#undef MIN +#endif +#ifdef CLAMP +#undef CLAMP +#endif + +#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 + +#define TEX_DIRTY_SHIFT 10 + +#define TEX_CACHE_MAX 64 + +enum +{ + VOODOO_1 = 0, + VOODOO_SB50, + VOODOO_2, + VOODOO_BANSHEE, + VOODOO_3 +}; + +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-4) +#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), + FIFO_WRITEL_2DREG = (0x05 << 24) +}; + +#define PARAM_SIZE 1024 +#define PARAM_MASK (PARAM_SIZE - 1) +#define PARAM_ENTRY_SIZE (1 << 31) + +#define PARAM_ENTRIES(x) (voodoo->params_write_idx - voodoo->params_read_idx[x]) +#define PARAM_FULL(x) ((voodoo->params_write_idx - voodoo->params_read_idx[x]) >= PARAM_SIZE) +#define PARAM_EMPTY(x) (voodoo->params_read_idx[x] == voodoo->params_write_idx) + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +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[2]; + + 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[2]; + uint32_t tLOD[2]; + + uint32_t texBaseAddr[2], texBaseAddr1[2], texBaseAddr2[2], texBaseAddr38[2]; + + uint32_t tex_base[2][LOD_MAX+2]; + uint32_t tex_end[2][LOD_MAX+2]; + int tex_width[2]; + int tex_w_mask[2][LOD_MAX+2]; + int tex_w_nmask[2][LOD_MAX+2]; + int tex_h_mask[2][LOD_MAX+2]; + int tex_shift[2][LOD_MAX+2]; + int tex_lod[2][LOD_MAX+2]; + int tex_entry[2]; + int detail_max[2], detail_bias[2], detail_scale[2]; + + uint32_t draw_offset, aux_offset; + + int tformat[2]; + + int clipLeft, clipRight, clipLowY, clipHighY; + int clipLeft1, clipRight1, clipLowY1, clipHighY1; + + int sign; + + uint32_t front_offset; + + uint32_t swapbufferCMD; + + uint32_t stipple; + + int col_tiled, aux_tiled; + int row_width, aux_row_width; +} voodoo_params_t; + +typedef struct texture_t +{ + uint32_t base; + uint32_t tLOD; + volatile int refcount, refcount_r[4]; + int is16; + uint32_t palette_checksum; + uint32_t addr_start[4], addr_end[4]; + uint32_t *data; +} texture_t; + +typedef struct vert_t +{ + float sVx, sVy; + float sRed, sGreen, sBlue, sAlpha; + float sVz, sWb; + float sW0, sS0, sT0; + float sW1, sS1, sT1; +} vert_t; + +typedef struct clip_t +{ + int x_min, x_max; + int y_min, y_max; +} clip_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; + uint64_t line_time; + + voodoo_params_t params; + + uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4; + uint32_t fbiInit5, fbiInit6, fbiInit7; /*Voodoo 2*/ + + uint32_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, aux_row_width; + int block_width; + + int col_tiled, aux_tiled; + + uint8_t *fb_mem, *tex_mem[2]; + uint16_t *tex_mem_w[2]; + + int rgb_sel; + + uint32_t trexInit1[2]; + + uint32_t tmuConfig; + + mutex_t *swap_mutex; + int swap_count; + + int disp_buffer, draw_buffer; + pc_timer_t timer; + + int line; + svga_t *svga; + + uint32_t backPorch; + uint32_t videoDimensions; + uint32_t hSync, vSync; + + int h_total, v_total, v_disp; + int h_disp; + int v_retrace; + + struct + { + uint32_t y[4], i[4], q[4]; + } nccTable[2][2]; + + rgba_u palette[2][256]; + + rgba_u ncc_lookup[2][2][256]; + int ncc_dirty[2]; + + thread_t *fifo_thread; + thread_t *render_thread[4]; + event_t *wake_fifo_thread; + event_t *wake_main_thread; + event_t *fifo_not_full_event; + event_t *render_not_full_event[4]; + event_t *wake_render_thread[4]; + + int voodoo_busy; + int render_voodoo_busy[4]; + + int render_threads; + int odd_even_mask; + + int pixel_count[4], texel_count[4], tri_count, frame_count; + int pixel_count_old[4], texel_count_old[4]; + int wr_count, rd_count, tex_count; + + int retrace_count; + int swap_interval; + uint32_t swap_offset; + int swap_pending; + + int bilinear_enabled; + int dithersub_enabled; + + int fb_size; + uint32_t fb_mask; + + int texture_size; + uint32_t texture_mask; + + int dual_tmus; + int type; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + volatile int cmd_read, cmd_written, cmd_written_fifo; + + voodoo_params_t params_buffer[PARAM_SIZE]; + volatile int params_read_idx[4], params_write_idx; + + uint32_t cmdfifo_base, cmdfifo_end, cmdfifo_size; + int cmdfifo_rp, cmdfifo_ret_addr; + int cmdfifo_in_sub; + volatile int cmdfifo_depth_rd, cmdfifo_depth_wr; + volatile int cmdfifo_enabled; + uint32_t cmdfifo_amin, cmdfifo_amax; + int cmdfifo_holecount; + + uint32_t sSetupMode; + vert_t verts[4]; + unsigned int vertex_ages[3]; + unsigned int vertex_next_age; + int num_verticies; + int cull_pingpong; + + int flush; + + int scrfilter; + int scrfilterEnabled; + int scrfilterThreshold; + int scrfilterThresholdOld; + + uint32_t last_write_addr; + + uint32_t fbiPixelsIn; + uint32_t fbiChromaFail; + uint32_t fbiZFuncFail; + uint32_t fbiAFuncFail; + uint32_t fbiPixelsOut; + + uint32_t bltSrcBaseAddr; + uint32_t bltDstBaseAddr; + int bltSrcXYStride, bltDstXYStride; + uint32_t bltSrcChromaRange, bltDstChromaRange; + int bltSrcChromaMinR, bltSrcChromaMinG, bltSrcChromaMinB; + int bltSrcChromaMaxR, bltSrcChromaMaxG, bltSrcChromaMaxB; + int bltDstChromaMinR, bltDstChromaMinG, bltDstChromaMinB; + int bltDstChromaMaxR, bltDstChromaMaxG, bltDstChromaMaxB; + + int bltClipRight, bltClipLeft; + int bltClipHighY, bltClipLowY; + + int bltSrcX, bltSrcY; + int bltDstX, bltDstY; + int bltSizeX, bltSizeY; + int bltRop[4]; + uint16_t bltColorFg, bltColorBg; + + uint32_t bltCommand; + + uint32_t leftOverlayBuf; + + struct + { + int dst_x, dst_y; + int cur_x; + int size_x, size_y; + int x_dir, y_dir; + int dst_stride; + } blt; + + struct + { + uint32_t bresError0, bresError1; + uint32_t clip0Min, clip0Max; + uint32_t clip1Min, clip1Max; + uint32_t colorBack, colorFore; + uint32_t command, commandExtra; + uint32_t dstBaseAddr; + uint32_t dstFormat; + uint32_t dstSize; + uint32_t dstXY; + uint32_t lineStipple; + uint32_t lineStyle; + uint32_t rop; + uint32_t srcBaseAddr; + uint32_t srcFormat; + uint32_t srcSize; + uint32_t srcXY; + + uint32_t colorPattern[64]; + + int bres_error_0, bres_error_1; + uint32_t colorPattern8[64], colorPattern16[64], colorPattern24[64]; + int cur_x, cur_y; + uint32_t dstBaseAddr_tiled; + uint32_t dstColorkeyMin, dstColorkeyMax; + int dstSizeX, dstSizeY; + int dstX, dstY; + int dst_stride; + int patoff_x, patoff_y; + uint8_t rops[4]; + uint32_t srcBaseAddr_tiled; + uint32_t srcColorkeyMin, srcColorkeyMax; + int srcSizeX, srcSizeY; + int srcX, srcY; + int src_stride; + int old_srcX; + + /*Used for handling packed 24bpp host data*/ + int host_data_remainder; + uint32_t old_host_data; + + /*Polyfill coordinates*/ + int lx[2], rx[2]; + int ly[2], ry[2]; + + /*Polyfill state*/ + int error[2]; + int dx[2], dy[2]; + int x_inc[2]; /*y_inc is always 1 for polyfill*/ + int lx_cur, rx_cur; + + clip_t clip[2]; + + uint8_t host_data[16384]; + int host_data_count; + int host_data_size_src, host_data_size_dest; + int src_stride_src, src_stride_dest; + + int src_bpp; + + int line_pix_pos, line_bit_pos; + int line_rep_cnt, line_bit_mask_size; + } banshee_blt; + + struct + { + uint32_t vidOverlayStartCoords; + uint32_t vidOverlayEndScreenCoords; + uint32_t vidOverlayDudx, vidOverlayDudxOffsetSrcWidth; + uint32_t vidOverlayDvdy, vidOverlayDvdyOffset; + //uint32_t vidDesktopOverlayStride; + + int start_x, start_y; + int end_x, end_y; + int size_x, size_y; + int overlay_bytes; + + unsigned int src_y; + } overlay; + + rgb_t clutData[33]; + int clutData_dirty; + rgb_t clutData256[256]; + uint32_t video_16to32[0x10000]; + + uint8_t dirty_line[2048]; + int dirty_line_low, dirty_line_high; + + int fb_write_buffer, fb_draw_buffer; + int buffer_cutoff; + + uint32_t tile_base, tile_stride; + int tile_stride_shift, tile_x, tile_x_real; + + int y_origin_swap; + + int read_time, write_time, burst_time; + + pc_timer_t wake_timer; + + /* screen filter tables */ + uint8_t thefilter[256][256]; + uint8_t thefilterg[256][256]; + uint8_t thefilterb[256][256]; + uint16_t purpleline[256][3]; + + texture_t texture_cache[2][TEX_CACHE_MAX]; + uint8_t texture_present[2][16384]; + int texture_last_removed; + + uint32_t palette_checksum[2]; + int palette_dirty[2]; + + uint64_t time; + int render_time[4]; + + int use_recompiler; + void *codegen_data; + + struct voodoo_set_t *set; + + + uint8_t *vram, *changedvram; + + void *p; +} voodoo_t; + +typedef struct voodoo_set_t +{ + voodoo_t *voodoos[2]; + + mem_mapping_t snoop_mapping; + + int nr_cards; +} voodoo_set_t; + + +extern rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; + + +void voodoo_generate_vb_filters(voodoo_t *voodoo, int fcr, int fcg); + +void voodoo_recalc(voodoo_t *voodoo); +void voodoo_update_ncc(voodoo_t *voodoo, int tmu); + +void *voodoo_2d3d_card_init(int type); +void voodoo_card_close(voodoo_t *voodoo); diff --git a/src/vid_voodoo_display.c b/src/vid_voodoo_display.c new file mode 100644 index 0000000..9ce92dd --- /dev/null +++ b/src/vid_voodoo_display.c @@ -0,0 +1,609 @@ +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_display.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" + +void voodoo_update_ncc(voodoo_t *voodoo, int tmu) +{ + 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 i_r, i_g, i_b; + int q_r, q_g, q_b; + + y = (voodoo->nccTable[tmu][tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; + + i_r = (voodoo->nccTable[tmu][tbl].i[i] >> 18) & 0x1ff; + if (i_r & 0x100) + i_r |= 0xfffffe00; + i_g = (voodoo->nccTable[tmu][tbl].i[i] >> 9) & 0x1ff; + if (i_g & 0x100) + i_g |= 0xfffffe00; + i_b = voodoo->nccTable[tmu][tbl].i[i] & 0x1ff; + if (i_b & 0x100) + i_b |= 0xfffffe00; + + q_r = (voodoo->nccTable[tmu][tbl].q[q] >> 18) & 0x1ff; + if (q_r & 0x100) + q_r |= 0xfffffe00; + q_g = (voodoo->nccTable[tmu][tbl].q[q] >> 9) & 0x1ff; + if (q_g & 0x100) + q_g |= 0xfffffe00; + q_b = voodoo->nccTable[tmu][tbl].q[q] & 0x1ff; + if (q_b & 0x100) + q_b |= 0xfffffe00; + + voodoo->ncc_lookup[tmu][tbl][col].rgba.r = CLAMP(y + i_r + q_r); + voodoo->ncc_lookup[tmu][tbl][col].rgba.g = CLAMP(y + i_g + q_g); + voodoo->ncc_lookup[tmu][tbl][col].rgba.b = CLAMP(y + i_b + q_b); + voodoo->ncc_lookup[tmu][tbl][col].rgba.a = 0xff; + } + } +} + +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 = (uint64_t)((double)line_length * clock_const * (double)(1ull << 32)); +} + +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 FILTDIV 256 + +static int FILTCAP, FILTCAPG, FILTCAPB = 0; /* color filter threshold values */ + +void voodoo_generate_filter_v1(voodoo_t *voodoo) +{ + int g, h; + float difference, diffg, diffb; + float thiscol, thiscolg, thiscolb, lined; + float fcr, fcg, fcb; + + fcr = FILTCAP * 5; + fcg = FILTCAPG * 6; + fcb = FILTCAPB * 5; + + for (g=0;g FILTCAP) + difference = FILTCAP; + if (difference < -FILTCAP) + difference = -FILTCAP; + + if (diffg > FILTCAPG) + diffg = FILTCAPG; + if (diffg < -FILTCAPG) + diffg = -FILTCAPG; + + if (diffb > FILTCAPB) + diffb = FILTCAPB; + if (diffb < -FILTCAPB) + diffb = -FILTCAPB; + + // hack - to make it not bleed onto black + //if (g == 0){ + //difference = diffg = diffb = 0; + //} + + if ((difference < fcr) || (-difference > -fcr)) + thiscol = g + (difference / 2); + if ((diffg < fcg) || (-diffg > -fcg)) + thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ + if ((diffb < fcb) || (-diffb > -fcb)) + thiscolb = g + (diffb / 2); + + if (thiscol < 0) + thiscol = 0; + if (thiscol > FILTDIV-1) + thiscol = FILTDIV-1; + + if (thiscolg < 0) + thiscolg = 0; + if (thiscolg > FILTDIV-1) + thiscolg = FILTDIV-1; + + if (thiscolb < 0) + thiscolb = 0; + if (thiscolb > FILTDIV-1) + thiscolb = FILTDIV-1; + + voodoo->thefilter[g][h] = thiscol; + voodoo->thefilterg[g][h] = thiscolg; + voodoo->thefilterb[g][h] = thiscolb; + } + + lined = g + 4; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][2] = lined; + + lined = g + 0; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][1] = lined; + } +} + +void voodoo_generate_filter_v2(voodoo_t *voodoo) +{ + int g, h; + float difference; + float thiscol, thiscolg, thiscolb; + float clr, clg, clb = 0; + float fcr, fcg, fcb = 0; + + // pre-clamping + + fcr = FILTCAP; + fcg = FILTCAPG; + fcb = FILTCAPB; + + if (fcr > 32) fcr = 32; + if (fcg > 32) fcg = 32; + if (fcb > 32) fcb = 32; + + for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into + { + for (h=0;h<256;h++) // pixel 2 - our main pixel + { + float avg; + float avgdiff; + + difference = (float)(g - h); + avg = (float)((g + g + g + g + h) / 5); + avgdiff = avg - (float)((g + h + h + h + h) / 5); + if (avgdiff < 0) avgdiff *= -1; + if (difference < 0) difference *= -1; + + thiscol = thiscolg = thiscolb = g; + + // try lighten + if (h > g) + { + clr = clg = clb = avgdiff; + + if (clr>fcr) clr=fcr; + if (clg>fcg) clg=fcg; + if (clb>fcb) clb=fcb; + + + thiscol = g + clr; + thiscolg = g + clg; + thiscolb = g + clb; + + if (thiscol>g+FILTCAP) + thiscol=g+FILTCAP; + if (thiscolg>g+FILTCAPG) + thiscolg=g+FILTCAPG; + if (thiscolb>g+FILTCAPB) + thiscolb=g+FILTCAPB; + + + if (thiscol>g+avgdiff) + thiscol=g+avgdiff; + if (thiscolg>g+avgdiff) + thiscolg=g+avgdiff; + if (thiscolb>g+avgdiff) + thiscolb=g+avgdiff; + + } + + if (difference > FILTCAP) + thiscol = g; + if (difference > FILTCAPG) + thiscolg = g; + if (difference > FILTCAPB) + thiscolb = g; + + // clamp + if (thiscol < 0) thiscol = 0; + if (thiscolg < 0) thiscolg = 0; + if (thiscolb < 0) thiscolb = 0; + + if (thiscol > 255) thiscol = 255; + if (thiscolg > 255) thiscolg = 255; + if (thiscolb > 255) thiscolb = 255; + + // add to the table + voodoo->thefilter[g][h] = (thiscol); + voodoo->thefilterg[g][h] = (thiscolg); + voodoo->thefilterb[g][h] = (thiscolb); + + // debug the ones that don't give us much of a difference + //if (difference < FILTCAP) + //pclog("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb); + } + + } +} + +void voodoo_threshold_check(voodoo_t *voodoo) +{ + int r, g, b; + + if (!voodoo->scrfilterEnabled) + return; /* considered disabled; don't check and generate */ + + /* Check for changes, to generate anew table */ + if (voodoo->scrfilterThreshold != voodoo->scrfilterThresholdOld) + { + r = (voodoo->scrfilterThreshold >> 16) & 0xFF; + g = (voodoo->scrfilterThreshold >> 8 ) & 0xFF; + b = voodoo->scrfilterThreshold & 0xFF; + + FILTCAP = r; + FILTCAPG = g; + FILTCAPB = b; + + pclog("Voodoo Filter Threshold Check: %06x - RED %i GREEN %i BLUE %i\n", voodoo->scrfilterThreshold, r, g, b); + + voodoo->scrfilterThresholdOld = voodoo->scrfilterThreshold; + + if (voodoo->type == VOODOO_2) + voodoo_generate_filter_v2(voodoo); + else + voodoo_generate_filter_v1(voodoo); + + if (voodoo->type >= VOODOO_BANSHEE) + voodoo_generate_vb_filters(voodoo, FILTCAP, FILTCAPG); + } +} + +static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for avoiding feedback streaks + uint8_t fil3[(voodoo->h_disp) * 3]; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + + // Copy to our scratchpads + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; + } + + + /* lines */ + + if (line & 1) + { + for (x=0; xpurpleline[fil[x*3]][0]; + fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1]; + fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2]; + } + } + + + /* filtering time */ + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil3[x*3]][fil3[ (x-1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x-1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=0; xthefilterb[fil3[x*3]][fil3[ (x+1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x+1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x+1) *3+2]]; + } +} + + +static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for blending filter + uint8_t fil3[(voodoo->h_disp) * 3]; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil3[x*3+2] = fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + } + + /* filtering time */ + + for (x=1; xthefilterb [((src[x+3] & 31) << 3)] [((src[x] & 31) << 3)]; + fil3[(x+3)*3+1] = voodoo->thefilterg [(((src[x+3] >> 5) & 63) << 2)] [(((src[x] >> 5) & 63) << 2)]; + fil3[(x+3)*3+2] = voodoo->thefilter [(((src[x+3] >> 11) & 31) << 3)] [(((src[x] >> 11) & 31) << 3)]; + + fil[(x+2)*3] = voodoo->thefilterb [fil3[(x+2)*3]][((src[x] & 31) << 3)]; + fil[(x+2)*3+1] = voodoo->thefilterg [fil3[(x+2)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x+2)*3+2] = voodoo->thefilter [fil3[(x+2)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil3[(x+1)*3] = voodoo->thefilterb [fil[(x+1)*3]][((src[x] & 31) << 3)]; + fil3[(x+1)*3+1] = voodoo->thefilterg [fil[(x+1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil3[(x+1)*3+2] = voodoo->thefilter [fil[(x+1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil[(x-1)*3] = voodoo->thefilterb [fil3[(x-1)*3]][((src[x] & 31) << 3)]; + fil[(x-1)*3+1] = voodoo->thefilterg [fil3[(x-1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x-1)*3+2] = voodoo->thefilter [fil3[(x-1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + } + + // unroll for edge cases + + fil3[(column-3)*3] = voodoo->thefilterb [((src[column-3] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-3)*3+1] = voodoo->thefilterg [(((src[column-3] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-3)*3+2] = voodoo->thefilter [(((src[column-3] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-2)*3] = voodoo->thefilterb [((src[column-2] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-2)*3+1] = voodoo->thefilterg [(((src[column-2] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-2)*3+2] = voodoo->thefilter [(((src[column-2] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [((src[column-1] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [(((src[column-1] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [(((src[column-1] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil[(column-2)*3] = voodoo->thefilterb [fil3[(column-2)*3]][((src[column] & 31) << 3)]; + fil[(column-2)*3+1] = voodoo->thefilterg [fil3[(column-2)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-2)*3+2] = voodoo->thefilter [fil3[(column-2)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil[(column-1)*3] = voodoo->thefilterb [fil3[(column-1)*3]][((src[column] & 31) << 3)]; + fil[(column-1)*3+1] = voodoo->thefilterg [fil3[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-1)*3+2] = voodoo->thefilter [fil3[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [fil[(column-1)*3]][((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [fil[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [fil[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; +} + +void voodoo_callback(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line < voodoo->v_disp) + { + voodoo_t *draw_voodoo; + int draw_line; + + if (SLI_ENABLED) + { + if (voodoo == voodoo->set->voodoos[1]) + goto skip_draw; + + if (((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) ? 1 : 0) == (voodoo->line & 1)) + draw_voodoo = voodoo; + else + draw_voodoo = voodoo->set->voodoos[1]; + draw_line = voodoo->line >> 1; + } + else + { + if (!(voodoo->fbiInit0 & 1)) + goto skip_draw; + draw_voodoo = voodoo; + draw_line = voodoo->line; + } + + if (draw_voodoo->dirty_line[draw_line]) + { + uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line])[32]; + uint16_t *src = (uint16_t *)&draw_voodoo->fb_mem[draw_voodoo->front_offset + draw_line*draw_voodoo->row_width]; + int x; + + draw_voodoo->dirty_line[draw_line] = 0; + + if (voodoo->line < voodoo->dirty_line_low) + { + voodoo->dirty_line_low = voodoo->line; + video_wait_for_buffer(); + } + if (voodoo->line > voodoo->dirty_line_high) + voodoo->dirty_line_high = voodoo->line; + + if (voodoo->scrfilter && voodoo->scrfilterEnabled) + { + uint8_t fil[(voodoo->h_disp) * 3]; /* interleaved 24-bit RGB */ + + if (voodoo->type == VOODOO_2) + voodoo_filterline_v2(voodoo, fil, voodoo->h_disp, src, voodoo->line); + else + voodoo_filterline_v1(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] = draw_voodoo->video_16to32[src[x]]; + } + } + } + } + } +skip_draw: + 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 (SLI_ENABLED && (voodoo->fbiInit2 & FBIINIT2_SWAP_ALGORITHM_MASK) == FBIINIT2_SWAP_ALGORITHM_SLI_SYNC) + { + if (voodoo == voodoo->set->voodoos[0]) + { + voodoo_t *voodoo_1 = voodoo->set->voodoos[1]; + + thread_lock_mutex(voodoo->swap_mutex); + /*Only swap if both Voodoos are waiting for buffer swap*/ + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval) && + voodoo_1->swap_pending && (voodoo_1->retrace_count > voodoo_1->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + voodoo->front_offset = voodoo->swap_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + + memset(voodoo_1->dirty_line, 1, 1024); + voodoo_1->retrace_count = 0; + voodoo_1->front_offset = voodoo_1->swap_offset; + if (voodoo_1->swap_count > 0) + voodoo_1->swap_count--; + voodoo_1->swap_pending = 0; + thread_unlock_mutex(voodoo->swap_mutex); + + thread_set_event(voodoo->wake_fifo_thread); + thread_set_event(voodoo_1->wake_fifo_thread); + + voodoo->frame_count++; + voodoo_1->frame_count++; + } + else + thread_unlock_mutex(voodoo->swap_mutex); + } + } + else + { + thread_lock_mutex(voodoo->swap_mutex); + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + voodoo->front_offset = voodoo->swap_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_unlock_mutex(voodoo->swap_mutex); + + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + else + thread_unlock_mutex(voodoo->swap_mutex); + } + 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-1, 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) + timer_advance_u64(&voodoo->timer, voodoo->line_time); + else + timer_advance_u64(&voodoo->timer, TIMER_USEC * 32); +} diff --git a/src/vid_voodoo_display.h b/src/vid_voodoo_display.h new file mode 100644 index 0000000..46cbc00 --- /dev/null +++ b/src/vid_voodoo_display.h @@ -0,0 +1,6 @@ +void voodoo_update_ncc(voodoo_t *voodoo, int tmu); +void voodoo_pixelclock_update(voodoo_t *voodoo); +void voodoo_generate_filter_v1(voodoo_t *voodoo); +void voodoo_generate_filter_v2(voodoo_t *voodoo); +void voodoo_threshold_check(voodoo_t *voodoo); +void voodoo_callback(void *p); diff --git a/src/vid_voodoo_dither.h b/src/vid_voodoo_dither.h index 7ec7471..c1109c9 100644 --- a/src/vid_voodoo_dither.h +++ b/src/vid_voodoo_dither.h @@ -1,4 +1,4 @@ -uint8_t dither_rb[256][4][4] = +static const uint8_t dither_rb[256][4][4] = { { {0, 0, 0, 0}, @@ -1538,7 +1538,7 @@ uint8_t dither_rb[256][4][4] = }, }; -uint8_t dither_g[256][4][4] = +static const uint8_t dither_g[256][4][4] = { { {0, 0, 0, 0}, @@ -3078,7 +3078,7 @@ uint8_t dither_g[256][4][4] = }, }; -uint8_t dither_rb2x2[256][2][2] = +static const uint8_t dither_rb2x2[256][2][2] = { { {0, 0}, @@ -4106,7 +4106,7 @@ uint8_t dither_rb2x2[256][2][2] = }, }; -uint8_t dither_g2x2[256][2][2] = +static const uint8_t dither_g2x2[256][2][2] = { { {0, 0}, @@ -5134,3 +5134,5147 @@ uint8_t dither_g2x2[256][2][2] = }, }; + + +/* Dither subtraction */ + +static const uint8_t dithersub_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, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {9, 5, 8, 4}, + {3, 7, 2, 6}, + {7, 3, 8, 4}, + {1, 5, 2, 6}, + }, + { + {10, 6, 9, 5}, + {4, 8, 3, 7}, + {8, 4, 9, 5}, + {2, 6, 3, 7}, + }, + { + {11, 7, 10, 6}, + {5, 9, 4, 8}, + {9, 5, 10, 6}, + {3, 7, 4, 8}, + }, + { + {12, 8, 11, 7}, + {6, 10, 5, 9}, + {10, 6, 11, 7}, + {4, 8, 5, 9}, + }, + { + {13, 9, 12, 8}, + {7, 11, 6, 10}, + {11, 7, 12, 8}, + {5, 9, 6, 10}, + }, + { + {14, 10, 13, 9}, + {8, 12, 7, 11}, + {12, 8, 13, 9}, + {6, 10, 7, 11}, + }, + { + {15, 11, 14, 10}, + {9, 13, 8, 12}, + {13, 9, 14, 10}, + {7, 11, 8, 12}, + }, + { + {16, 12, 15, 11}, + {10, 14, 9, 13}, + {14, 10, 15, 11}, + {8, 12, 9, 13}, + }, + { + {17, 13, 16, 12}, + {11, 15, 10, 14}, + {15, 11, 16, 12}, + {9, 13, 10, 14}, + }, + { + {18, 14, 17, 13}, + {12, 16, 11, 15}, + {16, 12, 17, 13}, + {10, 14, 11, 15}, + }, + { + {19, 15, 18, 14}, + {13, 17, 12, 16}, + {17, 13, 18, 14}, + {11, 15, 12, 16}, + }, + { + {20, 16, 19, 15}, + {14, 18, 13, 17}, + {18, 14, 19, 15}, + {12, 16, 13, 17}, + }, + { + {21, 17, 20, 16}, + {15, 19, 14, 18}, + {19, 15, 20, 16}, + {13, 17, 14, 18}, + }, + { + {22, 18, 21, 17}, + {16, 20, 15, 19}, + {20, 16, 21, 17}, + {14, 18, 15, 19}, + }, + { + {23, 19, 22, 18}, + {17, 21, 16, 20}, + {21, 17, 22, 18}, + {15, 19, 16, 20}, + }, + { + {24, 20, 23, 19}, + {18, 22, 17, 21}, + {22, 18, 23, 19}, + {16, 20, 17, 21}, + }, + { + {25, 21, 24, 20}, + {19, 23, 18, 22}, + {23, 19, 24, 20}, + {17, 21, 18, 22}, + }, + { + {26, 22, 25, 21}, + {20, 24, 19, 23}, + {24, 20, 25, 21}, + {18, 22, 19, 23}, + }, + { + {27, 23, 26, 22}, + {21, 25, 20, 24}, + {25, 21, 26, 22}, + {19, 23, 20, 24}, + }, + { + {28, 24, 27, 23}, + {22, 26, 21, 25}, + {26, 22, 27, 23}, + {20, 24, 21, 25}, + }, + { + {29, 25, 28, 24}, + {23, 27, 22, 26}, + {27, 23, 28, 24}, + {21, 25, 22, 26}, + }, + { + {30, 26, 29, 25}, + {24, 28, 23, 27}, + {28, 24, 29, 25}, + {22, 26, 23, 27}, + }, + { + {31, 27, 30, 26}, + {25, 29, 24, 28}, + {29, 25, 30, 26}, + {23, 27, 24, 28}, + }, + { + {32, 28, 31, 27}, + {26, 30, 25, 29}, + {30, 26, 31, 27}, + {24, 28, 25, 29}, + }, + { + {33, 29, 32, 28}, + {27, 31, 26, 30}, + {31, 27, 32, 28}, + {25, 29, 26, 30}, + }, + { + {34, 30, 33, 29}, + {28, 32, 27, 31}, + {32, 28, 33, 29}, + {26, 30, 27, 31}, + }, + { + {35, 31, 34, 30}, + {29, 33, 28, 32}, + {33, 29, 34, 30}, + {27, 31, 28, 32}, + }, + { + {36, 32, 35, 31}, + {30, 34, 29, 33}, + {34, 30, 35, 31}, + {28, 32, 29, 33}, + }, + { + {37, 33, 36, 32}, + {31, 35, 30, 34}, + {35, 31, 36, 32}, + {29, 33, 30, 34}, + }, + { + {38, 34, 37, 33}, + {32, 36, 31, 35}, + {36, 32, 37, 33}, + {30, 34, 31, 35}, + }, + { + {39, 35, 38, 34}, + {33, 37, 32, 36}, + {37, 33, 38, 34}, + {31, 35, 32, 36}, + }, + { + {40, 36, 39, 35}, + {34, 38, 33, 37}, + {38, 34, 39, 35}, + {32, 36, 33, 37}, + }, + { + {41, 37, 40, 36}, + {35, 39, 34, 38}, + {39, 35, 40, 36}, + {33, 37, 34, 38}, + }, + { + {42, 38, 41, 37}, + {36, 40, 35, 39}, + {40, 36, 41, 37}, + {34, 38, 35, 39}, + }, + { + {43, 39, 42, 38}, + {37, 41, 36, 40}, + {41, 37, 42, 38}, + {35, 39, 36, 40}, + }, + { + {44, 40, 43, 39}, + {38, 42, 37, 41}, + {42, 38, 43, 39}, + {36, 40, 37, 41}, + }, + { + {45, 41, 44, 40}, + {39, 43, 38, 42}, + {43, 39, 44, 40}, + {37, 41, 38, 42}, + }, + { + {46, 42, 45, 41}, + {40, 44, 39, 43}, + {44, 40, 45, 41}, + {38, 42, 39, 43}, + }, + { + {47, 43, 46, 42}, + {41, 45, 40, 44}, + {45, 41, 46, 42}, + {39, 43, 40, 44}, + }, + { + {48, 44, 47, 43}, + {42, 46, 41, 45}, + {46, 42, 47, 43}, + {40, 44, 41, 45}, + }, + { + {49, 45, 48, 44}, + {43, 47, 42, 46}, + {47, 43, 48, 44}, + {41, 45, 42, 46}, + }, + { + {50, 46, 49, 45}, + {44, 48, 43, 47}, + {48, 44, 49, 45}, + {42, 46, 43, 47}, + }, + { + {51, 47, 50, 46}, + {45, 49, 44, 48}, + {49, 45, 50, 46}, + {43, 47, 44, 48}, + }, + { + {52, 48, 51, 47}, + {46, 50, 45, 49}, + {50, 46, 51, 47}, + {44, 48, 45, 49}, + }, + { + {53, 49, 52, 48}, + {47, 51, 46, 50}, + {51, 47, 52, 48}, + {45, 49, 46, 50}, + }, + { + {54, 50, 53, 49}, + {48, 52, 47, 51}, + {52, 48, 53, 49}, + {46, 50, 47, 51}, + }, + { + {55, 51, 54, 50}, + {49, 53, 48, 52}, + {53, 49, 54, 50}, + {47, 51, 48, 52}, + }, + { + {56, 52, 55, 51}, + {50, 54, 49, 53}, + {54, 50, 55, 51}, + {48, 52, 49, 53}, + }, + { + {57, 53, 56, 52}, + {51, 55, 50, 54}, + {55, 51, 56, 52}, + {49, 53, 50, 54}, + }, + { + {58, 54, 57, 53}, + {52, 56, 51, 55}, + {56, 52, 57, 53}, + {50, 54, 51, 55}, + }, + { + {59, 55, 58, 54}, + {53, 57, 52, 56}, + {57, 53, 58, 54}, + {51, 55, 52, 56}, + }, + { + {60, 56, 59, 55}, + {54, 58, 53, 57}, + {58, 54, 59, 55}, + {52, 56, 53, 57}, + }, + { + {61, 57, 60, 56}, + {55, 59, 54, 58}, + {59, 55, 60, 56}, + {53, 57, 54, 58}, + }, + { + {62, 58, 61, 57}, + {56, 60, 55, 59}, + {60, 56, 61, 57}, + {54, 58, 55, 59}, + }, + { + {63, 59, 62, 58}, + {57, 61, 56, 60}, + {61, 57, 62, 58}, + {55, 59, 56, 60}, + }, + { + {64, 60, 63, 59}, + {58, 62, 57, 61}, + {62, 58, 63, 59}, + {56, 60, 57, 61}, + }, + { + {65, 61, 64, 60}, + {59, 63, 58, 62}, + {63, 59, 64, 60}, + {57, 61, 58, 62}, + }, + { + {66, 62, 65, 61}, + {60, 64, 59, 63}, + {64, 60, 65, 61}, + {58, 62, 59, 63}, + }, + { + {67, 63, 66, 62}, + {61, 65, 60, 64}, + {65, 61, 66, 62}, + {59, 63, 60, 64}, + }, + { + {68, 64, 67, 63}, + {62, 66, 61, 65}, + {66, 62, 67, 63}, + {60, 64, 61, 65}, + }, + { + {69, 65, 68, 64}, + {63, 67, 62, 66}, + {67, 63, 68, 64}, + {61, 65, 62, 66}, + }, + { + {70, 66, 69, 65}, + {64, 68, 63, 67}, + {68, 64, 69, 65}, + {62, 66, 63, 67}, + }, + { + {71, 67, 70, 66}, + {65, 69, 64, 68}, + {69, 65, 70, 66}, + {63, 67, 64, 68}, + }, + { + {72, 68, 71, 67}, + {66, 70, 65, 69}, + {70, 66, 71, 67}, + {64, 68, 65, 69}, + }, + { + {73, 69, 72, 68}, + {67, 71, 66, 70}, + {71, 67, 72, 68}, + {65, 69, 66, 70}, + }, + { + {74, 70, 73, 69}, + {68, 72, 67, 71}, + {72, 68, 73, 69}, + {66, 70, 67, 71}, + }, + { + {75, 71, 74, 70}, + {69, 73, 68, 72}, + {73, 69, 74, 70}, + {67, 71, 68, 72}, + }, + { + {76, 72, 75, 71}, + {70, 74, 69, 73}, + {74, 70, 75, 71}, + {68, 72, 69, 73}, + }, + { + {77, 73, 76, 72}, + {71, 75, 70, 74}, + {75, 71, 76, 72}, + {69, 73, 70, 74}, + }, + { + {78, 74, 77, 73}, + {72, 76, 71, 75}, + {76, 72, 77, 73}, + {70, 74, 71, 75}, + }, + { + {79, 75, 78, 74}, + {73, 77, 72, 76}, + {77, 73, 78, 74}, + {71, 75, 72, 76}, + }, + { + {80, 76, 79, 75}, + {74, 78, 73, 77}, + {78, 74, 79, 75}, + {72, 76, 73, 77}, + }, + { + {81, 77, 80, 76}, + {75, 79, 74, 78}, + {79, 75, 80, 76}, + {73, 77, 74, 78}, + }, + { + {82, 78, 81, 77}, + {76, 80, 75, 79}, + {80, 76, 81, 77}, + {74, 78, 75, 79}, + }, + { + {83, 79, 82, 78}, + {77, 81, 76, 80}, + {81, 77, 82, 78}, + {75, 79, 76, 80}, + }, + { + {84, 80, 83, 79}, + {78, 82, 77, 81}, + {82, 78, 83, 79}, + {76, 80, 77, 81}, + }, + { + {85, 81, 84, 80}, + {79, 83, 78, 82}, + {83, 79, 84, 80}, + {77, 81, 78, 82}, + }, + { + {86, 82, 85, 81}, + {80, 84, 79, 83}, + {84, 80, 85, 81}, + {78, 82, 79, 83}, + }, + { + {87, 83, 86, 82}, + {81, 85, 80, 84}, + {85, 81, 86, 82}, + {79, 83, 80, 84}, + }, + { + {88, 84, 87, 83}, + {82, 86, 81, 85}, + {86, 82, 87, 83}, + {80, 84, 81, 85}, + }, + { + {89, 85, 88, 84}, + {83, 87, 82, 86}, + {87, 83, 88, 84}, + {81, 85, 82, 86}, + }, + { + {90, 86, 89, 85}, + {84, 88, 83, 87}, + {88, 84, 89, 85}, + {82, 86, 83, 87}, + }, + { + {91, 87, 90, 86}, + {85, 89, 84, 88}, + {89, 85, 90, 86}, + {83, 87, 84, 88}, + }, + { + {92, 88, 91, 87}, + {86, 90, 85, 89}, + {90, 86, 91, 87}, + {84, 88, 85, 89}, + }, + { + {93, 89, 92, 88}, + {87, 91, 86, 90}, + {91, 87, 92, 88}, + {85, 89, 86, 90}, + }, + { + {94, 90, 93, 89}, + {88, 92, 87, 91}, + {92, 88, 93, 89}, + {86, 90, 87, 91}, + }, + { + {95, 91, 94, 90}, + {89, 93, 88, 92}, + {93, 89, 94, 90}, + {87, 91, 88, 92}, + }, + { + {96, 92, 95, 91}, + {90, 94, 89, 93}, + {94, 90, 95, 91}, + {88, 92, 89, 93}, + }, + { + {97, 93, 96, 92}, + {91, 95, 90, 94}, + {95, 91, 96, 92}, + {89, 93, 90, 94}, + }, + { + {98, 94, 97, 93}, + {92, 96, 91, 95}, + {96, 92, 97, 93}, + {90, 94, 91, 95}, + }, + { + {99, 95, 98, 94}, + {93, 97, 92, 96}, + {97, 93, 98, 94}, + {91, 95, 92, 96}, + }, + { + {100, 96, 99, 95}, + {94, 98, 93, 97}, + {98, 94, 99, 95}, + {92, 96, 93, 97}, + }, + { + {101, 97, 100, 96}, + {95, 99, 94, 98}, + {99, 95, 100, 96}, + {93, 97, 94, 98}, + }, + { + {102, 98, 101, 97}, + {96, 100, 95, 99}, + {100, 96, 101, 97}, + {94, 98, 95, 99}, + }, + { + {103, 99, 102, 98}, + {97, 101, 96, 100}, + {101, 97, 102, 98}, + {95, 99, 96, 100}, + }, + { + {104, 100, 103, 99}, + {98, 102, 97, 101}, + {102, 98, 103, 99}, + {96, 100, 97, 101}, + }, + { + {105, 101, 104, 100}, + {99, 103, 98, 102}, + {103, 99, 104, 100}, + {97, 101, 98, 102}, + }, + { + {106, 102, 105, 101}, + {100, 104, 99, 103}, + {104, 100, 105, 101}, + {98, 102, 99, 103}, + }, + { + {107, 103, 106, 102}, + {101, 105, 100, 104}, + {105, 101, 106, 102}, + {99, 103, 100, 104}, + }, + { + {108, 104, 107, 103}, + {102, 106, 101, 105}, + {106, 102, 107, 103}, + {100, 104, 101, 105}, + }, + { + {109, 105, 108, 104}, + {103, 107, 102, 106}, + {107, 103, 108, 104}, + {101, 105, 102, 106}, + }, + { + {110, 106, 109, 105}, + {104, 108, 103, 107}, + {108, 104, 109, 105}, + {102, 106, 103, 107}, + }, + { + {111, 107, 110, 106}, + {105, 109, 104, 108}, + {109, 105, 110, 106}, + {103, 107, 104, 108}, + }, + { + {112, 108, 111, 107}, + {106, 110, 105, 109}, + {110, 106, 111, 107}, + {104, 108, 105, 109}, + }, + { + {113, 109, 112, 108}, + {107, 111, 106, 110}, + {111, 107, 112, 108}, + {105, 109, 106, 110}, + }, + { + {114, 110, 113, 109}, + {108, 112, 107, 111}, + {112, 108, 113, 109}, + {106, 110, 107, 111}, + }, + { + {115, 111, 114, 110}, + {109, 113, 108, 112}, + {113, 109, 114, 110}, + {107, 111, 108, 112}, + }, + { + {116, 112, 115, 111}, + {110, 114, 109, 113}, + {114, 110, 115, 111}, + {108, 112, 109, 113}, + }, + { + {117, 113, 116, 112}, + {111, 115, 110, 114}, + {115, 111, 116, 112}, + {109, 113, 110, 114}, + }, + { + {118, 114, 117, 113}, + {112, 116, 111, 115}, + {116, 112, 117, 113}, + {110, 114, 111, 115}, + }, + { + {119, 115, 118, 114}, + {113, 117, 112, 116}, + {117, 113, 118, 114}, + {111, 115, 112, 116}, + }, + { + {120, 116, 119, 115}, + {114, 118, 113, 117}, + {118, 114, 119, 115}, + {112, 116, 113, 117}, + }, + { + {121, 117, 120, 116}, + {115, 119, 114, 118}, + {119, 115, 120, 116}, + {113, 117, 114, 118}, + }, + { + {122, 118, 121, 117}, + {116, 120, 115, 119}, + {120, 116, 121, 117}, + {114, 118, 115, 119}, + }, + { + {123, 119, 122, 118}, + {117, 121, 116, 120}, + {121, 117, 122, 118}, + {115, 119, 116, 120}, + }, + { + {124, 120, 123, 119}, + {118, 122, 117, 121}, + {122, 118, 123, 119}, + {116, 120, 117, 121}, + }, + { + {125, 121, 124, 120}, + {119, 123, 118, 122}, + {123, 119, 124, 120}, + {117, 121, 118, 122}, + }, + { + {126, 122, 125, 121}, + {120, 124, 119, 123}, + {124, 120, 125, 121}, + {118, 122, 119, 123}, + }, + { + {127, 123, 126, 122}, + {121, 125, 120, 124}, + {125, 121, 126, 122}, + {119, 123, 120, 124}, + }, + { + {128, 124, 127, 123}, + {122, 126, 121, 125}, + {126, 122, 127, 123}, + {120, 124, 121, 125}, + }, + { + {129, 125, 128, 124}, + {123, 127, 122, 126}, + {127, 123, 128, 124}, + {121, 125, 122, 126}, + }, + { + {130, 126, 129, 125}, + {124, 128, 123, 127}, + {128, 124, 129, 125}, + {122, 126, 123, 127}, + }, + { + {131, 127, 130, 126}, + {125, 129, 124, 128}, + {129, 125, 130, 126}, + {123, 127, 124, 128}, + }, + { + {132, 128, 131, 127}, + {126, 130, 125, 129}, + {130, 126, 131, 127}, + {124, 128, 125, 129}, + }, + { + {133, 129, 132, 128}, + {127, 131, 126, 130}, + {131, 127, 132, 128}, + {125, 129, 126, 130}, + }, + { + {134, 130, 133, 129}, + {128, 132, 127, 131}, + {132, 128, 133, 129}, + {126, 130, 127, 131}, + }, + { + {135, 131, 134, 130}, + {129, 133, 128, 132}, + {133, 129, 134, 130}, + {127, 131, 128, 132}, + }, + { + {136, 132, 135, 131}, + {130, 134, 129, 133}, + {134, 130, 135, 131}, + {128, 132, 129, 133}, + }, + { + {137, 133, 136, 132}, + {131, 135, 130, 134}, + {135, 131, 136, 132}, + {129, 133, 130, 134}, + }, + { + {138, 134, 137, 133}, + {132, 136, 131, 135}, + {136, 132, 137, 133}, + {130, 134, 131, 135}, + }, + { + {139, 135, 138, 134}, + {133, 137, 132, 136}, + {137, 133, 138, 134}, + {131, 135, 132, 136}, + }, + { + {140, 136, 139, 135}, + {134, 138, 133, 137}, + {138, 134, 139, 135}, + {132, 136, 133, 137}, + }, + { + {141, 137, 140, 136}, + {135, 139, 134, 138}, + {139, 135, 140, 136}, + {133, 137, 134, 138}, + }, + { + {142, 138, 141, 137}, + {136, 140, 135, 139}, + {140, 136, 141, 137}, + {134, 138, 135, 139}, + }, + { + {143, 139, 142, 138}, + {137, 141, 136, 140}, + {141, 137, 142, 138}, + {135, 139, 136, 140}, + }, + { + {144, 140, 143, 139}, + {138, 142, 137, 141}, + {142, 138, 143, 139}, + {136, 140, 137, 141}, + }, + { + {145, 141, 144, 140}, + {139, 143, 138, 142}, + {143, 139, 144, 140}, + {137, 141, 138, 142}, + }, + { + {146, 142, 145, 141}, + {140, 144, 139, 143}, + {144, 140, 145, 141}, + {138, 142, 139, 143}, + }, + { + {147, 143, 146, 142}, + {141, 145, 140, 144}, + {145, 141, 146, 142}, + {139, 143, 140, 144}, + }, + { + {148, 144, 147, 143}, + {142, 146, 141, 145}, + {146, 142, 147, 143}, + {140, 144, 141, 145}, + }, + { + {149, 145, 148, 144}, + {143, 147, 142, 146}, + {147, 143, 148, 144}, + {141, 145, 142, 146}, + }, + { + {150, 146, 149, 145}, + {144, 148, 143, 147}, + {148, 144, 149, 145}, + {142, 146, 143, 147}, + }, + { + {151, 147, 150, 146}, + {145, 149, 144, 148}, + {149, 145, 150, 146}, + {143, 147, 144, 148}, + }, + { + {152, 148, 151, 147}, + {146, 150, 145, 149}, + {150, 146, 151, 147}, + {144, 148, 145, 149}, + }, + { + {153, 149, 152, 148}, + {147, 151, 146, 150}, + {151, 147, 152, 148}, + {145, 149, 146, 150}, + }, + { + {154, 150, 153, 149}, + {148, 152, 147, 151}, + {152, 148, 153, 149}, + {146, 150, 147, 151}, + }, + { + {155, 151, 154, 150}, + {149, 153, 148, 152}, + {153, 149, 154, 150}, + {147, 151, 148, 152}, + }, + { + {156, 152, 155, 151}, + {150, 154, 149, 153}, + {154, 150, 155, 151}, + {148, 152, 149, 153}, + }, + { + {157, 153, 156, 152}, + {151, 155, 150, 154}, + {155, 151, 156, 152}, + {149, 153, 150, 154}, + }, + { + {158, 154, 157, 153}, + {152, 156, 151, 155}, + {156, 152, 157, 153}, + {150, 154, 151, 155}, + }, + { + {159, 155, 158, 154}, + {153, 157, 152, 156}, + {157, 153, 158, 154}, + {151, 155, 152, 156}, + }, + { + {160, 156, 159, 155}, + {154, 158, 153, 157}, + {158, 154, 159, 155}, + {152, 156, 153, 157}, + }, + { + {161, 157, 160, 156}, + {155, 159, 154, 158}, + {159, 155, 160, 156}, + {153, 157, 154, 158}, + }, + { + {162, 158, 161, 157}, + {156, 160, 155, 159}, + {160, 156, 161, 157}, + {154, 158, 155, 159}, + }, + { + {163, 159, 162, 158}, + {157, 161, 156, 160}, + {161, 157, 162, 158}, + {155, 159, 156, 160}, + }, + { + {164, 160, 163, 159}, + {158, 162, 157, 161}, + {162, 158, 163, 159}, + {156, 160, 157, 161}, + }, + { + {165, 161, 164, 160}, + {159, 163, 158, 162}, + {163, 159, 164, 160}, + {157, 161, 158, 162}, + }, + { + {166, 162, 165, 161}, + {160, 164, 159, 163}, + {164, 160, 165, 161}, + {158, 162, 159, 163}, + }, + { + {167, 163, 166, 162}, + {161, 165, 160, 164}, + {165, 161, 166, 162}, + {159, 163, 160, 164}, + }, + { + {168, 164, 167, 163}, + {162, 166, 161, 165}, + {166, 162, 167, 163}, + {160, 164, 161, 165}, + }, + { + {169, 165, 168, 164}, + {163, 167, 162, 166}, + {167, 163, 168, 164}, + {161, 165, 162, 166}, + }, + { + {170, 166, 169, 165}, + {164, 168, 163, 167}, + {168, 164, 169, 165}, + {162, 166, 163, 167}, + }, + { + {171, 167, 170, 166}, + {165, 169, 164, 168}, + {169, 165, 170, 166}, + {163, 167, 164, 168}, + }, + { + {172, 168, 171, 167}, + {166, 170, 165, 169}, + {170, 166, 171, 167}, + {164, 168, 165, 169}, + }, + { + {173, 169, 172, 168}, + {167, 171, 166, 170}, + {171, 167, 172, 168}, + {165, 169, 166, 170}, + }, + { + {174, 170, 173, 169}, + {168, 172, 167, 171}, + {172, 168, 173, 169}, + {166, 170, 167, 171}, + }, + { + {175, 171, 174, 170}, + {169, 173, 168, 172}, + {173, 169, 174, 170}, + {167, 171, 168, 172}, + }, + { + {176, 172, 175, 171}, + {170, 174, 169, 173}, + {174, 170, 175, 171}, + {168, 172, 169, 173}, + }, + { + {177, 173, 176, 172}, + {171, 175, 170, 174}, + {175, 171, 176, 172}, + {169, 173, 170, 174}, + }, + { + {178, 174, 177, 173}, + {172, 176, 171, 175}, + {176, 172, 177, 173}, + {170, 174, 171, 175}, + }, + { + {179, 175, 178, 174}, + {173, 177, 172, 176}, + {177, 173, 178, 174}, + {171, 175, 172, 176}, + }, + { + {180, 176, 179, 175}, + {174, 178, 173, 177}, + {178, 174, 179, 175}, + {172, 176, 173, 177}, + }, + { + {181, 177, 180, 176}, + {175, 179, 174, 178}, + {179, 175, 180, 176}, + {173, 177, 174, 178}, + }, + { + {182, 178, 181, 177}, + {176, 180, 175, 179}, + {180, 176, 181, 177}, + {174, 178, 175, 179}, + }, + { + {183, 179, 182, 178}, + {177, 181, 176, 180}, + {181, 177, 182, 178}, + {175, 179, 176, 180}, + }, + { + {184, 180, 183, 179}, + {178, 182, 177, 181}, + {182, 178, 183, 179}, + {176, 180, 177, 181}, + }, + { + {185, 181, 184, 180}, + {179, 183, 178, 182}, + {183, 179, 184, 180}, + {177, 181, 178, 182}, + }, + { + {186, 182, 185, 181}, + {180, 184, 179, 183}, + {184, 180, 185, 181}, + {178, 182, 179, 183}, + }, + { + {187, 183, 186, 182}, + {181, 185, 180, 184}, + {185, 181, 186, 182}, + {179, 183, 180, 184}, + }, + { + {188, 184, 187, 183}, + {182, 186, 181, 185}, + {186, 182, 187, 183}, + {180, 184, 181, 185}, + }, + { + {189, 185, 188, 184}, + {183, 187, 182, 186}, + {187, 183, 188, 184}, + {181, 185, 182, 186}, + }, + { + {190, 186, 189, 185}, + {184, 188, 183, 187}, + {188, 184, 189, 185}, + {182, 186, 183, 187}, + }, + { + {191, 187, 190, 186}, + {185, 189, 184, 188}, + {189, 185, 190, 186}, + {183, 187, 184, 188}, + }, + { + {192, 188, 191, 187}, + {186, 190, 185, 189}, + {190, 186, 191, 187}, + {184, 188, 185, 189}, + }, + { + {193, 189, 192, 188}, + {187, 191, 186, 190}, + {191, 187, 192, 188}, + {185, 189, 186, 190}, + }, + { + {194, 190, 193, 189}, + {188, 192, 187, 191}, + {192, 188, 193, 189}, + {186, 190, 187, 191}, + }, + { + {195, 191, 194, 190}, + {189, 193, 188, 192}, + {193, 189, 194, 190}, + {187, 191, 188, 192}, + }, + { + {196, 192, 195, 191}, + {190, 194, 189, 193}, + {194, 190, 195, 191}, + {188, 192, 189, 193}, + }, + { + {197, 193, 196, 192}, + {191, 195, 190, 194}, + {195, 191, 196, 192}, + {189, 193, 190, 194}, + }, + { + {198, 194, 197, 193}, + {192, 196, 191, 195}, + {196, 192, 197, 193}, + {190, 194, 191, 195}, + }, + { + {199, 195, 198, 194}, + {193, 197, 192, 196}, + {197, 193, 198, 194}, + {191, 195, 192, 196}, + }, + { + {200, 196, 199, 195}, + {194, 198, 193, 197}, + {198, 194, 199, 195}, + {192, 196, 193, 197}, + }, + { + {201, 197, 200, 196}, + {195, 199, 194, 198}, + {199, 195, 200, 196}, + {193, 197, 194, 198}, + }, + { + {202, 198, 201, 197}, + {196, 200, 195, 199}, + {200, 196, 201, 197}, + {194, 198, 195, 199}, + }, + { + {203, 199, 202, 198}, + {197, 201, 196, 200}, + {201, 197, 202, 198}, + {195, 199, 196, 200}, + }, + { + {204, 200, 203, 199}, + {198, 202, 197, 201}, + {202, 198, 203, 199}, + {196, 200, 197, 201}, + }, + { + {205, 201, 204, 200}, + {199, 203, 198, 202}, + {203, 199, 204, 200}, + {197, 201, 198, 202}, + }, + { + {206, 202, 205, 201}, + {200, 204, 199, 203}, + {204, 200, 205, 201}, + {198, 202, 199, 203}, + }, + { + {207, 203, 206, 202}, + {201, 205, 200, 204}, + {205, 201, 206, 202}, + {199, 203, 200, 204}, + }, + { + {208, 204, 207, 203}, + {202, 206, 201, 205}, + {206, 202, 207, 203}, + {200, 204, 201, 205}, + }, + { + {209, 205, 208, 204}, + {203, 207, 202, 206}, + {207, 203, 208, 204}, + {201, 205, 202, 206}, + }, + { + {210, 206, 209, 205}, + {204, 208, 203, 207}, + {208, 204, 209, 205}, + {202, 206, 203, 207}, + }, + { + {211, 207, 210, 206}, + {205, 209, 204, 208}, + {209, 205, 210, 206}, + {203, 207, 204, 208}, + }, + { + {212, 208, 211, 207}, + {206, 210, 205, 209}, + {210, 206, 211, 207}, + {204, 208, 205, 209}, + }, + { + {213, 209, 212, 208}, + {207, 211, 206, 210}, + {211, 207, 212, 208}, + {205, 209, 206, 210}, + }, + { + {214, 210, 213, 209}, + {208, 212, 207, 211}, + {212, 208, 213, 209}, + {206, 210, 207, 211}, + }, + { + {215, 211, 214, 210}, + {209, 213, 208, 212}, + {213, 209, 214, 210}, + {207, 211, 208, 212}, + }, + { + {216, 212, 215, 211}, + {210, 214, 209, 213}, + {214, 210, 215, 211}, + {208, 212, 209, 213}, + }, + { + {217, 213, 216, 212}, + {211, 215, 210, 214}, + {215, 211, 216, 212}, + {209, 213, 210, 214}, + }, + { + {218, 214, 217, 213}, + {212, 216, 211, 215}, + {216, 212, 217, 213}, + {210, 214, 211, 215}, + }, + { + {219, 215, 218, 214}, + {213, 217, 212, 216}, + {217, 213, 218, 214}, + {211, 215, 212, 216}, + }, + { + {220, 216, 219, 215}, + {214, 218, 213, 217}, + {218, 214, 219, 215}, + {212, 216, 213, 217}, + }, + { + {221, 217, 220, 216}, + {215, 219, 214, 218}, + {219, 215, 220, 216}, + {213, 217, 214, 218}, + }, + { + {222, 218, 221, 217}, + {216, 220, 215, 219}, + {220, 216, 221, 217}, + {214, 218, 215, 219}, + }, + { + {223, 219, 222, 218}, + {217, 221, 216, 220}, + {221, 217, 222, 218}, + {215, 219, 216, 220}, + }, + { + {224, 220, 223, 219}, + {218, 222, 217, 221}, + {222, 218, 223, 219}, + {216, 220, 217, 221}, + }, + { + {225, 221, 224, 220}, + {219, 223, 218, 222}, + {223, 219, 224, 220}, + {217, 221, 218, 222}, + }, + { + {226, 222, 225, 221}, + {220, 224, 219, 223}, + {224, 220, 225, 221}, + {218, 222, 219, 223}, + }, + { + {227, 223, 226, 222}, + {221, 225, 220, 224}, + {225, 221, 226, 222}, + {219, 223, 220, 224}, + }, + { + {228, 224, 227, 223}, + {222, 226, 221, 225}, + {226, 222, 227, 223}, + {220, 224, 221, 225}, + }, + { + {229, 225, 228, 224}, + {223, 227, 222, 226}, + {227, 223, 228, 224}, + {221, 225, 222, 226}, + }, + { + {230, 226, 229, 225}, + {224, 228, 223, 227}, + {228, 224, 229, 225}, + {222, 226, 223, 227}, + }, + { + {231, 227, 230, 226}, + {225, 229, 224, 228}, + {229, 225, 230, 226}, + {223, 227, 224, 228}, + }, + { + {232, 228, 231, 227}, + {226, 230, 225, 229}, + {230, 226, 231, 227}, + {224, 228, 225, 229}, + }, + { + {233, 229, 232, 228}, + {227, 231, 226, 230}, + {231, 227, 232, 228}, + {225, 229, 226, 230}, + }, + { + {234, 230, 233, 229}, + {228, 232, 227, 231}, + {232, 228, 233, 229}, + {226, 230, 227, 231}, + }, + { + {235, 231, 234, 230}, + {229, 233, 228, 232}, + {233, 229, 234, 230}, + {227, 231, 228, 232}, + }, + { + {236, 232, 235, 231}, + {230, 234, 229, 233}, + {234, 230, 235, 231}, + {228, 232, 229, 233}, + }, + { + {237, 233, 236, 232}, + {231, 235, 230, 234}, + {235, 231, 236, 232}, + {229, 233, 230, 234}, + }, + { + {238, 234, 237, 233}, + {232, 236, 231, 235}, + {236, 232, 237, 233}, + {230, 234, 231, 235}, + }, + { + {239, 235, 238, 234}, + {233, 237, 232, 236}, + {237, 233, 238, 234}, + {231, 235, 232, 236}, + }, + { + {240, 236, 239, 235}, + {234, 238, 233, 237}, + {238, 234, 239, 235}, + {232, 236, 233, 237}, + }, + { + {241, 237, 240, 236}, + {235, 239, 234, 238}, + {239, 235, 240, 236}, + {233, 237, 234, 238}, + }, + { + {242, 238, 241, 237}, + {236, 240, 235, 239}, + {240, 236, 241, 237}, + {234, 238, 235, 239}, + }, + { + {243, 239, 242, 238}, + {237, 241, 236, 240}, + {241, 237, 242, 238}, + {235, 239, 236, 240}, + }, + { + {244, 240, 243, 239}, + {238, 242, 237, 241}, + {242, 238, 243, 239}, + {236, 240, 237, 241}, + }, + { + {245, 241, 244, 240}, + {239, 243, 238, 242}, + {243, 239, 244, 240}, + {237, 241, 238, 242}, + }, + { + {246, 242, 245, 241}, + {240, 244, 239, 243}, + {244, 240, 245, 241}, + {238, 242, 239, 243}, + }, + { + {247, 243, 246, 242}, + {241, 245, 240, 244}, + {245, 241, 246, 242}, + {239, 243, 240, 244}, + }, + { + {248, 244, 247, 243}, + {242, 246, 241, 245}, + {246, 242, 247, 243}, + {240, 244, 241, 245}, + }, + { + {249, 245, 248, 244}, + {243, 247, 242, 246}, + {247, 243, 248, 244}, + {241, 245, 242, 246}, + }, + { + {250, 246, 249, 245}, + {244, 248, 243, 247}, + {248, 244, 249, 245}, + {242, 246, 243, 247}, + }, + { + {251, 247, 250, 246}, + {245, 249, 244, 248}, + {249, 245, 250, 246}, + {243, 247, 244, 248}, + }, + { + {252, 248, 251, 247}, + {246, 250, 245, 249}, + {250, 246, 251, 247}, + {244, 248, 245, 249}, + }, + { + {253, 249, 252, 248}, + {247, 251, 246, 250}, + {251, 247, 252, 248}, + {245, 249, 246, 250}, + }, + { + {254, 250, 253, 249}, + {248, 252, 247, 251}, + {252, 248, 253, 249}, + {246, 250, 247, 251}, + }, + { + {255, 251, 254, 250}, + {249, 253, 248, 252}, + {253, 249, 254, 250}, + {247, 251, 248, 252}, + }, + { + {255, 252, 255, 251}, + {250, 254, 249, 253}, + {254, 250, 255, 251}, + {248, 252, 249, 253}, + }, + { + {255, 253, 255, 252}, + {251, 255, 250, 254}, + {255, 251, 255, 252}, + {249, 253, 250, 254}, + }, + { + {255, 254, 255, 253}, + {252, 255, 251, 255}, + {255, 252, 255, 253}, + {250, 254, 251, 255}, + }, + { + {255, 255, 255, 254}, + {253, 255, 252, 255}, + {255, 253, 255, 254}, + {251, 255, 252, 255}, + }, + { + {255, 255, 255, 255}, + {254, 255, 253, 255}, + {255, 254, 255, 255}, + {252, 255, 253, 255}, + }, +}; + +static const uint8_t dithersub_g[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, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {5, 3, 4, 2}, + {2, 4, 1, 3}, + {4, 2, 4, 2}, + {1, 3, 1, 3}, + }, + { + {6, 4, 5, 3}, + {3, 5, 2, 4}, + {5, 3, 5, 3}, + {2, 4, 2, 4}, + }, + { + {7, 5, 6, 4}, + {4, 6, 3, 5}, + {6, 4, 6, 4}, + {3, 5, 3, 5}, + }, + { + {8, 6, 7, 5}, + {5, 7, 4, 6}, + {7, 5, 7, 5}, + {4, 6, 4, 6}, + }, + { + {9, 7, 8, 6}, + {6, 8, 5, 7}, + {8, 6, 8, 6}, + {5, 7, 5, 7}, + }, + { + {10, 8, 9, 7}, + {7, 9, 6, 8}, + {9, 7, 9, 7}, + {6, 8, 6, 8}, + }, + { + {11, 9, 10, 8}, + {8, 10, 7, 9}, + {10, 8, 10, 8}, + {7, 9, 7, 9}, + }, + { + {12, 10, 11, 9}, + {9, 11, 8, 10}, + {11, 9, 11, 9}, + {8, 10, 8, 10}, + }, + { + {13, 11, 12, 10}, + {10, 12, 9, 11}, + {12, 10, 12, 10}, + {9, 11, 9, 11}, + }, + { + {14, 12, 13, 11}, + {11, 13, 10, 12}, + {13, 11, 13, 11}, + {10, 12, 10, 12}, + }, + { + {15, 13, 14, 12}, + {12, 14, 11, 13}, + {14, 12, 14, 12}, + {11, 13, 11, 13}, + }, + { + {16, 14, 15, 13}, + {13, 15, 12, 14}, + {15, 13, 15, 13}, + {12, 14, 12, 14}, + }, + { + {17, 15, 16, 14}, + {14, 16, 13, 15}, + {16, 14, 16, 14}, + {13, 15, 13, 15}, + }, + { + {18, 16, 17, 15}, + {15, 17, 14, 16}, + {17, 15, 17, 15}, + {14, 16, 14, 16}, + }, + { + {19, 17, 18, 16}, + {16, 18, 15, 17}, + {18, 16, 18, 16}, + {15, 17, 15, 17}, + }, + { + {20, 18, 19, 17}, + {17, 19, 16, 18}, + {19, 17, 19, 17}, + {16, 18, 16, 18}, + }, + { + {21, 19, 20, 18}, + {18, 20, 17, 19}, + {20, 18, 20, 18}, + {17, 19, 17, 19}, + }, + { + {22, 20, 21, 19}, + {19, 21, 18, 20}, + {21, 19, 21, 19}, + {18, 20, 18, 20}, + }, + { + {23, 21, 22, 20}, + {20, 22, 19, 21}, + {22, 20, 22, 20}, + {19, 21, 19, 21}, + }, + { + {24, 22, 23, 21}, + {21, 23, 20, 22}, + {23, 21, 23, 21}, + {20, 22, 20, 22}, + }, + { + {25, 23, 24, 22}, + {22, 24, 21, 23}, + {24, 22, 24, 22}, + {21, 23, 21, 23}, + }, + { + {26, 24, 25, 23}, + {23, 25, 22, 24}, + {25, 23, 25, 23}, + {22, 24, 22, 24}, + }, + { + {27, 25, 26, 24}, + {24, 26, 23, 25}, + {26, 24, 26, 24}, + {23, 25, 23, 25}, + }, + { + {28, 26, 27, 25}, + {25, 27, 24, 26}, + {27, 25, 27, 25}, + {24, 26, 24, 26}, + }, + { + {29, 27, 28, 26}, + {26, 28, 25, 27}, + {28, 26, 28, 26}, + {25, 27, 25, 27}, + }, + { + {30, 28, 29, 27}, + {27, 29, 26, 28}, + {29, 27, 29, 27}, + {26, 28, 26, 28}, + }, + { + {31, 29, 30, 28}, + {28, 30, 27, 29}, + {30, 28, 30, 28}, + {27, 29, 27, 29}, + }, + { + {32, 30, 31, 29}, + {29, 31, 28, 30}, + {31, 29, 31, 29}, + {28, 30, 28, 30}, + }, + { + {33, 31, 32, 30}, + {30, 32, 29, 31}, + {32, 30, 32, 30}, + {29, 31, 29, 31}, + }, + { + {34, 32, 33, 31}, + {31, 33, 30, 32}, + {33, 31, 33, 31}, + {30, 32, 30, 32}, + }, + { + {35, 33, 34, 32}, + {32, 34, 31, 33}, + {34, 32, 34, 32}, + {31, 33, 31, 33}, + }, + { + {36, 34, 35, 33}, + {33, 35, 32, 34}, + {35, 33, 35, 33}, + {32, 34, 32, 34}, + }, + { + {37, 35, 36, 34}, + {34, 36, 33, 35}, + {36, 34, 36, 34}, + {33, 35, 33, 35}, + }, + { + {38, 36, 37, 35}, + {35, 37, 34, 36}, + {37, 35, 37, 35}, + {34, 36, 34, 36}, + }, + { + {39, 37, 38, 36}, + {36, 38, 35, 37}, + {38, 36, 38, 36}, + {35, 37, 35, 37}, + }, + { + {40, 38, 39, 37}, + {37, 39, 36, 38}, + {39, 37, 39, 37}, + {36, 38, 36, 38}, + }, + { + {41, 39, 40, 38}, + {38, 40, 37, 39}, + {40, 38, 40, 38}, + {37, 39, 37, 39}, + }, + { + {42, 40, 41, 39}, + {39, 41, 38, 40}, + {41, 39, 41, 39}, + {38, 40, 38, 40}, + }, + { + {43, 41, 42, 40}, + {40, 42, 39, 41}, + {42, 40, 42, 40}, + {39, 41, 39, 41}, + }, + { + {44, 42, 43, 41}, + {41, 43, 40, 42}, + {43, 41, 43, 41}, + {40, 42, 40, 42}, + }, + { + {45, 43, 44, 42}, + {42, 44, 41, 43}, + {44, 42, 44, 42}, + {41, 43, 41, 43}, + }, + { + {46, 44, 45, 43}, + {43, 45, 42, 44}, + {45, 43, 45, 43}, + {42, 44, 42, 44}, + }, + { + {47, 45, 46, 44}, + {44, 46, 43, 45}, + {46, 44, 46, 44}, + {43, 45, 43, 45}, + }, + { + {48, 46, 47, 45}, + {45, 47, 44, 46}, + {47, 45, 47, 45}, + {44, 46, 44, 46}, + }, + { + {49, 47, 48, 46}, + {46, 48, 45, 47}, + {48, 46, 48, 46}, + {45, 47, 45, 47}, + }, + { + {50, 48, 49, 47}, + {47, 49, 46, 48}, + {49, 47, 49, 47}, + {46, 48, 46, 48}, + }, + { + {51, 49, 50, 48}, + {48, 50, 47, 49}, + {50, 48, 50, 48}, + {47, 49, 47, 49}, + }, + { + {52, 50, 51, 49}, + {49, 51, 48, 50}, + {51, 49, 51, 49}, + {48, 50, 48, 50}, + }, + { + {53, 51, 52, 50}, + {50, 52, 49, 51}, + {52, 50, 52, 50}, + {49, 51, 49, 51}, + }, + { + {54, 52, 53, 51}, + {51, 53, 50, 52}, + {53, 51, 53, 51}, + {50, 52, 50, 52}, + }, + { + {55, 53, 54, 52}, + {52, 54, 51, 53}, + {54, 52, 54, 52}, + {51, 53, 51, 53}, + }, + { + {56, 54, 55, 53}, + {53, 55, 52, 54}, + {55, 53, 55, 53}, + {52, 54, 52, 54}, + }, + { + {57, 55, 56, 54}, + {54, 56, 53, 55}, + {56, 54, 56, 54}, + {53, 55, 53, 55}, + }, + { + {58, 56, 57, 55}, + {55, 57, 54, 56}, + {57, 55, 57, 55}, + {54, 56, 54, 56}, + }, + { + {59, 57, 58, 56}, + {56, 58, 55, 57}, + {58, 56, 58, 56}, + {55, 57, 55, 57}, + }, + { + {60, 58, 59, 57}, + {57, 59, 56, 58}, + {59, 57, 59, 57}, + {56, 58, 56, 58}, + }, + { + {61, 59, 60, 58}, + {58, 60, 57, 59}, + {60, 58, 60, 58}, + {57, 59, 57, 59}, + }, + { + {62, 60, 61, 59}, + {59, 61, 58, 60}, + {61, 59, 61, 59}, + {58, 60, 58, 60}, + }, + { + {63, 61, 62, 60}, + {60, 62, 59, 61}, + {62, 60, 62, 60}, + {59, 61, 59, 61}, + }, + { + {64, 62, 63, 61}, + {61, 63, 60, 62}, + {63, 61, 63, 61}, + {60, 62, 60, 62}, + }, + { + {65, 63, 64, 62}, + {62, 64, 61, 63}, + {64, 62, 64, 62}, + {61, 63, 61, 63}, + }, + { + {66, 64, 65, 63}, + {63, 65, 62, 64}, + {65, 63, 65, 63}, + {62, 64, 62, 64}, + }, + { + {67, 65, 66, 64}, + {64, 66, 63, 65}, + {66, 64, 66, 64}, + {63, 65, 63, 65}, + }, + { + {68, 66, 67, 65}, + {65, 67, 64, 66}, + {67, 65, 67, 65}, + {64, 66, 64, 66}, + }, + { + {69, 67, 68, 66}, + {66, 68, 65, 67}, + {68, 66, 68, 66}, + {65, 67, 65, 67}, + }, + { + {70, 68, 69, 67}, + {67, 69, 66, 68}, + {69, 67, 69, 67}, + {66, 68, 66, 68}, + }, + { + {71, 69, 70, 68}, + {68, 70, 67, 69}, + {70, 68, 70, 68}, + {67, 69, 67, 69}, + }, + { + {72, 70, 71, 69}, + {69, 71, 68, 70}, + {71, 69, 71, 69}, + {68, 70, 68, 70}, + }, + { + {73, 71, 72, 70}, + {70, 72, 69, 71}, + {72, 70, 72, 70}, + {69, 71, 69, 71}, + }, + { + {74, 72, 73, 71}, + {71, 73, 70, 72}, + {73, 71, 73, 71}, + {70, 72, 70, 72}, + }, + { + {75, 73, 74, 72}, + {72, 74, 71, 73}, + {74, 72, 74, 72}, + {71, 73, 71, 73}, + }, + { + {76, 74, 75, 73}, + {73, 75, 72, 74}, + {75, 73, 75, 73}, + {72, 74, 72, 74}, + }, + { + {77, 75, 76, 74}, + {74, 76, 73, 75}, + {76, 74, 76, 74}, + {73, 75, 73, 75}, + }, + { + {78, 76, 77, 75}, + {75, 77, 74, 76}, + {77, 75, 77, 75}, + {74, 76, 74, 76}, + }, + { + {79, 77, 78, 76}, + {76, 78, 75, 77}, + {78, 76, 78, 76}, + {75, 77, 75, 77}, + }, + { + {80, 78, 79, 77}, + {77, 79, 76, 78}, + {79, 77, 79, 77}, + {76, 78, 76, 78}, + }, + { + {81, 79, 80, 78}, + {78, 80, 77, 79}, + {80, 78, 80, 78}, + {77, 79, 77, 79}, + }, + { + {82, 80, 81, 79}, + {79, 81, 78, 80}, + {81, 79, 81, 79}, + {78, 80, 78, 80}, + }, + { + {83, 81, 82, 80}, + {80, 82, 79, 81}, + {82, 80, 82, 80}, + {79, 81, 79, 81}, + }, + { + {84, 82, 83, 81}, + {81, 83, 80, 82}, + {83, 81, 83, 81}, + {80, 82, 80, 82}, + }, + { + {85, 83, 84, 82}, + {82, 84, 81, 83}, + {84, 82, 84, 82}, + {81, 83, 81, 83}, + }, + { + {86, 84, 85, 83}, + {83, 85, 82, 84}, + {85, 83, 85, 83}, + {82, 84, 82, 84}, + }, + { + {87, 85, 86, 84}, + {84, 86, 83, 85}, + {86, 84, 86, 84}, + {83, 85, 83, 85}, + }, + { + {88, 86, 87, 85}, + {85, 87, 84, 86}, + {87, 85, 87, 85}, + {84, 86, 84, 86}, + }, + { + {89, 87, 88, 86}, + {86, 88, 85, 87}, + {88, 86, 88, 86}, + {85, 87, 85, 87}, + }, + { + {90, 88, 89, 87}, + {87, 89, 86, 88}, + {89, 87, 89, 87}, + {86, 88, 86, 88}, + }, + { + {91, 89, 90, 88}, + {88, 90, 87, 89}, + {90, 88, 90, 88}, + {87, 89, 87, 89}, + }, + { + {92, 90, 91, 89}, + {89, 91, 88, 90}, + {91, 89, 91, 89}, + {88, 90, 88, 90}, + }, + { + {93, 91, 92, 90}, + {90, 92, 89, 91}, + {92, 90, 92, 90}, + {89, 91, 89, 91}, + }, + { + {94, 92, 93, 91}, + {91, 93, 90, 92}, + {93, 91, 93, 91}, + {90, 92, 90, 92}, + }, + { + {95, 93, 94, 92}, + {92, 94, 91, 93}, + {94, 92, 94, 92}, + {91, 93, 91, 93}, + }, + { + {96, 94, 95, 93}, + {93, 95, 92, 94}, + {95, 93, 95, 93}, + {92, 94, 92, 94}, + }, + { + {97, 95, 96, 94}, + {94, 96, 93, 95}, + {96, 94, 96, 94}, + {93, 95, 93, 95}, + }, + { + {98, 96, 97, 95}, + {95, 97, 94, 96}, + {97, 95, 97, 95}, + {94, 96, 94, 96}, + }, + { + {99, 97, 98, 96}, + {96, 98, 95, 97}, + {98, 96, 98, 96}, + {95, 97, 95, 97}, + }, + { + {100, 98, 99, 97}, + {97, 99, 96, 98}, + {99, 97, 99, 97}, + {96, 98, 96, 98}, + }, + { + {101, 99, 100, 98}, + {98, 100, 97, 99}, + {100, 98, 100, 98}, + {97, 99, 97, 99}, + }, + { + {102, 100, 101, 99}, + {99, 101, 98, 100}, + {101, 99, 101, 99}, + {98, 100, 98, 100}, + }, + { + {103, 101, 102, 100}, + {100, 102, 99, 101}, + {102, 100, 102, 100}, + {99, 101, 99, 101}, + }, + { + {104, 102, 103, 101}, + {101, 103, 100, 102}, + {103, 101, 103, 101}, + {100, 102, 100, 102}, + }, + { + {105, 103, 104, 102}, + {102, 104, 101, 103}, + {104, 102, 104, 102}, + {101, 103, 101, 103}, + }, + { + {106, 104, 105, 103}, + {103, 105, 102, 104}, + {105, 103, 105, 103}, + {102, 104, 102, 104}, + }, + { + {107, 105, 106, 104}, + {104, 106, 103, 105}, + {106, 104, 106, 104}, + {103, 105, 103, 105}, + }, + { + {108, 106, 107, 105}, + {105, 107, 104, 106}, + {107, 105, 107, 105}, + {104, 106, 104, 106}, + }, + { + {109, 107, 108, 106}, + {106, 108, 105, 107}, + {108, 106, 108, 106}, + {105, 107, 105, 107}, + }, + { + {110, 108, 109, 107}, + {107, 109, 106, 108}, + {109, 107, 109, 107}, + {106, 108, 106, 108}, + }, + { + {111, 109, 110, 108}, + {108, 110, 107, 109}, + {110, 108, 110, 108}, + {107, 109, 107, 109}, + }, + { + {112, 110, 111, 109}, + {109, 111, 108, 110}, + {111, 109, 111, 109}, + {108, 110, 108, 110}, + }, + { + {113, 111, 112, 110}, + {110, 112, 109, 111}, + {112, 110, 112, 110}, + {109, 111, 109, 111}, + }, + { + {114, 112, 113, 111}, + {111, 113, 110, 112}, + {113, 111, 113, 111}, + {110, 112, 110, 112}, + }, + { + {115, 113, 114, 112}, + {112, 114, 111, 113}, + {114, 112, 114, 112}, + {111, 113, 111, 113}, + }, + { + {116, 114, 115, 113}, + {113, 115, 112, 114}, + {115, 113, 115, 113}, + {112, 114, 112, 114}, + }, + { + {117, 115, 116, 114}, + {114, 116, 113, 115}, + {116, 114, 116, 114}, + {113, 115, 113, 115}, + }, + { + {118, 116, 117, 115}, + {115, 117, 114, 116}, + {117, 115, 117, 115}, + {114, 116, 114, 116}, + }, + { + {119, 117, 118, 116}, + {116, 118, 115, 117}, + {118, 116, 118, 116}, + {115, 117, 115, 117}, + }, + { + {120, 118, 119, 117}, + {117, 119, 116, 118}, + {119, 117, 119, 117}, + {116, 118, 116, 118}, + }, + { + {121, 119, 120, 118}, + {118, 120, 117, 119}, + {120, 118, 120, 118}, + {117, 119, 117, 119}, + }, + { + {122, 120, 121, 119}, + {119, 121, 118, 120}, + {121, 119, 121, 119}, + {118, 120, 118, 120}, + }, + { + {123, 121, 122, 120}, + {120, 122, 119, 121}, + {122, 120, 122, 120}, + {119, 121, 119, 121}, + }, + { + {124, 122, 123, 121}, + {121, 123, 120, 122}, + {123, 121, 123, 121}, + {120, 122, 120, 122}, + }, + { + {125, 123, 124, 122}, + {122, 124, 121, 123}, + {124, 122, 124, 122}, + {121, 123, 121, 123}, + }, + { + {126, 124, 125, 123}, + {123, 125, 122, 124}, + {125, 123, 125, 123}, + {122, 124, 122, 124}, + }, + { + {127, 125, 126, 124}, + {124, 126, 123, 125}, + {126, 124, 126, 124}, + {123, 125, 123, 125}, + }, + { + {128, 126, 127, 125}, + {125, 127, 124, 126}, + {127, 125, 127, 125}, + {124, 126, 124, 126}, + }, + { + {129, 127, 128, 126}, + {126, 128, 125, 127}, + {128, 126, 128, 126}, + {125, 127, 125, 127}, + }, + { + {130, 128, 129, 127}, + {127, 129, 126, 128}, + {129, 127, 129, 127}, + {126, 128, 126, 128}, + }, + { + {131, 129, 130, 128}, + {128, 130, 127, 129}, + {130, 128, 130, 128}, + {127, 129, 127, 129}, + }, + { + {132, 130, 131, 129}, + {129, 131, 128, 130}, + {131, 129, 131, 129}, + {128, 130, 128, 130}, + }, + { + {133, 131, 132, 130}, + {130, 132, 129, 131}, + {132, 130, 132, 130}, + {129, 131, 129, 131}, + }, + { + {134, 132, 133, 131}, + {131, 133, 130, 132}, + {133, 131, 133, 131}, + {130, 132, 130, 132}, + }, + { + {135, 133, 134, 132}, + {132, 134, 131, 133}, + {134, 132, 134, 132}, + {131, 133, 131, 133}, + }, + { + {136, 134, 135, 133}, + {133, 135, 132, 134}, + {135, 133, 135, 133}, + {132, 134, 132, 134}, + }, + { + {137, 135, 136, 134}, + {134, 136, 133, 135}, + {136, 134, 136, 134}, + {133, 135, 133, 135}, + }, + { + {138, 136, 137, 135}, + {135, 137, 134, 136}, + {137, 135, 137, 135}, + {134, 136, 134, 136}, + }, + { + {139, 137, 138, 136}, + {136, 138, 135, 137}, + {138, 136, 138, 136}, + {135, 137, 135, 137}, + }, + { + {140, 138, 139, 137}, + {137, 139, 136, 138}, + {139, 137, 139, 137}, + {136, 138, 136, 138}, + }, + { + {141, 139, 140, 138}, + {138, 140, 137, 139}, + {140, 138, 140, 138}, + {137, 139, 137, 139}, + }, + { + {142, 140, 141, 139}, + {139, 141, 138, 140}, + {141, 139, 141, 139}, + {138, 140, 138, 140}, + }, + { + {143, 141, 142, 140}, + {140, 142, 139, 141}, + {142, 140, 142, 140}, + {139, 141, 139, 141}, + }, + { + {144, 142, 143, 141}, + {141, 143, 140, 142}, + {143, 141, 143, 141}, + {140, 142, 140, 142}, + }, + { + {145, 143, 144, 142}, + {142, 144, 141, 143}, + {144, 142, 144, 142}, + {141, 143, 141, 143}, + }, + { + {146, 144, 145, 143}, + {143, 145, 142, 144}, + {145, 143, 145, 143}, + {142, 144, 142, 144}, + }, + { + {147, 145, 146, 144}, + {144, 146, 143, 145}, + {146, 144, 146, 144}, + {143, 145, 143, 145}, + }, + { + {148, 146, 147, 145}, + {145, 147, 144, 146}, + {147, 145, 147, 145}, + {144, 146, 144, 146}, + }, + { + {149, 147, 148, 146}, + {146, 148, 145, 147}, + {148, 146, 148, 146}, + {145, 147, 145, 147}, + }, + { + {150, 148, 149, 147}, + {147, 149, 146, 148}, + {149, 147, 149, 147}, + {146, 148, 146, 148}, + }, + { + {151, 149, 150, 148}, + {148, 150, 147, 149}, + {150, 148, 150, 148}, + {147, 149, 147, 149}, + }, + { + {152, 150, 151, 149}, + {149, 151, 148, 150}, + {151, 149, 151, 149}, + {148, 150, 148, 150}, + }, + { + {153, 151, 152, 150}, + {150, 152, 149, 151}, + {152, 150, 152, 150}, + {149, 151, 149, 151}, + }, + { + {154, 152, 153, 151}, + {151, 153, 150, 152}, + {153, 151, 153, 151}, + {150, 152, 150, 152}, + }, + { + {155, 153, 154, 152}, + {152, 154, 151, 153}, + {154, 152, 154, 152}, + {151, 153, 151, 153}, + }, + { + {156, 154, 155, 153}, + {153, 155, 152, 154}, + {155, 153, 155, 153}, + {152, 154, 152, 154}, + }, + { + {157, 155, 156, 154}, + {154, 156, 153, 155}, + {156, 154, 156, 154}, + {153, 155, 153, 155}, + }, + { + {158, 156, 157, 155}, + {155, 157, 154, 156}, + {157, 155, 157, 155}, + {154, 156, 154, 156}, + }, + { + {159, 157, 158, 156}, + {156, 158, 155, 157}, + {158, 156, 158, 156}, + {155, 157, 155, 157}, + }, + { + {160, 158, 159, 157}, + {157, 159, 156, 158}, + {159, 157, 159, 157}, + {156, 158, 156, 158}, + }, + { + {161, 159, 160, 158}, + {158, 160, 157, 159}, + {160, 158, 160, 158}, + {157, 159, 157, 159}, + }, + { + {162, 160, 161, 159}, + {159, 161, 158, 160}, + {161, 159, 161, 159}, + {158, 160, 158, 160}, + }, + { + {163, 161, 162, 160}, + {160, 162, 159, 161}, + {162, 160, 162, 160}, + {159, 161, 159, 161}, + }, + { + {164, 162, 163, 161}, + {161, 163, 160, 162}, + {163, 161, 163, 161}, + {160, 162, 160, 162}, + }, + { + {165, 163, 164, 162}, + {162, 164, 161, 163}, + {164, 162, 164, 162}, + {161, 163, 161, 163}, + }, + { + {166, 164, 165, 163}, + {163, 165, 162, 164}, + {165, 163, 165, 163}, + {162, 164, 162, 164}, + }, + { + {167, 165, 166, 164}, + {164, 166, 163, 165}, + {166, 164, 166, 164}, + {163, 165, 163, 165}, + }, + { + {168, 166, 167, 165}, + {165, 167, 164, 166}, + {167, 165, 167, 165}, + {164, 166, 164, 166}, + }, + { + {169, 167, 168, 166}, + {166, 168, 165, 167}, + {168, 166, 168, 166}, + {165, 167, 165, 167}, + }, + { + {170, 168, 169, 167}, + {167, 169, 166, 168}, + {169, 167, 169, 167}, + {166, 168, 166, 168}, + }, + { + {171, 169, 170, 168}, + {168, 170, 167, 169}, + {170, 168, 170, 168}, + {167, 169, 167, 169}, + }, + { + {172, 170, 171, 169}, + {169, 171, 168, 170}, + {171, 169, 171, 169}, + {168, 170, 168, 170}, + }, + { + {173, 171, 172, 170}, + {170, 172, 169, 171}, + {172, 170, 172, 170}, + {169, 171, 169, 171}, + }, + { + {174, 172, 173, 171}, + {171, 173, 170, 172}, + {173, 171, 173, 171}, + {170, 172, 170, 172}, + }, + { + {175, 173, 174, 172}, + {172, 174, 171, 173}, + {174, 172, 174, 172}, + {171, 173, 171, 173}, + }, + { + {176, 174, 175, 173}, + {173, 175, 172, 174}, + {175, 173, 175, 173}, + {172, 174, 172, 174}, + }, + { + {177, 175, 176, 174}, + {174, 176, 173, 175}, + {176, 174, 176, 174}, + {173, 175, 173, 175}, + }, + { + {178, 176, 177, 175}, + {175, 177, 174, 176}, + {177, 175, 177, 175}, + {174, 176, 174, 176}, + }, + { + {179, 177, 178, 176}, + {176, 178, 175, 177}, + {178, 176, 178, 176}, + {175, 177, 175, 177}, + }, + { + {180, 178, 179, 177}, + {177, 179, 176, 178}, + {179, 177, 179, 177}, + {176, 178, 176, 178}, + }, + { + {181, 179, 180, 178}, + {178, 180, 177, 179}, + {180, 178, 180, 178}, + {177, 179, 177, 179}, + }, + { + {182, 180, 181, 179}, + {179, 181, 178, 180}, + {181, 179, 181, 179}, + {178, 180, 178, 180}, + }, + { + {183, 181, 182, 180}, + {180, 182, 179, 181}, + {182, 180, 182, 180}, + {179, 181, 179, 181}, + }, + { + {184, 182, 183, 181}, + {181, 183, 180, 182}, + {183, 181, 183, 181}, + {180, 182, 180, 182}, + }, + { + {185, 183, 184, 182}, + {182, 184, 181, 183}, + {184, 182, 184, 182}, + {181, 183, 181, 183}, + }, + { + {186, 184, 185, 183}, + {183, 185, 182, 184}, + {185, 183, 185, 183}, + {182, 184, 182, 184}, + }, + { + {187, 185, 186, 184}, + {184, 186, 183, 185}, + {186, 184, 186, 184}, + {183, 185, 183, 185}, + }, + { + {188, 186, 187, 185}, + {185, 187, 184, 186}, + {187, 185, 187, 185}, + {184, 186, 184, 186}, + }, + { + {189, 187, 188, 186}, + {186, 188, 185, 187}, + {188, 186, 188, 186}, + {185, 187, 185, 187}, + }, + { + {190, 188, 189, 187}, + {187, 189, 186, 188}, + {189, 187, 189, 187}, + {186, 188, 186, 188}, + }, + { + {191, 189, 190, 188}, + {188, 190, 187, 189}, + {190, 188, 190, 188}, + {187, 189, 187, 189}, + }, + { + {192, 190, 191, 189}, + {189, 191, 188, 190}, + {191, 189, 191, 189}, + {188, 190, 188, 190}, + }, + { + {193, 191, 192, 190}, + {190, 192, 189, 191}, + {192, 190, 192, 190}, + {189, 191, 189, 191}, + }, + { + {194, 192, 193, 191}, + {191, 193, 190, 192}, + {193, 191, 193, 191}, + {190, 192, 190, 192}, + }, + { + {195, 193, 194, 192}, + {192, 194, 191, 193}, + {194, 192, 194, 192}, + {191, 193, 191, 193}, + }, + { + {196, 194, 195, 193}, + {193, 195, 192, 194}, + {195, 193, 195, 193}, + {192, 194, 192, 194}, + }, + { + {197, 195, 196, 194}, + {194, 196, 193, 195}, + {196, 194, 196, 194}, + {193, 195, 193, 195}, + }, + { + {198, 196, 197, 195}, + {195, 197, 194, 196}, + {197, 195, 197, 195}, + {194, 196, 194, 196}, + }, + { + {199, 197, 198, 196}, + {196, 198, 195, 197}, + {198, 196, 198, 196}, + {195, 197, 195, 197}, + }, + { + {200, 198, 199, 197}, + {197, 199, 196, 198}, + {199, 197, 199, 197}, + {196, 198, 196, 198}, + }, + { + {201, 199, 200, 198}, + {198, 200, 197, 199}, + {200, 198, 200, 198}, + {197, 199, 197, 199}, + }, + { + {202, 200, 201, 199}, + {199, 201, 198, 200}, + {201, 199, 201, 199}, + {198, 200, 198, 200}, + }, + { + {203, 201, 202, 200}, + {200, 202, 199, 201}, + {202, 200, 202, 200}, + {199, 201, 199, 201}, + }, + { + {204, 202, 203, 201}, + {201, 203, 200, 202}, + {203, 201, 203, 201}, + {200, 202, 200, 202}, + }, + { + {205, 203, 204, 202}, + {202, 204, 201, 203}, + {204, 202, 204, 202}, + {201, 203, 201, 203}, + }, + { + {206, 204, 205, 203}, + {203, 205, 202, 204}, + {205, 203, 205, 203}, + {202, 204, 202, 204}, + }, + { + {207, 205, 206, 204}, + {204, 206, 203, 205}, + {206, 204, 206, 204}, + {203, 205, 203, 205}, + }, + { + {208, 206, 207, 205}, + {205, 207, 204, 206}, + {207, 205, 207, 205}, + {204, 206, 204, 206}, + }, + { + {209, 207, 208, 206}, + {206, 208, 205, 207}, + {208, 206, 208, 206}, + {205, 207, 205, 207}, + }, + { + {210, 208, 209, 207}, + {207, 209, 206, 208}, + {209, 207, 209, 207}, + {206, 208, 206, 208}, + }, + { + {211, 209, 210, 208}, + {208, 210, 207, 209}, + {210, 208, 210, 208}, + {207, 209, 207, 209}, + }, + { + {212, 210, 211, 209}, + {209, 211, 208, 210}, + {211, 209, 211, 209}, + {208, 210, 208, 210}, + }, + { + {213, 211, 212, 210}, + {210, 212, 209, 211}, + {212, 210, 212, 210}, + {209, 211, 209, 211}, + }, + { + {214, 212, 213, 211}, + {211, 213, 210, 212}, + {213, 211, 213, 211}, + {210, 212, 210, 212}, + }, + { + {215, 213, 214, 212}, + {212, 214, 211, 213}, + {214, 212, 214, 212}, + {211, 213, 211, 213}, + }, + { + {216, 214, 215, 213}, + {213, 215, 212, 214}, + {215, 213, 215, 213}, + {212, 214, 212, 214}, + }, + { + {217, 215, 216, 214}, + {214, 216, 213, 215}, + {216, 214, 216, 214}, + {213, 215, 213, 215}, + }, + { + {218, 216, 217, 215}, + {215, 217, 214, 216}, + {217, 215, 217, 215}, + {214, 216, 214, 216}, + }, + { + {219, 217, 218, 216}, + {216, 218, 215, 217}, + {218, 216, 218, 216}, + {215, 217, 215, 217}, + }, + { + {220, 218, 219, 217}, + {217, 219, 216, 218}, + {219, 217, 219, 217}, + {216, 218, 216, 218}, + }, + { + {221, 219, 220, 218}, + {218, 220, 217, 219}, + {220, 218, 220, 218}, + {217, 219, 217, 219}, + }, + { + {222, 220, 221, 219}, + {219, 221, 218, 220}, + {221, 219, 221, 219}, + {218, 220, 218, 220}, + }, + { + {223, 221, 222, 220}, + {220, 222, 219, 221}, + {222, 220, 222, 220}, + {219, 221, 219, 221}, + }, + { + {224, 222, 223, 221}, + {221, 223, 220, 222}, + {223, 221, 223, 221}, + {220, 222, 220, 222}, + }, + { + {225, 223, 224, 222}, + {222, 224, 221, 223}, + {224, 222, 224, 222}, + {221, 223, 221, 223}, + }, + { + {226, 224, 225, 223}, + {223, 225, 222, 224}, + {225, 223, 225, 223}, + {222, 224, 222, 224}, + }, + { + {227, 225, 226, 224}, + {224, 226, 223, 225}, + {226, 224, 226, 224}, + {223, 225, 223, 225}, + }, + { + {228, 226, 227, 225}, + {225, 227, 224, 226}, + {227, 225, 227, 225}, + {224, 226, 224, 226}, + }, + { + {229, 227, 228, 226}, + {226, 228, 225, 227}, + {228, 226, 228, 226}, + {225, 227, 225, 227}, + }, + { + {230, 228, 229, 227}, + {227, 229, 226, 228}, + {229, 227, 229, 227}, + {226, 228, 226, 228}, + }, + { + {231, 229, 230, 228}, + {228, 230, 227, 229}, + {230, 228, 230, 228}, + {227, 229, 227, 229}, + }, + { + {232, 230, 231, 229}, + {229, 231, 228, 230}, + {231, 229, 231, 229}, + {228, 230, 228, 230}, + }, + { + {233, 231, 232, 230}, + {230, 232, 229, 231}, + {232, 230, 232, 230}, + {229, 231, 229, 231}, + }, + { + {234, 232, 233, 231}, + {231, 233, 230, 232}, + {233, 231, 233, 231}, + {230, 232, 230, 232}, + }, + { + {235, 233, 234, 232}, + {232, 234, 231, 233}, + {234, 232, 234, 232}, + {231, 233, 231, 233}, + }, + { + {236, 234, 235, 233}, + {233, 235, 232, 234}, + {235, 233, 235, 233}, + {232, 234, 232, 234}, + }, + { + {237, 235, 236, 234}, + {234, 236, 233, 235}, + {236, 234, 236, 234}, + {233, 235, 233, 235}, + }, + { + {238, 236, 237, 235}, + {235, 237, 234, 236}, + {237, 235, 237, 235}, + {234, 236, 234, 236}, + }, + { + {239, 237, 238, 236}, + {236, 238, 235, 237}, + {238, 236, 238, 236}, + {235, 237, 235, 237}, + }, + { + {240, 238, 239, 237}, + {237, 239, 236, 238}, + {239, 237, 239, 237}, + {236, 238, 236, 238}, + }, + { + {241, 239, 240, 238}, + {238, 240, 237, 239}, + {240, 238, 240, 238}, + {237, 239, 237, 239}, + }, + { + {242, 240, 241, 239}, + {239, 241, 238, 240}, + {241, 239, 241, 239}, + {238, 240, 238, 240}, + }, + { + {243, 241, 242, 240}, + {240, 242, 239, 241}, + {242, 240, 242, 240}, + {239, 241, 239, 241}, + }, + { + {244, 242, 243, 241}, + {241, 243, 240, 242}, + {243, 241, 243, 241}, + {240, 242, 240, 242}, + }, + { + {245, 243, 244, 242}, + {242, 244, 241, 243}, + {244, 242, 244, 242}, + {241, 243, 241, 243}, + }, + { + {246, 244, 245, 243}, + {243, 245, 242, 244}, + {245, 243, 245, 243}, + {242, 244, 242, 244}, + }, + { + {247, 245, 246, 244}, + {244, 246, 243, 245}, + {246, 244, 246, 244}, + {243, 245, 243, 245}, + }, + { + {248, 246, 247, 245}, + {245, 247, 244, 246}, + {247, 245, 247, 245}, + {244, 246, 244, 246}, + }, + { + {249, 247, 248, 246}, + {246, 248, 245, 247}, + {248, 246, 248, 246}, + {245, 247, 245, 247}, + }, + { + {250, 248, 249, 247}, + {247, 249, 246, 248}, + {249, 247, 249, 247}, + {246, 248, 246, 248}, + }, + { + {251, 249, 250, 248}, + {248, 250, 247, 249}, + {250, 248, 250, 248}, + {247, 249, 247, 249}, + }, + { + {252, 250, 251, 249}, + {249, 251, 248, 250}, + {251, 249, 251, 249}, + {248, 250, 248, 250}, + }, + { + {253, 251, 252, 250}, + {250, 252, 249, 251}, + {252, 250, 252, 250}, + {249, 251, 249, 251}, + }, + { + {254, 252, 253, 251}, + {251, 253, 250, 252}, + {253, 251, 253, 251}, + {250, 252, 250, 252}, + }, + { + {255, 253, 254, 252}, + {252, 254, 251, 253}, + {254, 252, 254, 252}, + {251, 253, 251, 253}, + }, + { + {255, 254, 255, 253}, + {253, 255, 252, 254}, + {255, 253, 255, 253}, + {252, 254, 252, 254}, + }, + { + {255, 255, 255, 254}, + {254, 255, 253, 255}, + {255, 254, 255, 254}, + {253, 255, 253, 255}, + }, + { + {255, 255, 255, 255}, + {255, 255, 254, 255}, + {255, 255, 255, 255}, + {254, 255, 254, 255}, + }, +}; + + + + +static const uint8_t dithersub_g2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {0, 0}, + }, + { + {4, 2}, + {1, 3}, + }, + { + {5, 3}, + {2, 4}, + }, + { + {6, 4}, + {3, 5}, + }, + { + {7, 5}, + {4, 6}, + }, + { + {8, 6}, + {5, 7}, + }, + { + {9, 7}, + {6, 8}, + }, + { + {10, 8}, + {7, 9}, + }, + { + {11, 9}, + {8, 10}, + }, + { + {12, 10}, + {9, 11}, + }, + { + {13, 11}, + {10, 12}, + }, + { + {14, 12}, + {11, 13}, + }, + { + {15, 13}, + {12, 14}, + }, + { + {16, 14}, + {13, 15}, + }, + { + {17, 15}, + {14, 16}, + }, + { + {18, 16}, + {15, 17}, + }, + { + {19, 17}, + {16, 18}, + }, + { + {20, 18}, + {17, 19}, + }, + { + {21, 19}, + {18, 20}, + }, + { + {22, 20}, + {19, 21}, + }, + { + {23, 21}, + {20, 22}, + }, + { + {24, 22}, + {21, 23}, + }, + { + {25, 23}, + {22, 24}, + }, + { + {26, 24}, + {23, 25}, + }, + { + {27, 25}, + {24, 26}, + }, + { + {28, 26}, + {25, 27}, + }, + { + {29, 27}, + {26, 28}, + }, + { + {30, 28}, + {27, 29}, + }, + { + {31, 29}, + {28, 30}, + }, + { + {32, 30}, + {29, 31}, + }, + { + {33, 31}, + {30, 32}, + }, + { + {34, 32}, + {31, 33}, + }, + { + {35, 33}, + {32, 34}, + }, + { + {36, 34}, + {33, 35}, + }, + { + {37, 35}, + {34, 36}, + }, + { + {38, 36}, + {35, 37}, + }, + { + {39, 37}, + {36, 38}, + }, + { + {40, 38}, + {37, 39}, + }, + { + {41, 39}, + {38, 40}, + }, + { + {42, 40}, + {39, 41}, + }, + { + {43, 41}, + {40, 42}, + }, + { + {44, 42}, + {41, 43}, + }, + { + {45, 43}, + {42, 44}, + }, + { + {46, 44}, + {43, 45}, + }, + { + {47, 45}, + {44, 46}, + }, + { + {48, 46}, + {45, 47}, + }, + { + {49, 47}, + {46, 48}, + }, + { + {50, 48}, + {47, 49}, + }, + { + {51, 49}, + {48, 50}, + }, + { + {52, 50}, + {49, 51}, + }, + { + {53, 51}, + {50, 52}, + }, + { + {54, 52}, + {51, 53}, + }, + { + {55, 53}, + {52, 54}, + }, + { + {56, 54}, + {53, 55}, + }, + { + {57, 55}, + {54, 56}, + }, + { + {58, 56}, + {55, 57}, + }, + { + {59, 57}, + {56, 58}, + }, + { + {60, 58}, + {57, 59}, + }, + { + {61, 59}, + {58, 60}, + }, + { + {62, 60}, + {59, 61}, + }, + { + {63, 61}, + {60, 62}, + }, + { + {64, 62}, + {61, 63}, + }, + { + {65, 63}, + {62, 64}, + }, + { + {66, 64}, + {63, 65}, + }, + { + {67, 65}, + {64, 66}, + }, + { + {68, 66}, + {65, 67}, + }, + { + {69, 67}, + {66, 68}, + }, + { + {70, 68}, + {67, 69}, + }, + { + {71, 69}, + {68, 70}, + }, + { + {72, 70}, + {69, 71}, + }, + { + {73, 71}, + {70, 72}, + }, + { + {74, 72}, + {71, 73}, + }, + { + {75, 73}, + {72, 74}, + }, + { + {76, 74}, + {73, 75}, + }, + { + {77, 75}, + {74, 76}, + }, + { + {78, 76}, + {75, 77}, + }, + { + {79, 77}, + {76, 78}, + }, + { + {80, 78}, + {77, 79}, + }, + { + {81, 79}, + {78, 80}, + }, + { + {82, 80}, + {79, 81}, + }, + { + {83, 81}, + {80, 82}, + }, + { + {84, 82}, + {81, 83}, + }, + { + {85, 83}, + {82, 84}, + }, + { + {86, 84}, + {83, 85}, + }, + { + {87, 85}, + {84, 86}, + }, + { + {88, 86}, + {85, 87}, + }, + { + {89, 87}, + {86, 88}, + }, + { + {90, 88}, + {87, 89}, + }, + { + {91, 89}, + {88, 90}, + }, + { + {92, 90}, + {89, 91}, + }, + { + {93, 91}, + {90, 92}, + }, + { + {94, 92}, + {91, 93}, + }, + { + {95, 93}, + {92, 94}, + }, + { + {96, 94}, + {93, 95}, + }, + { + {97, 95}, + {94, 96}, + }, + { + {98, 96}, + {95, 97}, + }, + { + {99, 97}, + {96, 98}, + }, + { + {100, 98}, + {97, 99}, + }, + { + {101, 99}, + {98, 100}, + }, + { + {102, 100}, + {99, 101}, + }, + { + {103, 101}, + {100, 102}, + }, + { + {104, 102}, + {101, 103}, + }, + { + {105, 103}, + {102, 104}, + }, + { + {106, 104}, + {103, 105}, + }, + { + {107, 105}, + {104, 106}, + }, + { + {108, 106}, + {105, 107}, + }, + { + {109, 107}, + {106, 108}, + }, + { + {110, 108}, + {107, 109}, + }, + { + {111, 109}, + {108, 110}, + }, + { + {112, 110}, + {109, 111}, + }, + { + {113, 111}, + {110, 112}, + }, + { + {114, 112}, + {111, 113}, + }, + { + {115, 113}, + {112, 114}, + }, + { + {116, 114}, + {113, 115}, + }, + { + {117, 115}, + {114, 116}, + }, + { + {118, 116}, + {115, 117}, + }, + { + {119, 117}, + {116, 118}, + }, + { + {120, 118}, + {117, 119}, + }, + { + {121, 119}, + {118, 120}, + }, + { + {122, 120}, + {119, 121}, + }, + { + {123, 121}, + {120, 122}, + }, + { + {124, 122}, + {121, 123}, + }, + { + {125, 123}, + {122, 124}, + }, + { + {126, 124}, + {123, 125}, + }, + { + {127, 125}, + {124, 126}, + }, + { + {128, 126}, + {125, 127}, + }, + { + {129, 127}, + {126, 128}, + }, + { + {130, 128}, + {127, 129}, + }, + { + {131, 129}, + {128, 130}, + }, + { + {132, 130}, + {129, 131}, + }, + { + {133, 131}, + {130, 132}, + }, + { + {134, 132}, + {131, 133}, + }, + { + {135, 133}, + {132, 134}, + }, + { + {136, 134}, + {133, 135}, + }, + { + {137, 135}, + {134, 136}, + }, + { + {138, 136}, + {135, 137}, + }, + { + {139, 137}, + {136, 138}, + }, + { + {140, 138}, + {137, 139}, + }, + { + {141, 139}, + {138, 140}, + }, + { + {142, 140}, + {139, 141}, + }, + { + {143, 141}, + {140, 142}, + }, + { + {144, 142}, + {141, 143}, + }, + { + {145, 143}, + {142, 144}, + }, + { + {146, 144}, + {143, 145}, + }, + { + {147, 145}, + {144, 146}, + }, + { + {148, 146}, + {145, 147}, + }, + { + {149, 147}, + {146, 148}, + }, + { + {150, 148}, + {147, 149}, + }, + { + {151, 149}, + {148, 150}, + }, + { + {152, 150}, + {149, 151}, + }, + { + {153, 151}, + {150, 152}, + }, + { + {154, 152}, + {151, 153}, + }, + { + {155, 153}, + {152, 154}, + }, + { + {156, 154}, + {153, 155}, + }, + { + {157, 155}, + {154, 156}, + }, + { + {158, 156}, + {155, 157}, + }, + { + {159, 157}, + {156, 158}, + }, + { + {160, 158}, + {157, 159}, + }, + { + {161, 159}, + {158, 160}, + }, + { + {162, 160}, + {159, 161}, + }, + { + {163, 161}, + {160, 162}, + }, + { + {164, 162}, + {161, 163}, + }, + { + {165, 163}, + {162, 164}, + }, + { + {166, 164}, + {163, 165}, + }, + { + {167, 165}, + {164, 166}, + }, + { + {168, 166}, + {165, 167}, + }, + { + {169, 167}, + {166, 168}, + }, + { + {170, 168}, + {167, 169}, + }, + { + {171, 169}, + {168, 170}, + }, + { + {172, 170}, + {169, 171}, + }, + { + {173, 171}, + {170, 172}, + }, + { + {174, 172}, + {171, 173}, + }, + { + {175, 173}, + {172, 174}, + }, + { + {176, 174}, + {173, 175}, + }, + { + {177, 175}, + {174, 176}, + }, + { + {178, 176}, + {175, 177}, + }, + { + {179, 177}, + {176, 178}, + }, + { + {180, 178}, + {177, 179}, + }, + { + {181, 179}, + {178, 180}, + }, + { + {182, 180}, + {179, 181}, + }, + { + {183, 181}, + {180, 182}, + }, + { + {184, 182}, + {181, 183}, + }, + { + {185, 183}, + {182, 184}, + }, + { + {186, 184}, + {183, 185}, + }, + { + {187, 185}, + {184, 186}, + }, + { + {188, 186}, + {185, 187}, + }, + { + {189, 187}, + {186, 188}, + }, + { + {190, 188}, + {187, 189}, + }, + { + {191, 189}, + {188, 190}, + }, + { + {192, 190}, + {189, 191}, + }, + { + {193, 191}, + {190, 192}, + }, + { + {194, 192}, + {191, 193}, + }, + { + {195, 193}, + {192, 194}, + }, + { + {196, 194}, + {193, 195}, + }, + { + {197, 195}, + {194, 196}, + }, + { + {198, 196}, + {195, 197}, + }, + { + {199, 197}, + {196, 198}, + }, + { + {200, 198}, + {197, 199}, + }, + { + {201, 199}, + {198, 200}, + }, + { + {202, 200}, + {199, 201}, + }, + { + {203, 201}, + {200, 202}, + }, + { + {204, 202}, + {201, 203}, + }, + { + {205, 203}, + {202, 204}, + }, + { + {206, 204}, + {203, 205}, + }, + { + {207, 205}, + {204, 206}, + }, + { + {208, 206}, + {205, 207}, + }, + { + {209, 207}, + {206, 208}, + }, + { + {210, 208}, + {207, 209}, + }, + { + {211, 209}, + {208, 210}, + }, + { + {212, 210}, + {209, 211}, + }, + { + {213, 211}, + {210, 212}, + }, + { + {214, 212}, + {211, 213}, + }, + { + {215, 213}, + {212, 214}, + }, + { + {216, 214}, + {213, 215}, + }, + { + {217, 215}, + {214, 216}, + }, + { + {218, 216}, + {215, 217}, + }, + { + {219, 217}, + {216, 218}, + }, + { + {220, 218}, + {217, 219}, + }, + { + {221, 219}, + {218, 220}, + }, + { + {222, 220}, + {219, 221}, + }, + { + {223, 221}, + {220, 222}, + }, + { + {224, 222}, + {221, 223}, + }, + { + {225, 223}, + {222, 224}, + }, + { + {226, 224}, + {223, 225}, + }, + { + {227, 225}, + {224, 226}, + }, + { + {228, 226}, + {225, 227}, + }, + { + {229, 227}, + {226, 228}, + }, + { + {230, 228}, + {227, 229}, + }, + { + {231, 229}, + {228, 230}, + }, + { + {232, 230}, + {229, 231}, + }, + { + {233, 231}, + {230, 232}, + }, + { + {234, 232}, + {231, 233}, + }, + { + {235, 233}, + {232, 234}, + }, + { + {236, 234}, + {233, 235}, + }, + { + {237, 235}, + {234, 236}, + }, + { + {238, 236}, + {235, 237}, + }, + { + {239, 237}, + {236, 238}, + }, + { + {240, 238}, + {237, 239}, + }, + { + {241, 239}, + {238, 240}, + }, + { + {242, 240}, + {239, 241}, + }, + { + {243, 241}, + {240, 242}, + }, + { + {244, 242}, + {241, 243}, + }, + { + {245, 243}, + {242, 244}, + }, + { + {246, 244}, + {243, 245}, + }, + { + {247, 245}, + {244, 246}, + }, + { + {248, 246}, + {245, 247}, + }, + { + {249, 247}, + {246, 248}, + }, + { + {250, 248}, + {247, 249}, + }, + { + {251, 249}, + {248, 250}, + }, + { + {252, 250}, + {249, 251}, + }, + { + {253, 251}, + {250, 252}, + }, + { + {254, 252}, + {251, 253}, + }, + { + {255, 253}, + {252, 254}, + }, + { + {255, 254}, + {253, 255}, + }, + { + {255, 255}, + {254, 255}, + }, +}; + + +static const uint8_t dithersub_rb2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {0, 0}, + }, + { + {8, 4}, + {2, 6}, + }, + { + {9, 5}, + {3, 7}, + }, + { + {10, 6}, + {4, 8}, + }, + { + {11, 7}, + {5, 9}, + }, + { + {12, 8}, + {6, 10}, + }, + { + {13, 9}, + {7, 11}, + }, + { + {14, 10}, + {8, 12}, + }, + { + {15, 11}, + {9, 13}, + }, + { + {16, 12}, + {10, 14}, + }, + { + {17, 13}, + {11, 15}, + }, + { + {18, 14}, + {12, 16}, + }, + { + {19, 15}, + {13, 17}, + }, + { + {20, 16}, + {14, 18}, + }, + { + {21, 17}, + {15, 19}, + }, + { + {22, 18}, + {16, 20}, + }, + { + {23, 19}, + {17, 21}, + }, + { + {24, 20}, + {18, 22}, + }, + { + {25, 21}, + {19, 23}, + }, + { + {26, 22}, + {20, 24}, + }, + { + {27, 23}, + {21, 25}, + }, + { + {28, 24}, + {22, 26}, + }, + { + {29, 25}, + {23, 27}, + }, + { + {30, 26}, + {24, 28}, + }, + { + {31, 27}, + {25, 29}, + }, + { + {32, 28}, + {26, 30}, + }, + { + {33, 29}, + {27, 31}, + }, + { + {34, 30}, + {28, 32}, + }, + { + {35, 31}, + {29, 33}, + }, + { + {36, 32}, + {30, 34}, + }, + { + {37, 33}, + {31, 35}, + }, + { + {38, 34}, + {32, 36}, + }, + { + {39, 35}, + {33, 37}, + }, + { + {40, 36}, + {34, 38}, + }, + { + {41, 37}, + {35, 39}, + }, + { + {42, 38}, + {36, 40}, + }, + { + {43, 39}, + {37, 41}, + }, + { + {44, 40}, + {38, 42}, + }, + { + {45, 41}, + {39, 43}, + }, + { + {46, 42}, + {40, 44}, + }, + { + {47, 43}, + {41, 45}, + }, + { + {48, 44}, + {42, 46}, + }, + { + {49, 45}, + {43, 47}, + }, + { + {50, 46}, + {44, 48}, + }, + { + {51, 47}, + {45, 49}, + }, + { + {52, 48}, + {46, 50}, + }, + { + {53, 49}, + {47, 51}, + }, + { + {54, 50}, + {48, 52}, + }, + { + {55, 51}, + {49, 53}, + }, + { + {56, 52}, + {50, 54}, + }, + { + {57, 53}, + {51, 55}, + }, + { + {58, 54}, + {52, 56}, + }, + { + {59, 55}, + {53, 57}, + }, + { + {60, 56}, + {54, 58}, + }, + { + {61, 57}, + {55, 59}, + }, + { + {62, 58}, + {56, 60}, + }, + { + {63, 59}, + {57, 61}, + }, + { + {64, 60}, + {58, 62}, + }, + { + {65, 61}, + {59, 63}, + }, + { + {66, 62}, + {60, 64}, + }, + { + {67, 63}, + {61, 65}, + }, + { + {68, 64}, + {62, 66}, + }, + { + {69, 65}, + {63, 67}, + }, + { + {70, 66}, + {64, 68}, + }, + { + {71, 67}, + {65, 69}, + }, + { + {72, 68}, + {66, 70}, + }, + { + {73, 69}, + {67, 71}, + }, + { + {74, 70}, + {68, 72}, + }, + { + {75, 71}, + {69, 73}, + }, + { + {76, 72}, + {70, 74}, + }, + { + {77, 73}, + {71, 75}, + }, + { + {78, 74}, + {72, 76}, + }, + { + {79, 75}, + {73, 77}, + }, + { + {80, 76}, + {74, 78}, + }, + { + {81, 77}, + {75, 79}, + }, + { + {82, 78}, + {76, 80}, + }, + { + {83, 79}, + {77, 81}, + }, + { + {84, 80}, + {78, 82}, + }, + { + {85, 81}, + {79, 83}, + }, + { + {86, 82}, + {80, 84}, + }, + { + {87, 83}, + {81, 85}, + }, + { + {88, 84}, + {82, 86}, + }, + { + {89, 85}, + {83, 87}, + }, + { + {90, 86}, + {84, 88}, + }, + { + {91, 87}, + {85, 89}, + }, + { + {92, 88}, + {86, 90}, + }, + { + {93, 89}, + {87, 91}, + }, + { + {94, 90}, + {88, 92}, + }, + { + {95, 91}, + {89, 93}, + }, + { + {96, 92}, + {90, 94}, + }, + { + {97, 93}, + {91, 95}, + }, + { + {98, 94}, + {92, 96}, + }, + { + {99, 95}, + {93, 97}, + }, + { + {100, 96}, + {94, 98}, + }, + { + {101, 97}, + {95, 99}, + }, + { + {102, 98}, + {96, 100}, + }, + { + {103, 99}, + {97, 101}, + }, + { + {104, 100}, + {98, 102}, + }, + { + {105, 101}, + {99, 103}, + }, + { + {106, 102}, + {100, 104}, + }, + { + {107, 103}, + {101, 105}, + }, + { + {108, 104}, + {102, 106}, + }, + { + {109, 105}, + {103, 107}, + }, + { + {110, 106}, + {104, 108}, + }, + { + {111, 107}, + {105, 109}, + }, + { + {112, 108}, + {106, 110}, + }, + { + {113, 109}, + {107, 111}, + }, + { + {114, 110}, + {108, 112}, + }, + { + {115, 111}, + {109, 113}, + }, + { + {116, 112}, + {110, 114}, + }, + { + {117, 113}, + {111, 115}, + }, + { + {118, 114}, + {112, 116}, + }, + { + {119, 115}, + {113, 117}, + }, + { + {120, 116}, + {114, 118}, + }, + { + {121, 117}, + {115, 119}, + }, + { + {122, 118}, + {116, 120}, + }, + { + {123, 119}, + {117, 121}, + }, + { + {124, 120}, + {118, 122}, + }, + { + {125, 121}, + {119, 123}, + }, + { + {126, 122}, + {120, 124}, + }, + { + {127, 123}, + {121, 125}, + }, + { + {128, 124}, + {122, 126}, + }, + { + {129, 125}, + {123, 127}, + }, + { + {130, 126}, + {124, 128}, + }, + { + {131, 127}, + {125, 129}, + }, + { + {132, 128}, + {126, 130}, + }, + { + {133, 129}, + {127, 131}, + }, + { + {134, 130}, + {128, 132}, + }, + { + {135, 131}, + {129, 133}, + }, + { + {136, 132}, + {130, 134}, + }, + { + {137, 133}, + {131, 135}, + }, + { + {138, 134}, + {132, 136}, + }, + { + {139, 135}, + {133, 137}, + }, + { + {140, 136}, + {134, 138}, + }, + { + {141, 137}, + {135, 139}, + }, + { + {142, 138}, + {136, 140}, + }, + { + {143, 139}, + {137, 141}, + }, + { + {144, 140}, + {138, 142}, + }, + { + {145, 141}, + {139, 143}, + }, + { + {146, 142}, + {140, 144}, + }, + { + {147, 143}, + {141, 145}, + }, + { + {148, 144}, + {142, 146}, + }, + { + {149, 145}, + {143, 147}, + }, + { + {150, 146}, + {144, 148}, + }, + { + {151, 147}, + {145, 149}, + }, + { + {152, 148}, + {146, 150}, + }, + { + {153, 149}, + {147, 151}, + }, + { + {154, 150}, + {148, 152}, + }, + { + {155, 151}, + {149, 153}, + }, + { + {156, 152}, + {150, 154}, + }, + { + {157, 153}, + {151, 155}, + }, + { + {158, 154}, + {152, 156}, + }, + { + {159, 155}, + {153, 157}, + }, + { + {160, 156}, + {154, 158}, + }, + { + {161, 157}, + {155, 159}, + }, + { + {162, 158}, + {156, 160}, + }, + { + {163, 159}, + {157, 161}, + }, + { + {164, 160}, + {158, 162}, + }, + { + {165, 161}, + {159, 163}, + }, + { + {166, 162}, + {160, 164}, + }, + { + {167, 163}, + {161, 165}, + }, + { + {168, 164}, + {162, 166}, + }, + { + {169, 165}, + {163, 167}, + }, + { + {170, 166}, + {164, 168}, + }, + { + {171, 167}, + {165, 169}, + }, + { + {172, 168}, + {166, 170}, + }, + { + {173, 169}, + {167, 171}, + }, + { + {174, 170}, + {168, 172}, + }, + { + {175, 171}, + {169, 173}, + }, + { + {176, 172}, + {170, 174}, + }, + { + {177, 173}, + {171, 175}, + }, + { + {178, 174}, + {172, 176}, + }, + { + {179, 175}, + {173, 177}, + }, + { + {180, 176}, + {174, 178}, + }, + { + {181, 177}, + {175, 179}, + }, + { + {182, 178}, + {176, 180}, + }, + { + {183, 179}, + {177, 181}, + }, + { + {184, 180}, + {178, 182}, + }, + { + {185, 181}, + {179, 183}, + }, + { + {186, 182}, + {180, 184}, + }, + { + {187, 183}, + {181, 185}, + }, + { + {188, 184}, + {182, 186}, + }, + { + {189, 185}, + {183, 187}, + }, + { + {190, 186}, + {184, 188}, + }, + { + {191, 187}, + {185, 189}, + }, + { + {192, 188}, + {186, 190}, + }, + { + {193, 189}, + {187, 191}, + }, + { + {194, 190}, + {188, 192}, + }, + { + {195, 191}, + {189, 193}, + }, + { + {196, 192}, + {190, 194}, + }, + { + {197, 193}, + {191, 195}, + }, + { + {198, 194}, + {192, 196}, + }, + { + {199, 195}, + {193, 197}, + }, + { + {200, 196}, + {194, 198}, + }, + { + {201, 197}, + {195, 199}, + }, + { + {202, 198}, + {196, 200}, + }, + { + {203, 199}, + {197, 201}, + }, + { + {204, 200}, + {198, 202}, + }, + { + {205, 201}, + {199, 203}, + }, + { + {206, 202}, + {200, 204}, + }, + { + {207, 203}, + {201, 205}, + }, + { + {208, 204}, + {202, 206}, + }, + { + {209, 205}, + {203, 207}, + }, + { + {210, 206}, + {204, 208}, + }, + { + {211, 207}, + {205, 209}, + }, + { + {212, 208}, + {206, 210}, + }, + { + {213, 209}, + {207, 211}, + }, + { + {214, 210}, + {208, 212}, + }, + { + {215, 211}, + {209, 213}, + }, + { + {216, 212}, + {210, 214}, + }, + { + {217, 213}, + {211, 215}, + }, + { + {218, 214}, + {212, 216}, + }, + { + {219, 215}, + {213, 217}, + }, + { + {220, 216}, + {214, 218}, + }, + { + {221, 217}, + {215, 219}, + }, + { + {222, 218}, + {216, 220}, + }, + { + {223, 219}, + {217, 221}, + }, + { + {224, 220}, + {218, 222}, + }, + { + {225, 221}, + {219, 223}, + }, + { + {226, 222}, + {220, 224}, + }, + { + {227, 223}, + {221, 225}, + }, + { + {228, 224}, + {222, 226}, + }, + { + {229, 225}, + {223, 227}, + }, + { + {230, 226}, + {224, 228}, + }, + { + {231, 227}, + {225, 229}, + }, + { + {232, 228}, + {226, 230}, + }, + { + {233, 229}, + {227, 231}, + }, + { + {234, 230}, + {228, 232}, + }, + { + {235, 231}, + {229, 233}, + }, + { + {236, 232}, + {230, 234}, + }, + { + {237, 233}, + {231, 235}, + }, + { + {238, 234}, + {232, 236}, + }, + { + {239, 235}, + {233, 237}, + }, + { + {240, 236}, + {234, 238}, + }, + { + {241, 237}, + {235, 239}, + }, + { + {242, 238}, + {236, 240}, + }, + { + {243, 239}, + {237, 241}, + }, + { + {244, 240}, + {238, 242}, + }, + { + {245, 241}, + {239, 243}, + }, + { + {246, 242}, + {240, 244}, + }, + { + {247, 243}, + {241, 245}, + }, + { + {248, 244}, + {242, 246}, + }, + { + {249, 245}, + {243, 247}, + }, + { + {250, 246}, + {244, 248}, + }, + { + {251, 247}, + {245, 249}, + }, + { + {252, 248}, + {246, 250}, + }, + { + {253, 249}, + {247, 251}, + }, + { + {254, 250}, + {248, 252}, + }, + { + {255, 251}, + {249, 253}, + }, + { + {255, 252}, + {250, 254}, + }, + { + {255, 253}, + {251, 255}, + }, + { + {255, 254}, + {252, 255}, + }, + { + {255, 255}, + {253, 255}, + }, +}; + diff --git a/src/vid_voodoo_fb.c b/src/vid_voodoo_fb.c new file mode 100644 index 0000000..cbf8c17 --- /dev/null +++ b/src/vid_voodoo_fb.c @@ -0,0 +1,447 @@ +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_dither.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "vid_voodoo_fb.h" + +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; + + if (voodoo->type >= VOODOO_BANSHEE) + { + x = addr & 0xffe; + y = (addr >> 12) & 0x3ff; + } + else + { + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + } + + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + + y >>= 1; + } + + if (voodoo->col_tiled) + read_addr = voodoo->fb_read_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + read_addr = voodoo->fb_read_offset + x + (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; +} +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; + + if (voodoo->type >= VOODOO_BANSHEE) + { + x = addr & 0xffe; + y = (addr >> 12) & 0x3ff; + } + else + { + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + } + + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + + y >>= 1; + } + + if (voodoo->col_tiled) + read_addr = voodoo->fb_read_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + 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); +} + +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 = 0; + + colour_data.r = colour_data.g = colour_data.b = colour_data.a = 0; + + 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; + case LFB_FORMAT_DEPTH: + depth_data = val; + write_mask = LFB_WRITE_DEPTH; + break; + + default: + fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode); + } + + if (voodoo->type >= VOODOO_BANSHEE) + { + x = addr & 0xffe; + y = (addr >> 12) & 0x3ff; + } + else + { + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + } + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) + return; + y >>= 1; + } + + + if (voodoo->fb_write_offset == voodoo->params.front_offset && y < 2048) + voodoo->dirty_line[y] = 1; + + if (voodoo->col_tiled) + write_addr = voodoo->fb_write_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + if (voodoo->aux_tiled) + write_addr_aux = voodoo->params.aux_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + 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(new_depth); + } + + 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; + int64_t w_depth = (int64_t)(int32_t)new_depth; + int32_t ia = alpha_data << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); + } + + 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; + } +} + + +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 = 0, 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); + } + + if (voodoo->type >= VOODOO_BANSHEE) + { + x = addr & 0xffe; + y = (addr >> 12) & 0x3ff; + } + else + { + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + } + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) + return; + y >>= 1; + } + + if (voodoo->fb_write_offset == voodoo->params.front_offset && y < 2048) + voodoo->dirty_line[y] = 1; + + if (voodoo->col_tiled) + write_addr = voodoo->fb_write_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + if (voodoo->aux_tiled) + write_addr_aux = voodoo->params.aux_offset + (x & 127) + (x >> 7) * 128*32 + (y & 31) * 128 + (y >> 5) * voodoo->row_width; + else + 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(new_depth); + } + + 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; + int64_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, w_depth); + } + + 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; + } + } +} diff --git a/src/vid_voodoo_fb.h b/src/vid_voodoo_fb.h new file mode 100644 index 0000000..fcb2513 --- /dev/null +++ b/src/vid_voodoo_fb.h @@ -0,0 +1,4 @@ +uint16_t voodoo_fb_readw(uint32_t addr, void *p); +uint32_t voodoo_fb_readl(uint32_t addr, void *p); +void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p); +void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p); diff --git a/src/vid_voodoo_fifo.c b/src/vid_voodoo_fifo.c new file mode 100644 index 0000000..59861f3 --- /dev/null +++ b/src/vid_voodoo_fifo.c @@ -0,0 +1,503 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_banshee_blitter.h" +#include "vid_voodoo_fb.h" +#include "vid_voodoo_fifo.h" +#include "vid_voodoo_reg.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "vid_voodoo_texture.h" + +#define WAKE_DELAY (TIMER_USEC * 100) +void voodoo_wake_fifo_thread(voodoo_t *voodoo) +{ + if (!timer_is_enabled(&voodoo->wake_timer)) + { + /*Don't wake FIFO thread immediately - if we do that it will probably + process one word and go back to sleep, requiring it to be woken on + almost every write. Instead, wait a short while so that the CPU + emulation writes more data so we have more batched-up work.*/ + timer_set_delay_u64(&voodoo->wake_timer, WAKE_DELAY); + } +} + +void voodoo_wake_fifo_thread_now(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +void voodoo_wake_timer(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +void voodoo_queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) +{ + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; + + while (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*/ + if (FIFO_FULL) + voodoo_wake_fifo_thread_now(voodoo); + } + } + + fifo->val = val; + fifo->addr_type = addr_type; + + voodoo->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000) + voodoo_wake_fifo_thread(voodoo); +} + +void voodoo_flush(voodoo_t *voodoo) +{ + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + voodoo_wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + voodoo_wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; +} + +void voodoo_wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo) +{ + voodoo_wake_fifo_thread(voodoo); + if (SLI_ENABLED && voodoo->type != VOODOO_2 && set->voodoos[0] == voodoo) + voodoo_wake_fifo_thread(set->voodoos[1]); +} + +void voodoo_wait_for_swap_complete(voodoo_t *voodoo) +{ + while (voodoo->swap_pending) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + + thread_lock_mutex(voodoo->swap_mutex); + if ((voodoo->swap_pending && voodoo->flush) || FIFO_FULL) + { + /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); + voodoo->front_offset = voodoo->params.front_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_unlock_mutex(voodoo->swap_mutex); + break; + } + else + thread_unlock_mutex(voodoo->swap_mutex); + } +} + + +static uint32_t cmdfifo_get(voodoo_t *voodoo) +{ + uint32_t val; + + if (!voodoo->cmdfifo_in_sub) + { + while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + } + } + + val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; + + if (!voodoo->cmdfifo_in_sub) + voodoo->cmdfifo_depth_rd++; + voodoo->cmdfifo_rp += 4; + +// pclog(" CMDFIFO get %08x\n", val); + return val; +} + +static inline float cmdfifo_get_f(voodoo_t *voodoo) +{ + union + { + uint32_t i; + float f; + } tempif; + + tempif.i = cmdfifo_get(voodoo); + return tempif.f; +} + +enum +{ + CMDFIFO3_PC_MASK_RGB = (1 << 10), + CMDFIFO3_PC_MASK_ALPHA = (1 << 11), + CMDFIFO3_PC_MASK_Z = (1 << 12), + CMDFIFO3_PC_MASK_Wb = (1 << 13), + CMDFIFO3_PC_MASK_W0 = (1 << 14), + CMDFIFO3_PC_MASK_S0_T0 = (1 << 15), + CMDFIFO3_PC_MASK_W1 = (1 << 16), + CMDFIFO3_PC_MASK_S1_T1 = (1 << 17), + + CMDFIFO3_PC = (1 << 28) +}; + +void voodoo_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: + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_REG) + { + voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + case FIFO_WRITEW_FB: + voodoo_wait_for_render_thread_idle(voodoo); + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEW_FB) + { + voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + case FIFO_WRITEL_FB: + voodoo_wait_for_render_thread_idle(voodoo); + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_FB) + { + voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + case FIFO_WRITEL_TEX: + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_TEX) + { + if (!(fifo->addr_type & 0x400000)) + voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + case FIFO_WRITEL_2DREG: + while ((fifo->addr_type & FIFO_TYPE) == FIFO_WRITEL_2DREG) + { + voodoo_2d_reg_writel(voodoo, fifo->addr_type & FIFO_ADDR, fifo->val); + fifo->addr_type = FIFO_INVALID; + voodoo->fifo_read_idx++; + if (FIFO_EMPTY) + break; + fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + } + break; + + default: + fatal("Unknown fifo entry %08x\n", fifo->addr_type); + } + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(voodoo->fifo_not_full_event); + + end_time = timer_read(); + voodoo->time += end_time - start_time; + } + + while (voodoo->cmdfifo_enabled && (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr || voodoo->cmdfifo_in_sub)) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + uint32_t header = cmdfifo_get(voodoo); + uint32_t addr; + uint32_t mask; + int smode; + int num; + int num_verticies; + int v_num; + +// pclog(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); + + switch (header & 7) + { + case 0: +// pclog("CMDFIFO0\n"); + switch ((header >> 3) & 7) + { + case 0: /*NOP*/ + break; + + case 1: /*JSR*/ +// pclog("JSR %08x\n", (header >> 4) & 0xfffffc); + voodoo->cmdfifo_ret_addr = voodoo->cmdfifo_rp; + voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; + voodoo->cmdfifo_in_sub = 1; + break; + + case 2: /*RET*/ + voodoo->cmdfifo_rp = voodoo->cmdfifo_ret_addr; + voodoo->cmdfifo_in_sub = 0; + break; + + case 3: /*JMP local frame buffer*/ + voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; +// pclog("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); + break; + + default: + fatal("Bad CMDFIFO0 %08x\n", header); + } + break; + + case 1: + num = header >> 16; + addr = (header & 0x7ff8) >> 1; +// pclog("CMDFIFO1 addr=%08x\n",addr); + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) + { +// if (voodoo->type != VOODOO_BANSHEE) +// fatal("CMDFIFO1: Not Banshee\n"); +// pclog("CMDFIFO1: write %08x %08x\n", addr, val); + voodoo_2d_reg_writel(voodoo, addr, val); + } + else + { + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + voodoo->cmd_written_fifo++; + voodoo_reg_writel(addr, val, voodoo); + } + + if (header & (1 << 15)) + addr += 4; + } + break; + + case 2: + if (voodoo->type < VOODOO_BANSHEE) + fatal("CMDFIFO2: Not Banshee\n"); + mask = (header >> 3); + addr = 8; + while (mask) + { + if (mask & 1) + { + uint32_t val = cmdfifo_get(voodoo); + + voodoo_2d_reg_writel(voodoo, addr, val); + } + + addr += 4; + mask >>= 1; + } + break; + + case 3: + num = (header >> 29) & 7; + mask = header;//(header >> 10) & 0xff; + smode = (header >> 22) & 0xf; + voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); + num_verticies = (header >> 6) & 0xf; + v_num = 0; + if (((header >> 3) & 7) == 2) + v_num = 1; +// pclog("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff); +// pclog("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7); + + while (num_verticies--) + { + voodoo->verts[3].sVx = cmdfifo_get_f(voodoo); + voodoo->verts[3].sVy = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_RGB) + { + if (header & CMDFIFO3_PC) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo->verts[3].sBlue = (float)(val & 0xff); + voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); + } + else + { + voodoo->verts[3].sRed = cmdfifo_get_f(voodoo); + voodoo->verts[3].sGreen = cmdfifo_get_f(voodoo); + voodoo->verts[3].sBlue = cmdfifo_get_f(voodoo); + } + } + if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC)) + voodoo->verts[3].sAlpha = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_Z) + voodoo->verts[3].sVz = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_Wb) + voodoo->verts[3].sWb = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_W0) + voodoo->verts[3].sW0 = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_S0_T0) + { + voodoo->verts[3].sS0 = cmdfifo_get_f(voodoo); + voodoo->verts[3].sT0 = cmdfifo_get_f(voodoo); + } + if (mask & CMDFIFO3_PC_MASK_W1) + voodoo->verts[3].sW1 = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_S1_T1) + { + voodoo->verts[3].sS1 = cmdfifo_get_f(voodoo); + voodoo->verts[3].sT1 = cmdfifo_get_f(voodoo); + } + if (v_num) + voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); + else + voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); + v_num++; + if (v_num == 3 && ((header >> 3) & 7) == 0) + v_num = 0; + } + break; + + case 4: + num = (header >> 29) & 7; + mask = (header >> 15) & 0x3fff; + addr = (header & 0x7ff8) >> 1; +// pclog("CMDFIFO4 addr=%08x\n",addr); + while (mask) + { + if (mask & 1) + { + uint32_t val = cmdfifo_get(voodoo); + + if ((addr & (1 << 13)) && voodoo->type >= VOODOO_BANSHEE) + { + if (voodoo->type < VOODOO_BANSHEE) + fatal("CMDFIFO1: Not Banshee\n"); +// pclog("CMDFIFO1: write %08x %08x\n", addr, val); + voodoo_2d_reg_writel(voodoo, addr, val); + } + else + { + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + if (voodoo->type >= VOODOO_BANSHEE && (addr & 0x3ff) == SST_swapbufferCMD) + voodoo->cmd_written_fifo++; + voodoo_reg_writel(addr, val, voodoo); + } + } + + addr += 4; + mask >>= 1; + } + while (num--) + cmdfifo_get(voodoo); + break; + + case 5: +// if (header & 0x3fc00000) +// fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); + num = (header >> 3) & 0x7ffff; + addr = cmdfifo_get(voodoo) & 0xffffff; + if (!num) + num = 1; +// pclog("CMDFIFO5 addr=%08x num=%i\n", addr, num); + switch (header >> 30) + { + case 0: /*Linear framebuffer (Banshee)*/ + if (voodoo->texture_present[0][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, 0); + } + if (voodoo->texture_present[1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, 1); + } + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + if (addr <= voodoo->fb_mask) + *(uint32_t *)&voodoo->fb_mem[addr] = val; + addr += 4; + } + break; + case 2: /*Framebuffer*/ + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo_fb_writel(addr, val, voodoo); + addr += 4; + } + break; + case 3: /*Texture*/ + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo_tex_writel(addr, val, voodoo); + addr += 4; + } + break; + + default: + fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp); + } + break; + + default: + fatal("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); + } + + end_time = timer_read(); + voodoo->time += end_time - start_time; + } + voodoo->voodoo_busy = 0; + } +} diff --git a/src/vid_voodoo_fifo.h b/src/vid_voodoo_fifo.h new file mode 100644 index 0000000..c1caeba --- /dev/null +++ b/src/vid_voodoo_fifo.h @@ -0,0 +1,8 @@ +void voodoo_wake_fifo_thread(voodoo_t *voodoo); +void voodoo_wake_fifo_thread_now(voodoo_t *voodoo); +void voodoo_wake_timer(void *p); +void voodoo_queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val); +void voodoo_flush(voodoo_t *voodoo); +void voodoo_wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo); +void voodoo_wait_for_swap_complete(voodoo_t *voodoo); +void voodoo_fifo_thread(void *param); diff --git a/src/vid_voodoo_reg.c b/src/vid_voodoo_reg.c new file mode 100644 index 0000000..63e590b --- /dev/null +++ b/src/vid_voodoo_reg.c @@ -0,0 +1,1321 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_banshee.h" +#include "vid_voodoo_blitter.h" +#include "vid_voodoo_dither.h" +#include "vid_voodoo_fifo.h" +#include "vid_voodoo_reg.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "vid_voodoo_setup.h" +#include "vid_voodoo_texture.h" + +enum +{ + CHIP_FBI = 0x1, + CHIP_TREX0 = 0x2, + CHIP_TREX1 = 0x4, + CHIP_TREX2 = 0x8 +}; + +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_reg_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: + if (voodoo->type >= VOODOO_BANSHEE) + { +// pclog("swapbufferCMD %08x %08x\n", val, voodoo->leftOverlayBuf); + + voodoo_wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + banshee_set_overlay_addr(voodoo->p, voodoo->leftOverlayBuf); + thread_lock_mutex(voodoo->swap_mutex); + if (voodoo->swap_count > 0) + voodoo->swap_count--; + thread_unlock_mutex(voodoo->swap_mutex); + voodoo->frame_count++; + } + else if (TRIPLE_BUFFER) + { + if (voodoo->swap_pending) + voodoo_wait_for_swap_complete(voodoo); + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->leftOverlayBuf; + voodoo->swap_pending = 1; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->leftOverlayBuf; + voodoo->swap_pending = 1; + + voodoo_wait_for_swap_complete(voodoo); + } + + voodoo->cmd_read++; + break; + } + + if (TRIPLE_BUFFER) + { + voodoo->disp_buffer = (voodoo->disp_buffer + 1) % 3; + voodoo->draw_buffer = (voodoo->draw_buffer + 1) % 3; + } + else + { + voodoo->disp_buffer = !voodoo->disp_buffer; + voodoo->draw_buffer = !voodoo->draw_buffer; + } + voodoo_recalc(voodoo); + + voodoo->params.swapbufferCMD = val; + +// pclog("Swap buffer %08x %d %p %i\n", val, voodoo->swap_count, &voodoo->swap_count, (voodoo == voodoo->set->voodoos[1]) ? 1 : 0); +// voodoo->front_offset = params->front_offset; + voodoo_wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + memset(voodoo->dirty_line, 1, sizeof(voodoo->dirty_line)); + voodoo->front_offset = voodoo->params.front_offset; + thread_lock_mutex(voodoo->swap_mutex); + if (voodoo->swap_count > 0) + voodoo->swap_count--; + thread_unlock_mutex(voodoo->swap_mutex); + } + else if (TRIPLE_BUFFER) + { + if (voodoo->swap_pending) + voodoo_wait_for_swap_complete(voodoo); + + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + + voodoo_wait_for_swap_complete(voodoo); + } + 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; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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_TREX1) + voodoo->params.tmu[1].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; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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_TREX1) + voodoo->params.tmu[1].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[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + voodoo_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); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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_TREX1) + voodoo->params.tmu[1].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); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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_TREX1) + voodoo->params.tmu[1].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); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].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_TREX1) + voodoo->params.tmu[1].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[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + voodoo_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: + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipRight = val & 0xfff; + voodoo->params.clipLeft = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipRight = val & 0x3ff; + voodoo->params.clipLeft = (val >> 16) & 0x3ff; + } + break; + case SST_clipLowYHighY: + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipHighY = val & 0xfff; + voodoo->params.clipLowY = (val >> 16) & 0xfff; + } + else + { + 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: + voodoo_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_stipple: + voodoo->params.stipple = val; + 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_clipLeftRight1: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->params.clipRight1 = val & 0xfff; + voodoo->params.clipLeft1 = (val >> 16) & 0xfff; + } + break; + case SST_clipTopBottom1: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->params.clipHighY1 = val & 0xfff; + voodoo->params.clipLowY1 = (val >> 16) & 0xfff; + } + break; + + case SST_colBufferAddr: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->params.draw_offset = val & 0xfffff0; + voodoo->fb_write_offset = voodoo->params.draw_offset; +// pclog("colorBufferAddr=%06x\n", voodoo->params.draw_offset); + } + break; + case SST_colBufferStride: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->col_tiled = val & (1 << 15); + voodoo->params.col_tiled = voodoo->col_tiled; + if (voodoo->col_tiled) + { + voodoo->row_width = (val & 0x7f) * 128*32; +// pclog("colBufferStride tiled = %i bytes, tiled %08x\n", voodoo->row_width, val); + } + else + { + voodoo->row_width = val & 0x3fff; +// pclog("colBufferStride linear = %i bytes, linear\n", voodoo->row_width); + } + voodoo->params.row_width = voodoo->row_width; + } + break; + case SST_auxBufferAddr: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->params.aux_offset = val & 0xfffff0; +// pclog("auxBufferAddr=%06x\n", voodoo->params.aux_offset); + } + break; + case SST_auxBufferStride: + if (voodoo->type >= VOODOO_BANSHEE) + { + voodoo->aux_tiled = val & (1 << 15); + voodoo->params.aux_tiled = voodoo->aux_tiled; + if (voodoo->aux_tiled) + { + voodoo->aux_row_width = (val & 0x7f) * 128*32; +// pclog("auxBufferStride tiled = %i bytes, tiled\n", voodoo->aux_row_width); + } + else + { + voodoo->aux_row_width = val & 0x3fff; +// pclog("auxBufferStride linear = %i bytes, linear\n", voodoo->aux_row_width); + } + voodoo->params.aux_row_width = voodoo->aux_row_width; + } + 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; + if (val & 0x20000000) + { + voodoo->clutData[(val >> 24) & 0x3f].b = 255; + voodoo->clutData[(val >> 24) & 0x3f].g = 255; + voodoo->clutData[(val >> 24) & 0x3f].r = 255; + } + voodoo->clutData_dirty = 1; + break; + + case SST_sSetupMode: + voodoo->sSetupMode = val; + break; + case SST_sVx: + tempif.i = val; + voodoo->verts[3].sVx = tempif.f; +// pclog("sVx[%i]=%f\n", voodoo->vertex_num, tempif.f); + break; + case SST_sVy: + tempif.i = val; + voodoo->verts[3].sVy = tempif.f; +// pclog("sVy[%i]=%f\n", voodoo->vertex_num, tempif.f); + break; + case SST_sARGB: + voodoo->verts[3].sBlue = (float)(val & 0xff); + voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); + break; + case SST_sRed: + tempif.i = val; + voodoo->verts[3].sRed = tempif.f; + break; + case SST_sGreen: + tempif.i = val; + voodoo->verts[3].sGreen = tempif.f; + break; + case SST_sBlue: + tempif.i = val; + voodoo->verts[3].sBlue = tempif.f; + break; + case SST_sAlpha: + tempif.i = val; + voodoo->verts[3].sAlpha = tempif.f; + break; + case SST_sVz: + tempif.i = val; + voodoo->verts[3].sVz = tempif.f; + break; + case SST_sWb: + tempif.i = val; + voodoo->verts[3].sWb = tempif.f; + break; + case SST_sW0: + tempif.i = val; + voodoo->verts[3].sW0 = tempif.f; + break; + case SST_sS0: + tempif.i = val; + voodoo->verts[3].sS0 = tempif.f; + break; + case SST_sT0: + tempif.i = val; + voodoo->verts[3].sT0 = tempif.f; + break; + case SST_sW1: + tempif.i = val; + voodoo->verts[3].sW1 = tempif.f; + break; + case SST_sS1: + tempif.i = val; + voodoo->verts[3].sS1 = tempif.f; + break; + case SST_sT1: + tempif.i = val; + voodoo->verts[3].sT1 = tempif.f; + break; + + case SST_sBeginTriCMD: +// pclog("sBeginTriCMD %i %f\n", voodoo->vertex_num, voodoo->verts[4].sVx); + voodoo->verts[0] = voodoo->verts[3]; + voodoo->verts[1] = voodoo->verts[3]; + voodoo->verts[2] = voodoo->verts[3]; + voodoo->vertex_next_age = 0; + voodoo->vertex_ages[0] = voodoo->vertex_next_age++; + + voodoo->num_verticies = 1; + voodoo->cull_pingpong = 0; + break; + case SST_sDrawTriCMD: +// pclog("sDrawTriCMD %i %i\n", voodoo->num_verticies, voodoo->sSetupMode & SETUPMODE_STRIP_MODE); + /*I'm not sure this is the vertex selection algorithm actually used in the 3dfx + chips, but this works with a number of games that switch between strip and fan + mode in the middle of a run (eg Black & White, Viper Racing)*/ + if (voodoo->vertex_next_age < 3) + { + /*Fewer than three vertices already written, store in next slot*/ + int vertex_nr = voodoo->vertex_next_age; + + voodoo->verts[vertex_nr] = voodoo->verts[3]; + voodoo->vertex_ages[vertex_nr] = voodoo->vertex_next_age++; + } + else + { + int vertex_nr = 0; + + if (!(voodoo->sSetupMode & SETUPMODE_STRIP_MODE)) + { + /*Strip - find oldest vertex*/ + if ((voodoo->vertex_ages[0] < voodoo->vertex_ages[1]) && + (voodoo->vertex_ages[0] < voodoo->vertex_ages[2])) + vertex_nr = 0; + else if ((voodoo->vertex_ages[1] < voodoo->vertex_ages[0]) && + (voodoo->vertex_ages[1] < voodoo->vertex_ages[2])) + vertex_nr = 1; + else + vertex_nr = 2; + } + else + { + /*Fan - find second oldest vertex (ie pivot around oldest)*/ + if ((voodoo->vertex_ages[1] < voodoo->vertex_ages[0]) && + (voodoo->vertex_ages[0] < voodoo->vertex_ages[2])) + vertex_nr = 0; + else if ((voodoo->vertex_ages[2] < voodoo->vertex_ages[0]) && + (voodoo->vertex_ages[0] < voodoo->vertex_ages[1])) + vertex_nr = 0; + else if ((voodoo->vertex_ages[0] < voodoo->vertex_ages[1]) && + (voodoo->vertex_ages[1] < voodoo->vertex_ages[2])) + vertex_nr = 1; + else if ((voodoo->vertex_ages[2] < voodoo->vertex_ages[1]) && + (voodoo->vertex_ages[1] < voodoo->vertex_ages[0])) + vertex_nr = 1; + else + vertex_nr = 2; + } + voodoo->verts[vertex_nr] = voodoo->verts[3]; + voodoo->vertex_ages[vertex_nr] = voodoo->vertex_next_age++; + } + + voodoo->num_verticies++; + if (voodoo->num_verticies == 3) + { +// pclog("triangle_setup\n"); + voodoo_triangle_setup(voodoo); + voodoo->cull_pingpong = !voodoo->cull_pingpong; + + voodoo->num_verticies = 2; + } + break; + + case SST_bltSrcBaseAddr: + voodoo->bltSrcBaseAddr = val & 0x3fffff; + break; + case SST_bltDstBaseAddr: +// pclog("Write bltDstBaseAddr %08x\n", val); + voodoo->bltDstBaseAddr = val & 0x3fffff; + break; + case SST_bltXYStrides: + voodoo->bltSrcXYStride = val & 0xfff; + voodoo->bltDstXYStride = (val >> 16) & 0xfff; +// pclog("Write bltXYStrides %08x\n", val); + break; + case SST_bltSrcChromaRange: + voodoo->bltSrcChromaRange = val; + voodoo->bltSrcChromaMinB = val & 0x1f; + voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f; + voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f; + voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f; + voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f; + voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f; + break; + case SST_bltDstChromaRange: + voodoo->bltDstChromaRange = val; + voodoo->bltDstChromaMinB = val & 0x1f; + voodoo->bltDstChromaMinG = (val >> 5) & 0x3f; + voodoo->bltDstChromaMinR = (val >> 11) & 0x1f; + voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f; + voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f; + voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f; + break; + case SST_bltClipX: + voodoo->bltClipRight = val & 0xfff; + voodoo->bltClipLeft = (val >> 16) & 0xfff; + break; + case SST_bltClipY: + voodoo->bltClipHighY = val & 0xfff; + voodoo->bltClipLowY = (val >> 16) & 0xfff; + break; + + case SST_bltSrcXY: + voodoo->bltSrcX = val & 0x7ff; + voodoo->bltSrcY = (val >> 16) & 0x7ff; + break; + case SST_bltDstXY: +// pclog("Write bltDstXY %08x\n", val); + voodoo->bltDstX = val & 0x7ff; + voodoo->bltDstY = (val >> 16) & 0x7ff; + if (val & (1 << 31)) + voodoo_v2_blit_start(voodoo); + break; + case SST_bltSize: +// pclog("Write bltSize %08x\n", val); + voodoo->bltSizeX = val & 0xfff; + if (voodoo->bltSizeX & 0x800) + voodoo->bltSizeX |= 0xfffff000; + voodoo->bltSizeY = (val >> 16) & 0xfff; + if (voodoo->bltSizeY & 0x800) + voodoo->bltSizeY |= 0xfffff000; + if (val & (1 << 31)) + voodoo_v2_blit_start(voodoo); + break; + case SST_bltRop: + voodoo->bltRop[0] = val & 0xf; + voodoo->bltRop[1] = (val >> 4) & 0xf; + voodoo->bltRop[2] = (val >> 8) & 0xf; + voodoo->bltRop[3] = (val >> 12) & 0xf; + break; + case SST_bltColor: +// pclog("Write bltColor %08x\n", val); + voodoo->bltColorFg = val & 0xffff; + voodoo->bltColorBg = (val >> 16) & 0xffff; + break; + + case SST_bltCommand: + voodoo->bltCommand = val; +// pclog("Write bltCommand %08x\n", val); + if (val & (1 << 31)) + voodoo_v2_blit_start(voodoo); + break; + case SST_bltData: + voodoo_v2_blit_data(voodoo, val); + break; + + case SST_textureMode: + if (chip & CHIP_TREX0) + { + voodoo->params.textureMode[0] = val; + voodoo->params.tformat[0] = (val >> 8) & 0xf; + } + if (chip & CHIP_TREX1) + { + voodoo->params.textureMode[1] = val; + voodoo->params.tformat[1] = (val >> 8) & 0xf; + } + break; + case SST_tLOD: + if (chip & CHIP_TREX0) + { + voodoo->params.tLOD[0] = val; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.tLOD[1] = val; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_tDetail: + if (chip & CHIP_TREX0) + { + voodoo->params.detail_max[0] = val & 0xff; + voodoo->params.detail_bias[0] = (val >> 8) & 0x3f; + voodoo->params.detail_scale[0] = (val >> 14) & 7; + } + if (chip & CHIP_TREX1) + { + voodoo->params.detail_max[1] = val & 0xff; + voodoo->params.detail_bias[1] = (val >> 8) & 0x3f; + voodoo->params.detail_scale[1] = (val >> 14) & 7; + } + break; + case SST_texBaseAddr: + if (chip & CHIP_TREX0) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; +// pclog("texBaseAddr = %08x %08x\n", voodoo->params.texBaseAddr[0], val); + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr1: + if (chip & CHIP_TREX0) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr1[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr1[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr2: + if (chip & CHIP_TREX0) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr2[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr2[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr38: + if (chip & CHIP_TREX0) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr38[0] = val & 0xfffff0; + else + voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + if (voodoo->type >= VOODOO_BANSHEE) + voodoo->params.texBaseAddr38[1] = val & 0xfffff0; + else + voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + + case SST_trexInit1: + if (chip & CHIP_TREX0) + voodoo->trexInit1[0] = val; + if (chip & CHIP_TREX1) + voodoo->trexInit1[1] = val; + break; + + case SST_nccTable0_Y0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + + case SST_nccTable0_I0: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_I2: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q0: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q2: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + if (val & (1 << 31)) + { + int p = (val >> 23) & 0xfe; + if (chip & CHIP_TREX0) + { + voodoo->palette[0][p].u = val | 0xff000000; + voodoo->palette_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->palette[1][p].u = val | 0xff000000; + voodoo->palette_dirty[1] = 1; + } + } + break; + + case SST_nccTable0_I1: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_I3: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q1: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q3: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + if (val & (1 << 31)) + { + int p = ((val >> 23) & 0xfe) | 0x01; + if (chip & CHIP_TREX0) + { + voodoo->palette[0][p].u = val | 0xff000000; + voodoo->palette_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->palette[1][p].u = val | 0xff000000; + voodoo->palette_dirty[1] = 1; + } + } + break; + + case SST_nccTable1_Y0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + + case SST_userIntrCMD: + fatal("userIntrCMD write %08x from FIFO\n", val); + break; + + + case SST_leftOverlayBuf: + voodoo->leftOverlayBuf = val; + break; + } +} diff --git a/src/vid_voodoo_reg.h b/src/vid_voodoo_reg.h new file mode 100644 index 0000000..f3a9418 --- /dev/null +++ b/src/vid_voodoo_reg.h @@ -0,0 +1 @@ +void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p); diff --git a/src/vid_voodoo_regs.h b/src/vid_voodoo_regs.h new file mode 100644 index 0000000..e99241f --- /dev/null +++ b/src/vid_voodoo_regs.h @@ -0,0 +1,694 @@ +enum +{ + SST_status = 0x000, + SST_intrCtrl = 0x004, + + 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_userIntrCMD = 0x13c, + SST_stipple = 0x140, + 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_cmdFifoBaseAddr = 0x1e0, + SST_cmdFifoBump = 0x1e4, + SST_cmdFifoRdPtr = 0x1e8, + SST_cmdFifoAMin = 0x1ec, + SST_cmdFifoAMax = 0x1f0, + SST_cmdFifoDepth = 0x1f4, + SST_cmdFifoHoles = 0x1f8, + + SST_colBufferAddr = 0x1ec, /*Banshee*/ + SST_colBufferStride = 0x1f0, /*Banshee*/ + SST_auxBufferAddr = 0x1f4, /*Banshee*/ + SST_auxBufferStride = 0x1f8, /*Banshee*/ + + SST_clipLeftRight1 = 0x200, /*Banshee*/ + SST_clipTopBottom1 = 0x204, /*Banshee*/ + + SST_fbiInit4 = 0x200, + SST_vRetrace = 0x204, + 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_scrFilter = 0x230, + + SST_hvRetrace = 0x240, + SST_fbiInit5 = 0x244, + SST_fbiInit6 = 0x248, + SST_fbiInit7 = 0x24c, + + SST_swapPending = 0x24c, /*Banshee*/ + SST_leftOverlayBuf = 0x250, /*Banshee*/ + + SST_sSetupMode = 0x260, + SST_sVx = 0x264, + SST_sVy = 0x268, + SST_sARGB = 0x26c, + SST_sRed = 0x270, + SST_sGreen = 0x274, + SST_sBlue = 0x278, + SST_sAlpha = 0x27c, + SST_sVz = 0x280, + SST_sWb = 0x284, + SST_sW0 = 0x288, + SST_sS0 = 0x28c, + SST_sT0 = 0x290, + SST_sW1 = 0x294, + SST_sS1 = 0x298, + SST_sT1 = 0x29c, + + SST_sDrawTriCMD = 0x2a0, + SST_sBeginTriCMD = 0x2a4, + + SST_bltSrcBaseAddr = 0x2c0, + SST_bltDstBaseAddr = 0x2c4, + SST_bltXYStrides = 0x2c8, + SST_bltSrcChromaRange = 0x2cc, + SST_bltDstChromaRange = 0x2d0, + SST_bltClipX = 0x2d4, + SST_bltClipY = 0x2d8, + + SST_bltSrcXY = 0x2e0, + SST_bltDstXY = 0x2e4, + SST_bltSize = 0x2e8, + SST_bltRop = 0x2ec, + SST_bltColor = 0x2f0, + + SST_bltCommand = 0x2f8, + SST_bltData = 0x2fc, + + SST_textureMode = 0x300, + SST_tLOD = 0x304, + SST_tDetail = 0x308, + 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_DITHER_SUB = (1 << 19), + FBZ_DEPTH_SOURCE = (1 << 20), + + 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_APAL8 = 0x6, + TEX_ARGB8332 = 0x8, + TEX_A8Y4I2Q2 = 0x9, + 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), + TEXTUREMODE_TRILINEAR = (1 << 30) +}; + +enum +{ + FBIINIT0_VGA_PASS = 1, + FBIINIT0_GRAPHICS_RESET = (1 << 1) +}; + +enum +{ + FBIINIT1_MULTI_SST = (1 << 2), /*Voodoo Graphics only*/ + FBIINIT1_VIDEO_RESET = (1 << 8), + FBIINIT1_SLI_ENABLE = (1 << 23) +}; + +enum +{ + FBIINIT2_SWAP_ALGORITHM_MASK = (3 << 9) +}; + +enum +{ + FBIINIT2_SWAP_ALGORITHM_DAC_VSYNC = (0 << 9), + FBIINIT2_SWAP_ALGORITHM_DAC_DATA = (1 << 9), + FBIINIT2_SWAP_ALGORITHM_PCI_FIFO_STALL = (2 << 9), + FBIINIT2_SWAP_ALGORITHM_SLI_SYNC = (3 << 9) +}; + +enum +{ + FBIINIT3_REMAP = 1 +}; + +enum +{ + FBIINIT5_MULTI_CVG = (1 << 14) +}; + +enum +{ + FBIINIT7_CMDFIFO_ENABLE = (1 << 8) +}; + +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, + CC_MSELECT_TEXRGB = 5 +}; + +enum +{ + CCA_MSELECT_ZERO = 0, + CCA_MSELECT_ALOCAL = 1, + CCA_MSELECT_AOTHER = 2, + CCA_MSELECT_ALOCAL2 = 3, + CCA_MSELECT_TEX = 4 +}; + +enum +{ + TC_MSELECT_ZERO = 0, + TC_MSELECT_CLOCAL = 1, + TC_MSELECT_AOTHER = 2, + TC_MSELECT_ALOCAL = 3, + TC_MSELECT_DETAIL = 4, + TC_MSELECT_LOD_FRAC = 5 +}; + +enum +{ + TCA_MSELECT_ZERO = 0, + TCA_MSELECT_CLOCAL = 1, + TCA_MSELECT_AOTHER = 2, + TCA_MSELECT_ALOCAL = 3, + TCA_MSELECT_DETAIL = 4, + TCA_MSELECT_LOD_FRAC = 5 +}; + +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_W = 0x18, + FOG_CONSTANT = 0x20 +}; + +enum +{ + LOD_ODD = (1 << 18), + LOD_SPLIT = (1 << 19), + LOD_S_IS_WIDER = (1 << 20), + LOD_TMULTIBASEADDR = (1 << 24), + LOD_TMIRROR_S = (1 << 28), + LOD_TMIRROR_T = (1 << 29) +}; +enum +{ + CMD_INVALID = 0, + CMD_DRAWTRIANGLE, + CMD_FASTFILL, + CMD_SWAPBUF +}; + +enum +{ + FBZCP_TEXTURE_ENABLED = (1 << 27) +}; + +enum +{ + BLTCMD_SRC_TILED = (1 << 14), + BLTCMD_DST_TILED = (1 << 15) +}; + +enum +{ + INITENABLE_SLI_MASTER_SLAVE = (1 << 11) +}; + +enum +{ + SETUPMODE_RGB = (1 << 0), + SETUPMODE_ALPHA = (1 << 1), + SETUPMODE_Z = (1 << 2), + SETUPMODE_Wb = (1 << 3), + SETUPMODE_W0 = (1 << 4), + SETUPMODE_S0_T0 = (1 << 5), + SETUPMODE_W1 = (1 << 6), + SETUPMODE_S1_T1 = (1 << 7), + + SETUPMODE_STRIP_MODE = (1 << 16), + SETUPMODE_CULLING_ENABLE = (1 << 17), + SETUPMODE_CULLING_SIGN = (1 << 18), + SETUPMODE_DISABLE_PINGPONG = (1 << 19) +}; + +#define TEXTUREMODE_MASK 0x3ffff000 +#define TEXTUREMODE_PASSTHROUGH 0 + +#define TEXTUREMODE_LOCAL_MASK 0x00643000 +#define TEXTUREMODE_LOCAL 0x00241000 + + +#define SLI_ENABLED (voodoo->fbiInit1 & FBIINIT1_SLI_ENABLE) +#define TRIPLE_BUFFER ((voodoo->fbiInit2 & 0x10) || (voodoo->fbiInit5 & 0x600) == 0x400) + + +#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 tc_zero_other (params->textureMode[0] & (1 << 12)) +#define tc_sub_clocal (params->textureMode[0] & (1 << 13)) +#define tc_mselect ((params->textureMode[0] >> 14) & 7) +#define tc_reverse_blend (params->textureMode[0] & (1 << 17)) +#define tc_add_clocal (params->textureMode[0] & (1 << 18)) +#define tc_add_alocal (params->textureMode[0] & (1 << 19)) +#define tc_invert_output (params->textureMode[0] & (1 << 20)) +#define tca_zero_other (params->textureMode[0] & (1 << 21)) +#define tca_sub_clocal (params->textureMode[0] & (1 << 22)) +#define tca_mselect ((params->textureMode[0] >> 23) & 7) +#define tca_reverse_blend (params->textureMode[0] & (1 << 26)) +#define tca_add_clocal (params->textureMode[0] & (1 << 27)) +#define tca_add_alocal (params->textureMode[0] & (1 << 28)) +#define tca_invert_output (params->textureMode[0] & (1 << 29)) + +#define tc_sub_clocal_1 (params->textureMode[1] & (1 << 13)) +#define tc_mselect_1 ((params->textureMode[1] >> 14) & 7) +#define tc_reverse_blend_1 (params->textureMode[1] & (1 << 17)) +#define tc_add_clocal_1 (params->textureMode[1] & (1 << 18)) +#define tc_add_alocal_1 (params->textureMode[1] & (1 << 19)) +#define tca_sub_clocal_1 (params->textureMode[1] & (1 << 22)) +#define tca_mselect_1 ((params->textureMode[1] >> 23) & 7) +#define tca_reverse_blend_1 (params->textureMode[1] & (1 << 26)) +#define tca_add_clocal_1 (params->textureMode[1] & (1 << 27)) +#define tca_add_alocal_1 (params->textureMode[1] & (1 << 28)) + +#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) +#define dithersub (params->fbzMode & FBZ_DITHER_SUB) + diff --git a/src/vid_voodoo_render.c b/src/vid_voodoo_render.c new file mode 100644 index 0000000..420e396 --- /dev/null +++ b/src/vid_voodoo_render.c @@ -0,0 +1,1655 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_dither.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "vid_voodoo_texture.h" + +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[2]; + int64_t base_w; + int lod; + int lod_min[2], lod_max[2]; + int dx1, dx2; + int y, yend, ydir; + int32_t dxAB, dxAC, dxBC; + int tex_b[2], tex_g[2], tex_r[2], tex_a[2]; + int tex_s, tex_t; + int clamp_s[2], clamp_t[2]; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t *tex[2][LOD_MAX+1]; + int tformat; + + int *tex_w_mask[2]; + int *tex_h_mask[2]; + int *tex_shift[2]; + int *tex_lod[2]; + + 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 tmu1_s, tmu1_t; + int64_t tmu1_w; + int64_t w; + + int pixel_count, texel_count; + int x, x2, x_tiled; + + uint32_t w_depth; + + float log_temp; + uint32_t ebp_store; + uint32_t texBaseAddr; + + int lod_frac[2]; +} 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 voodoo_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, int tmu) +{ + uint32_t dat; + + if (texture_state->s & ~texture_state->w_mask) + { + if (state->clamp_s[tmu]) + { + 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[tmu]) + { + 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; + } + + dat = state->tex[tmu][state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; + + state->tex_b[tmu] = dat & 0xff; + state->tex_g[tmu] = (dat >> 8) & 0xff; + state->tex_r[tmu] = (dat >> 16) & 0xff; + state->tex_a[tmu] = (dat >> 24) & 0xff; +} + +#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, int tmu, int x) +{ + rgba_u 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[tmu]) + { + 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[tmu]) + { + if (_t < 0) + _t = 0; + if (_t > texture_state->h_mask) + _t = texture_state->h_mask; + } + else + _t &= texture_state->h_mask; + } + dat[c].u = state->tex[tmu][state->lod][_s + (_t << texture_state->tex_shift)]; + } + } + else + { + dat[0].u = state->tex[tmu][state->lod][s + (t << texture_state->tex_shift)]; + dat[1].u = state->tex[tmu][state->lod][s + 1 + (t << texture_state->tex_shift)]; + dat[2].u = state->tex[tmu][state->lod][s + ((t + 1) << texture_state->tex_shift)]; + dat[3].u = state->tex[tmu][state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; + } + + state->tex_r[tmu] = (dat[0].rgba.r * d[0] + dat[1].rgba.r * d[1] + dat[2].rgba.r * d[2] + dat[3].rgba.r * d[3]) >> 8; + state->tex_g[tmu] = (dat[0].rgba.g * d[0] + dat[1].rgba.g * d[1] + dat[2].rgba.g * d[2] + dat[3].rgba.g * d[3]) >> 8; + state->tex_b[tmu] = (dat[0].rgba.b * d[0] + dat[1].rgba.b * d[1] + dat[2].rgba.b * d[2] + dat[3].rgba.b * d[3]) >> 8; + state->tex_a[tmu] = (dat[0].rgba.a * d[0] + dat[1].rgba.a * d[1] + dat[2].rgba.a * d[2] + dat[3].rgba.a * d[3]) >> 8; +} + +static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) +{ + voodoo_texture_state_t texture_state; + int d[4]; + int s, t; + int tex_lod = state->tex_lod[tmu][state->lod]; + + texture_state.w_mask = state->tex_w_mask[tmu][state->lod]; + texture_state.h_mask = state->tex_h_mask[tmu][state->lod]; + texture_state.tex_shift = 8 - tex_lod; + + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + if (state->tex_s & 0x1000) + state->tex_s = ~state->tex_s; + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + if (state->tex_t & 0x1000) + state->tex_t = ~state->tex_t; + } + + if (voodoo->bilinear_enabled && params->textureMode[tmu] & 6) + { + int _ds, dt; + + state->tex_s -= 1 << (3+tex_lod); + state->tex_t -= 1 << (3+tex_lod); + + s = state->tex_s >> tex_lod; + t = state->tex_t >> tex_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, tmu, x); + + +/* 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+tex_lod); + t = state->tex_t >> (4+tex_lod); + + texture_state.s = s; + texture_state.t = t; + tex_read(state, &texture_state, tmu); + +/* 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;*/ + } +} + +static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) +{ + if (params->textureMode[tmu] & 1) + { + int64_t _w = 0; + + if (tmu) + { + if (state->tmu1_w) + _w = (int64_t)((1ULL << 48) / state->tmu1_w); + state->tex_s = (int32_t)(((((state->tmu1_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + state->tex_t = (int32_t)(((((state->tmu1_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + } + else + { + if (state->tmu0_w) + _w = (int64_t)((1ULL << 48) / state->tmu0_w); + state->tex_s = (int32_t)(((((state->tmu0_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + state->tex_t = (int32_t)(((((state->tmu0_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + } + + state->lod = state->tmu[tmu].lod + (fastlog(_w) - (19 << 8)); + } + else + { + if (tmu) + { + state->tex_s = (int32_t)(state->tmu1_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu1_t >> (14+14)); + } + 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[tmu].lod; + } + + if (state->lod < state->lod_min[tmu]) + state->lod = state->lod_min[tmu]; + else if (state->lod > state->lod_max[tmu]) + state->lod = state->lod_max[tmu]; + state->lod_frac[tmu] = state->lod & 0xff; + state->lod >>= 8; + + voodoo_get_texture(voodoo, params, state, tmu, x); +} + + +/*Perform texture fetch and blending for both TMUs*/ +static inline void voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x) +{ + int r,g,b,a; + int c_reverse, a_reverse; +// int c_reverse1, a_reverse1; + int factor_r = 0, factor_g = 0, factor_b = 0, factor_a = 0; + + voodoo_tmu_fetch(voodoo, params, state, 1, x); + + if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) + { + c_reverse = tc_reverse_blend; + a_reverse = tca_reverse_blend; + } + else + { + c_reverse = !tc_reverse_blend; + a_reverse = !tca_reverse_blend; + } +/* c_reverse1 = c_reverse; + a_reverse1 = a_reverse;*/ + if (tc_sub_clocal_1) + { + switch (tc_mselect_1) + { + case TC_MSELECT_ZERO: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_CLOCAL: + factor_r = state->tex_r[1]; + factor_g = state->tex_g[1]; + factor_b = state->tex_b[1]; + break; + case TC_MSELECT_AOTHER: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_ALOCAL: + factor_r = factor_g = factor_b = state->tex_a[1]; + break; + case TC_MSELECT_DETAIL: + factor_r = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; + if (factor_r > params->detail_max[1]) + factor_r = params->detail_max[1]; + factor_g = factor_b = factor_r; + break; + case TC_MSELECT_LOD_FRAC: + factor_r = factor_g = factor_b = state->lod_frac[1]; + break; + } + if (!c_reverse) + { + r = (-state->tex_r[1] * (factor_r + 1)) >> 8; + g = (-state->tex_g[1] * (factor_g + 1)) >> 8; + b = (-state->tex_b[1] * (factor_b + 1)) >> 8; + } + else + { + r = (-state->tex_r[1] * ((factor_r^0xff) + 1)) >> 8; + g = (-state->tex_g[1] * ((factor_g^0xff) + 1)) >> 8; + b = (-state->tex_b[1] * ((factor_b^0xff) + 1)) >> 8; + } + if (tc_add_clocal_1) + { + r += state->tex_r[1]; + g += state->tex_g[1]; + b += state->tex_b[1]; + } + else if (tc_add_alocal_1) + { + r += state->tex_a[1]; + g += state->tex_a[1]; + b += state->tex_a[1]; + } + state->tex_r[1] = CLAMP(r); + state->tex_g[1] = CLAMP(g); + state->tex_b[1] = CLAMP(b); + } + if (tca_sub_clocal_1) + { + switch (tca_mselect_1) + { + case TCA_MSELECT_ZERO: + factor_a = 0; + break; + case TCA_MSELECT_CLOCAL: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_AOTHER: + factor_a = 0; + break; + case TCA_MSELECT_ALOCAL: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_DETAIL: + factor_a = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; + if (factor_a > params->detail_max[1]) + factor_a = params->detail_max[1]; + break; + case TCA_MSELECT_LOD_FRAC: + factor_a = state->lod_frac[1]; + break; + } + if (!a_reverse) + a = (-state->tex_a[1] * ((factor_a ^ 0xff) + 1)) >> 8; + else + a = (-state->tex_a[1] * (factor_a + 1)) >> 8; + if (tca_add_clocal_1 || tca_add_alocal_1) + a += state->tex_a[1]; + state->tex_a[1] = CLAMP(a); + } + + + voodoo_tmu_fetch(voodoo, params, state, 0, x); + + if ((params->textureMode[0] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) + { + c_reverse = tc_reverse_blend; + a_reverse = tca_reverse_blend; + } + else + { + c_reverse = !tc_reverse_blend; + a_reverse = !tca_reverse_blend; + } + + if (!tc_zero_other) + { + r = state->tex_r[1]; + g = state->tex_g[1]; + b = state->tex_b[1]; + } + else + r = g = b = 0; + if (tc_sub_clocal) + { + r -= state->tex_r[0]; + g -= state->tex_g[0]; + b -= state->tex_b[0]; + } + switch (tc_mselect) + { + case TC_MSELECT_ZERO: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_CLOCAL: + factor_r = state->tex_r[0]; + factor_g = state->tex_g[0]; + factor_b = state->tex_b[0]; + break; + case TC_MSELECT_AOTHER: + factor_r = factor_g = factor_b = state->tex_a[1]; + break; + case TC_MSELECT_ALOCAL: + factor_r = factor_g = factor_b = state->tex_a[0]; + break; + case TC_MSELECT_DETAIL: + factor_r = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; + if (factor_r > params->detail_max[0]) + factor_r = params->detail_max[0]; + factor_g = factor_b = factor_r; + break; + case TC_MSELECT_LOD_FRAC: + factor_r = factor_g = factor_b = state->lod_frac[0]; + break; + } + if (!c_reverse) + { + r = (r * (factor_r + 1)) >> 8; + g = (g * (factor_g + 1)) >> 8; + b = (b * (factor_b + 1)) >> 8; + } + else + { + r = (r * ((factor_r^0xff) + 1)) >> 8; + g = (g * ((factor_g^0xff) + 1)) >> 8; + b = (b * ((factor_b^0xff) + 1)) >> 8; + } + if (tc_add_clocal) + { + r += state->tex_r[0]; + g += state->tex_g[0]; + b += state->tex_b[0]; + } + else if (tc_add_alocal) + { + r += state->tex_a[0]; + g += state->tex_a[0]; + b += state->tex_a[0]; + } + + if (!tca_zero_other) + a = state->tex_a[1]; + else + a = 0; + if (tca_sub_clocal) + a -= state->tex_a[0]; + switch (tca_mselect) + { + case TCA_MSELECT_ZERO: + factor_a = 0; + break; + case TCA_MSELECT_CLOCAL: + factor_a = state->tex_a[0]; + break; + case TCA_MSELECT_AOTHER: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_ALOCAL: + factor_a = state->tex_a[0]; + break; + case TCA_MSELECT_DETAIL: + factor_a = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; + if (factor_a > params->detail_max[0]) + factor_a = params->detail_max[0]; + break; + case TCA_MSELECT_LOD_FRAC: + factor_a = state->lod_frac[0]; + break; + } + if (a_reverse) + a = (a * ((factor_a ^ 0xff) + 1)) >> 8; + else + a = (a * (factor_a + 1)) >> 8; + if (tca_add_clocal || tca_add_alocal) + a += state->tex_a[0]; + + + state->tex_r[0] = CLAMP(r); + state->tex_g[0] = CLAMP(g); + state->tex_b[0] = CLAMP(b); + state->tex_a[0] = CLAMP(a); + + if (tc_invert_output) + { + state->tex_r[0] ^= 0xff; + state->tex_g[0] ^= 0xff; + state->tex_b[0] ^= 0xff; + } + if (tca_invert_output) + state->tex_a[0] ^= 0xff; +} + +#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 +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 texels; + int c; +#ifndef NO_CODEGEN + uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y); +#endif + int y_diff = SLI_ENABLED ? 2 : 1; + int y_origin = (voodoo->type >= VOODOO_BANSHEE) ? voodoo->y_origin_swap : (voodoo->v_disp-1); + + if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || + (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) + texels = 1; + else + texels = 2; + + state->clamp_s[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPS; + state->clamp_t[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPT; + state->clamp_s[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPS; + state->clamp_t[1] = params->textureMode[1] & 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[0][c] = &voodoo->texture_cache[0][params->tex_entry[0]].data[texture_offset[c]]; + state->tex[1][c] = &voodoo->texture_cache[1][params->tex_entry[1]].data[texture_offset[c]]; + } + + state->tformat = params->tformat[0]; + + state->tex_w_mask[0] = params->tex_w_mask[0]; + state->tex_h_mask[0] = params->tex_h_mask[0]; + state->tex_shift[0] = params->tex_shift[0]; + state->tex_lod[0] = params->tex_lod[0]; + state->tex_w_mask[1] = params->tex_w_mask[1]; + state->tex_h_mask[1] = params->tex_h_mask[1]; + state->tex_shift[1] = params->tex_shift[1]; + state->tex_lod[1] = params->tex_lod[1]; + + 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->tmu[1].base_s += params->tmu[1].dSdY*dy; + state->tmu[1].base_t += params->tmu[1].dTdY*dy; + state->tmu[1].base_w += params->tmu[1].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--; + + if (SLI_ENABLED) + { + int test_y; + + if (params->fbzMode & (1 << 17)) + test_y = y_origin - state->y; + else + test_y = state->y; + + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (test_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(test_y & 1))) + { + state->y++; + + 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->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + } +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even); + else + voodoo_draw = NULL; +#endif + + if (voodoo_output) + pclog("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC); +// pclog("Start %i %i\n", ystart, voodoo->fbzMode & (1 << 17)); + + for (; state->y < yend; state->y += y_diff) + { + 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->tmu1_s = state->tmu[1].base_s; + state->tmu1_t = state->tmu[1].base_t; + state->tmu1_w = state->tmu[1].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 = y_origin - (real_y >> 4); + else + real_y >>= 4; + + if (SLI_ENABLED) + { + if (((real_y >> 1) & voodoo->odd_even_mask) != odd_even) + goto next_line; + } + else + { + 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 (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); + + 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->tmu1_s += (params->tmu[1].dSdX * dx); + state->tmu1_t += (params->tmu[1].dTdX * dx); + state->tmu1_w += (params->tmu[1].dWdX * dx); + state->w += (params->dWdX * dx); + + 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)); + + 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->tmu1_s += params->tmu[1].dSdX*dx; + state->tmu1_t += params->tmu[1].dTdX*dx; + state->tmu1_w += params->tmu[1].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipLeft; + } + if (x2 >= params->clipRight) + x2 = params->clipRight-1; + } + else + { + if (x >= params->clipRight) + { + int dx = (params->clipRight-1) - 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->tmu1_s += params->tmu[1].dSdX*dx; + state->tmu1_t += params->tmu[1].dTdX*dx; + state->tmu1_w += params->tmu[1].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipRight-1; + } + 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; + + if (SLI_ENABLED) + { + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + ((real_y >> 1) * params->row_width)]; + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + ((real_y >> 1) * params->row_width)) & voodoo->fb_mask]; + } + else + { + if (params->col_tiled) + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y >> 5) * params->row_width + (real_y & 31) * 128]; + else + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y * params->row_width)]; + if (params->aux_tiled) + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y >> 5) * params->aux_row_width + (real_y & 31) * 128) & voodoo->fb_mask]; + else + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y * params->row_width)) & voodoo->fb_mask]; + } + + 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); + + state->pixel_count = 0; + state->texel_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 + { + int x_tiled = (x & 63) | ((x >> 6) * 128*32/2); + start_x = x; + state->x = x; + voodoo->pixel_count[odd_even]++; + voodoo->texel_count[odd_even] += texels; + voodoo->fbiPixelsIn++; + + if (voodoo_output) + pclog(" X=%03i T=%08x\n", x, state->tmu0_t); +// 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 = 0, src_g = 0, src_b = 0, src_a = 0; + int msel_r, msel_g, msel_b, msel_a; + uint8_t dest_r, dest_g, dest_b, dest_a; + uint16_t 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 = voodoo_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 = CLAMP16(new_depth + (int16_t)params->zaColor); + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = voodoo->params.aux_tiled ? aux_mem[x_tiled] : aux_mem[x]; + + DEPTH_TEST((params->fbzMode & FBZ_DEPTH_SOURCE) ? (params->zaColor & 0xffff) : new_depth); + } + + dat = voodoo->params.col_tiled ? fb_mem[x_tiled] : 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[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) + { + /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ + voodoo_tmu_fetch(voodoo, params, state, 0, x); + } + else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) + { + /*TMU0 in pass-through mode, only sample TMU1*/ + voodoo_tmu_fetch(voodoo, params, state, 1, x); + + state->tex_r[0] = state->tex_r[1]; + state->tex_g[0] = state->tex_g[1]; + state->tex_b[0] = state->tex_b[1]; + state->tex_a[0] = state->tex_a[1]; + } + else + { + voodoo_tmu_fetch_and_blend(voodoo, params, state, x); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + state->tex_r[0] == params->chromaKey_r && + state->tex_g[0] == params->chromaKey_g && + state->tex_b[0] == params->chromaKey_b) + { + voodoo->fbiChromaFail++; + goto skip_pixel; + } + } + + if (voodoo->trexInit1[0] & (1 << 18)) + { + state->tex_r[0] = state->tex_g[0] = 0; + state->tex_b[0] = voodoo->tmuConfig; + } + + if (cc_localselect_override) + sel = (state->tex_a[0] & 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[0]; + cother_g = state->tex_g[0]; + cother_b = state->tex_b[0]; + 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: + fatal("Bad cca_localselect %i\n", cca_localselect); + 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[0]; + break; + case A_SEL_COLOR1: + aother = (params->color1 >> 24) & 0xff; + break; + default: + fatal("Bad a_sel %i\n", a_sel); + 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[0]; + msel_g = state->tex_a[0]; + msel_b = state->tex_a[0]; + break; + case CC_MSELECT_TEXRGB: + msel_r = state->tex_r[0]; + msel_g = state->tex_g[0]; + msel_b = state->tex_b[0]; + break; + + default: + fatal("Bad cc_mselect %i\n", cc_mselect); + 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[0]; + break; + + default: + fatal("Bad cca_mselect %i\n", cca_mselect); + 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; + case 0: + break; + default: + fatal("Bad cc_add %i\n", cc_add); + } + + 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, state->w); + + if (params->alphaMode & 1) + ALPHA_TEST(src_a); + + if (params->alphaMode & (1 << 4)) + { + if (dithersub && !dither2x2 && voodoo->dithersub_enabled) + { + dest_r = dithersub_rb[dest_r][real_y & 3][x & 3]; + dest_g = dithersub_g [dest_g][real_y & 3][x & 3]; + dest_b = dithersub_rb[dest_b][real_y & 3][x & 3]; + } + if (dithersub && dither2x2 && voodoo->dithersub_enabled) + { + dest_r = dithersub_rb2x2[dest_r][real_y & 1][x & 1]; + dest_g = dithersub_g2x2 [dest_g][real_y & 1][x & 1]; + dest_b = dithersub_rb2x2[dest_b][real_y & 1][x & 1]; + } + 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) + { + if (voodoo->params.col_tiled) + fb_mem[x_tiled] = src_b | (src_g << 5) | (src_r << 11); + else + fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); + } + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) + { + if (voodoo->params.aux_tiled) + aux_mem[x_tiled] = new_depth; + else + 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->tmu1_s += params->tmu[1].dSdX; + state->tmu1_t += params->tmu[1].dTdX; + state->tmu1_w += params->tmu[1].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->tmu1_s -= params->tmu[1].dSdX; + state->tmu1_t -= params->tmu[1].dTdX; + state->tmu1_w -= params->tmu[1].dWdX; + state->w -= params->dWdX; + } + + x += state->xdir; + } while (start_x != x2); + + voodoo->pixel_count[odd_even] += state->pixel_count; + voodoo->texel_count[odd_even] += state->texel_count; + voodoo->fbiPixelsIn += state->pixel_count; + + if (voodoo->params.draw_offset == voodoo->params.front_offset && (real_y >> 1) < 2048) + voodoo->dirty_line[real_y >> 1] = 1; + +next_line: + if (SLI_ENABLED) + { + 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->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + 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->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + + voodoo->texture_cache[0][params->tex_entry[0]].refcount_r[odd_even]++; + voodoo->texture_cache[1][params->tex_entry[1]].refcount_r[odd_even]++; +} + +void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) +{ + voodoo_state_t state; + int vertexAy_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,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%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] : 0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode);*/ + + 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.tmu[1].base_s = params->tmu[1].startS; + state.tmu[1].base_t = params->tmu[1].startT; + state.tmu[1].base_w = params->tmu[1].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.tmu[1].base_s += (dx*params->tmu[1].dSdX + dy*params->tmu[1].dSdY) >> 4; + state.tmu[1].base_t += (dx*params->tmu[1].dTdX + dy*params->tmu[1].dTdY) >> 4; + state.tmu[1].base_w += (dx*params->tmu[1].dWdX + dy*params->tmu[1].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; + 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[0] = (params->tLOD[0] & 0x3f) << 6; + state.lod_max[0] = ((params->tLOD[0] >> 6) & 0x3f) << 6; + if (state.lod_max[0] > 0x800) + state.lod_max[0] = 0x800; + state.lod_min[1] = (params->tLOD[1] & 0x3f) << 6; + state.lod_max[1] = ((params->tLOD[1] >> 6) & 0x3f) << 6; + if (state.lod_max[1] > 0x800) + state.lod_max[1] = 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[0] >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[0].lod = LOD + (lodbias << 6); + + + tempdx = (params->tmu[1].dSdX >> 14) * (params->tmu[1].dSdX >> 14) + (params->tmu[1].dTdX >> 14) * (params->tmu[1].dTdX >> 14); + tempdy = (params->tmu[1].dSdY >> 14) * (params->tmu[1].dSdY >> 14) + (params->tmu[1].dTdY >> 14) * (params->tmu[1].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD[1] >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[1].lod = LOD + (lodbias << 6); + + + voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); +} + + +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 (!PARAM_EMPTY(odd_even)) + { + 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 (PARAM_ENTRIES(odd_even) > (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; + } +} + +void voodoo_render_thread_1(void *param) +{ + render_thread(param, 0); +} +void voodoo_render_thread_2(void *param) +{ + render_thread(param, 1); +} +void voodoo_render_thread_3(void *param) +{ + render_thread(param, 2); +} +void voodoo_render_thread_4(void *param) +{ + render_thread(param, 3); +} + +void voodoo_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(0) || (voodoo->render_threads >= 2 && PARAM_FULL(1)) || + (voodoo->render_threads == 4 && (PARAM_FULL(2) || PARAM_FULL(3)))) + { + thread_reset_event(voodoo->render_not_full_event[0]); + if (voodoo->render_threads >= 2) + thread_reset_event(voodoo->render_not_full_event[1]); + if (voodoo->render_threads == 4) + { + thread_reset_event(voodoo->render_not_full_event[2]); + thread_reset_event(voodoo->render_not_full_event[3]); + } + if (PARAM_FULL(0)) + thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/ + if (voodoo->render_threads >= 2 && PARAM_FULL(1)) + thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/ + if (voodoo->render_threads == 4 && PARAM_FULL(2)) + thread_wait_event(voodoo->render_not_full_event[2], -1); /*Wait for room in ringbuffer*/ + if (voodoo->render_threads == 4 && PARAM_FULL(3)) + thread_wait_event(voodoo->render_not_full_event[3], -1); /*Wait for room in ringbuffer*/ + } + + voodoo_use_texture(voodoo, params, 0); + if (voodoo->dual_tmus) + voodoo_use_texture(voodoo, params, 1); + + memcpy(params_new, params, sizeof(voodoo_params_t)); + + voodoo->params_write_idx++; + + if (PARAM_ENTRIES(0) < 4 || (voodoo->render_threads >= 2 && PARAM_ENTRIES(1) < 4) || + (voodoo->render_threads == 4 && (PARAM_ENTRIES(2) < 4 || PARAM_ENTRIES(3) < 4))) + voodoo_wake_render_thread(voodoo); +} diff --git a/src/vid_voodoo_render.h b/src/vid_voodoo_render.h new file mode 100644 index 0000000..9ba73dc --- /dev/null +++ b/src/vid_voodoo_render.h @@ -0,0 +1,338 @@ +#if !(defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32) && !(defined __amd64__) +#define NO_CODEGEN +#endif + +#ifndef NO_CODEGEN +void voodoo_codegen_init(voodoo_t *voodoo); +void voodoo_codegen_close(voodoo_t *voodoo); +#endif + +#define DEPTH_TEST(comp_depth) \ + do \ + { \ + switch (depth_op) \ + { \ + case DEPTHOP_NEVER: \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + case DEPTHOP_LESSTHAN: \ + if (!(comp_depth < old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_EQUAL: \ + if (!(comp_depth == old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_LESSTHANEQUAL: \ + if (!(comp_depth <= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHAN: \ + if (!(comp_depth > old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_NOTEQUAL: \ + if (!(comp_depth != old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHANEQUAL: \ + if (!(comp_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, w) \ + 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 = 0; \ + int fog_idx; \ + \ + 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; \ + } \ + \ + switch (params->fogMode & (FOG_Z|FOG_ALPHA)) \ + { \ + case 0: \ + 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; \ + break; \ + case FOG_Z: \ + fog_a = (z >> 20) & 0xff; \ + break; \ + case FOG_ALPHA: \ + fog_a = CLAMP(ia >> 12); \ + break; \ + case FOG_W: \ + fog_a = CLAMP((w >> 32) & 0xff); \ + break; \ + } \ + 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 = 0, newdest_g = 0, newdest_b = 0; \ + \ + 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: \ + fatal("AFUNC_ACOLORBEFOREFOG\n"); \ + 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) + + + +void voodoo_render_thread_1(void *param); +void voodoo_render_thread_2(void *param); +void voodoo_render_thread_3(void *param); +void voodoo_render_thread_4(void *param); +void voodoo_queue_triangle(voodoo_t *voodoo, voodoo_params_t *params); + +extern int voodoo_recomp; +extern int tris; + +static inline void voodoo_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*/ + if (voodoo->render_threads == 4) + { + thread_set_event(voodoo->wake_render_thread[2]); /*Wake up render thread if moving from idle*/ + thread_set_event(voodoo->wake_render_thread[3]); /*Wake up render thread if moving from idle*/ + } +} + +static inline void voodoo_wait_for_render_thread_idle(voodoo_t *voodoo) +{ + while (!PARAM_EMPTY(0) || (voodoo->render_threads >= 2 && !PARAM_EMPTY(1)) || + (voodoo->render_threads == 4 && (!PARAM_EMPTY(2) || !PARAM_EMPTY(3))) || + voodoo->render_voodoo_busy[0] || (voodoo->render_threads >= 2 && voodoo->render_voodoo_busy[1]) || + (voodoo->render_threads == 4 && (voodoo->render_voodoo_busy[2] || voodoo->render_voodoo_busy[3]))) + { + voodoo_wake_render_thread(voodoo); + if (!PARAM_EMPTY(0) || voodoo->render_voodoo_busy[0]) + thread_wait_event(voodoo->render_not_full_event[0], 1); + if (voodoo->render_threads >= 2 && (!PARAM_EMPTY(1) || voodoo->render_voodoo_busy[1])) + thread_wait_event(voodoo->render_not_full_event[1], 1); + if (voodoo->render_threads == 4 && (!PARAM_EMPTY(2) || voodoo->render_voodoo_busy[2])) + thread_wait_event(voodoo->render_not_full_event[2], 1); + if (voodoo->render_threads == 4 && (!PARAM_EMPTY(3) || voodoo->render_voodoo_busy[3])) + thread_wait_event(voodoo->render_not_full_event[3], 1); + } +} diff --git a/src/vid_voodoo_setup.c b/src/vid_voodoo_setup.c new file mode 100644 index 0000000..360d14a --- /dev/null +++ b/src/vid_voodoo_setup.c @@ -0,0 +1,216 @@ +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "vid_voodoo_setup.h" + +void voodoo_triangle_setup(voodoo_t *voodoo) +{ + float dxAB, dxBC, dyAB, dyBC; + float area; + int va = 0, vb = 1, vc = 2; + vert_t verts[3]; + + verts[0] = voodoo->verts[0]; + verts[1] = voodoo->verts[1]; + verts[2] = voodoo->verts[2]; + + if (verts[0].sVy < verts[1].sVy) + { + if (verts[1].sVy < verts[2].sVy) + { + /* V1>V0, V2>V1, V2>V1>V0*/ + va = 0; /*OK*/ + vb = 1; + vc = 2; + } + else + { + /* V1>V0, V1>V2*/ + if (verts[0].sVy < verts[2].sVy) + { + /* V1>V0, V1>V2, V2>V0, V1>V2>V0*/ + va = 0; + vb = 2; + vc = 1; + } + else + { + /* V1>V0, V1>V2, V0>V2, V1>V0>V2*/ + va = 2; + vb = 0; + vc = 1; + } + } + } + else + { + if (verts[1].sVy < verts[2].sVy) + { + /* V0>V1, V2>V1*/ + if (verts[0].sVy < verts[2].sVy) + { + /* V0>V1, V2>V1, V2>V0, V2>V0>V1*/ + va = 1; + vb = 0; + vc = 2; + } + else + { + /* V0>V1, V2>V1, V0>V2, V0>V2>V1*/ + va = 1; + vb = 2; + vc = 0; + } + } + else + { + /*V0>V1>V2*/ + va = 2; + vb = 1; + vc = 0; + } + } + + dxAB = verts[0].sVx - verts[1].sVx; + dxBC = verts[1].sVx - verts[2].sVx; + dyAB = verts[0].sVy - verts[1].sVy; + dyBC = verts[1].sVy - verts[2].sVy; + + area = dxAB * dyBC - dxBC * dyAB; + + if (area == 0.0) + return; + + if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) + { + int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN; + int sign = (area < 0.0); + + if ((voodoo->sSetupMode & (SETUPMODE_CULLING_ENABLE | SETUPMODE_DISABLE_PINGPONG)) + == SETUPMODE_CULLING_ENABLE && voodoo->cull_pingpong) + cull_sign = !cull_sign; + + if (cull_sign && sign) + return; + if (!cull_sign && !sign) + return; + } + + + dxAB = verts[va].sVx - verts[vb].sVx; + dxBC = verts[vb].sVx - verts[vc].sVx; + dyAB = verts[va].sVy - verts[vb].sVy; + dyBC = verts[vb].sVy - verts[vc].sVy; + + area = dxAB * dyBC - dxBC * dyAB; + + dxAB /= area; + dxBC /= area; + dyAB /= area; + dyBC /= area; + + + + voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(verts[va].sVx * 16.0f) & 0xffff); + voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(verts[va].sVy * 16.0f) & 0xffff); + voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(verts[vb].sVx * 16.0f) & 0xffff); + voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(verts[vb].sVy * 16.0f) & 0xffff); + voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(verts[vc].sVx * 16.0f) & 0xffff); + voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(verts[vc].sVy * 16.0f) & 0xffff); + + if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) + { + pclog("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); + return; + } + + if (voodoo->sSetupMode & SETUPMODE_RGB) + { + voodoo->params.startR = (int32_t)(verts[va].sRed * 4096.0f); + voodoo->params.dRdX = (int32_t)(((verts[va].sRed - verts[vb].sRed) * dyBC - (verts[vb].sRed - verts[vc].sRed) * dyAB) * 4096.0f); + voodoo->params.dRdY = (int32_t)(((verts[vb].sRed - verts[vc].sRed) * dxAB - (verts[va].sRed - verts[vb].sRed) * dxBC) * 4096.0f); + voodoo->params.startG = (int32_t)(verts[va].sGreen * 4096.0f); + voodoo->params.dGdX = (int32_t)(((verts[va].sGreen - verts[vb].sGreen) * dyBC - (verts[vb].sGreen - verts[vc].sGreen) * dyAB) * 4096.0f); + voodoo->params.dGdY = (int32_t)(((verts[vb].sGreen - verts[vc].sGreen) * dxAB - (verts[va].sGreen - verts[vb].sGreen) * dxBC) * 4096.0f); + voodoo->params.startB = (int32_t)(verts[va].sBlue * 4096.0f); + voodoo->params.dBdX = (int32_t)(((verts[va].sBlue - verts[vb].sBlue) * dyBC - (verts[vb].sBlue - verts[vc].sBlue) * dyAB) * 4096.0f); + voodoo->params.dBdY = (int32_t)(((verts[vb].sBlue - verts[vc].sBlue) * dxAB - (verts[va].sBlue - verts[vb].sBlue) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_ALPHA) + { + voodoo->params.startA = (int32_t)(verts[va].sAlpha * 4096.0f); + voodoo->params.dAdX = (int32_t)(((verts[va].sAlpha - verts[vb].sAlpha) * dyBC - (verts[vb].sAlpha - verts[vc].sAlpha) * dyAB) * 4096.0f); + voodoo->params.dAdY = (int32_t)(((verts[vb].sAlpha - verts[vc].sAlpha) * dxAB - (verts[va].sAlpha - verts[vb].sAlpha) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_Z) + { + voodoo->params.startZ = (int32_t)(verts[va].sVz * 4096.0f); + voodoo->params.dZdX = (int32_t)(((verts[va].sVz - verts[vb].sVz) * dyBC - (verts[vb].sVz - verts[vc].sVz) * dyAB) * 4096.0f); + voodoo->params.dZdY = (int32_t)(((verts[vb].sVz - verts[vc].sVz) * dxAB - (verts[va].sVz - verts[vb].sVz) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_Wb) + { + voodoo->params.startW = (int64_t)(verts[va].sWb * 4294967296.0f); + voodoo->params.dWdX = (int64_t)(((verts[va].sWb - verts[vb].sWb) * dyBC - (verts[vb].sWb - verts[vc].sWb) * dyAB) * 4294967296.0f); + voodoo->params.dWdY = (int64_t)(((verts[vb].sWb - verts[vc].sWb) * dxAB - (verts[va].sWb - verts[vb].sWb) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW; + voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; + voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; + } + if (voodoo->sSetupMode & SETUPMODE_W0) + { + voodoo->params.tmu[0].startW = (int64_t)(verts[va].sW0 * 4294967296.0f); + voodoo->params.tmu[0].dWdX = (int64_t)(((verts[va].sW0 - verts[vb].sW0) * dyBC - (verts[vb].sW0 - verts[vc].sW0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dWdY = (int64_t)(((verts[vb].sW0 - verts[vc].sW0) * dxAB - (verts[va].sW0 - verts[vb].sW0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW; + voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX; + voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY; + } + if (voodoo->sSetupMode & SETUPMODE_S0_T0) + { + voodoo->params.tmu[0].startS = (int64_t)(verts[va].sS0 * 4294967296.0f); + voodoo->params.tmu[0].dSdX = (int64_t)(((verts[va].sS0 - verts[vb].sS0) * dyBC - (verts[vb].sS0 - verts[vc].sS0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dSdY = (int64_t)(((verts[vb].sS0 - verts[vc].sS0) * dxAB - (verts[va].sS0 - verts[vb].sS0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startT = (int64_t)(verts[va].sT0 * 4294967296.0f); + voodoo->params.tmu[0].dTdX = (int64_t)(((verts[va].sT0 - verts[vb].sT0) * dyBC - (verts[vb].sT0 - verts[vc].sT0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dTdY = (int64_t)(((verts[vb].sT0 - verts[vc].sT0) * dxAB - (verts[va].sT0 - verts[vb].sT0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS; + voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX; + voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY; + voodoo->params.tmu[1].startT = voodoo->params.tmu[0].startT; + voodoo->params.tmu[1].dTdX = voodoo->params.tmu[0].dTdX; + voodoo->params.tmu[1].dTdY = voodoo->params.tmu[0].dTdY; + } + if (voodoo->sSetupMode & SETUPMODE_W1) + { + voodoo->params.tmu[1].startW = (int64_t)(verts[va].sW1 * 4294967296.0f); + voodoo->params.tmu[1].dWdX = (int64_t)(((verts[va].sW1 - verts[vb].sW1) * dyBC - (verts[vb].sW1 - verts[vc].sW1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dWdY = (int64_t)(((verts[vb].sW1 - verts[vc].sW1) * dxAB - (verts[va].sW1 - verts[vb].sW1) * dxBC) * 4294967296.0f); + } + if (voodoo->sSetupMode & SETUPMODE_S1_T1) + { + voodoo->params.tmu[1].startS = (int64_t)(verts[va].sS1 * 4294967296.0f); + voodoo->params.tmu[1].dSdX = (int64_t)(((verts[va].sS1 - verts[vb].sS1) * dyBC - (verts[vb].sS1 - verts[vc].sS1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dSdY = (int64_t)(((verts[vb].sS1 - verts[vc].sS1) * dxAB - (verts[va].sS1 - verts[vb].sS1) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startT = (int64_t)(verts[va].sT1 * 4294967296.0f); + voodoo->params.tmu[1].dTdX = (int64_t)(((verts[va].sT1 - verts[vb].sT1) * dyBC - (verts[vb].sT1 - verts[vc].sT1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dTdY = (int64_t)(((verts[vb].sT1 - verts[vc].sT1) * dxAB - (verts[va].sT1 - verts[vb].sT1) * dxBC) * 4294967296.0f); + } + + voodoo->params.sign = (area < 0.0); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + voodoo_queue_triangle(voodoo, &voodoo->params); +} diff --git a/src/vid_voodoo_setup.h b/src/vid_voodoo_setup.h new file mode 100644 index 0000000..06d2f8d --- /dev/null +++ b/src/vid_voodoo_setup.h @@ -0,0 +1 @@ +void voodoo_triangle_setup(voodoo_t *voodoo); diff --git a/src/vid_voodoo_texture.c b/src/vid_voodoo_texture.c new file mode 100644 index 0000000..f1d5c78 --- /dev/null +++ b/src/vid_voodoo_texture.c @@ -0,0 +1,583 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_common.h" +#include "vid_voodoo_dither.h" +#include "vid_voodoo_regs.h" +#include "vid_voodoo_render.h" +#include "vid_voodoo_texture.h" + +void voodoo_recalc_tex(voodoo_t *voodoo, int tmu) +{ + int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3; + int width = 256, height = 256; + int shift = 8; + int lod; + uint32_t base = voodoo->params.texBaseAddr[tmu]; + uint32_t offset = 0; + int tex_lod = 0; + uint32_t offsets[LOD_MAX+3]; + int widths[LOD_MAX+3], heights[LOD_MAX+3], shifts[LOD_MAX+3]; + + if (voodoo->params.tLOD[tmu] & LOD_S_IS_WIDER) + height >>= aspect; + else + { + width >>= aspect; + shift -= aspect; + } + + for (lod = 0; lod <= LOD_MAX + 2; lod++) + { + offsets[lod] = offset; + widths[lod] = width >> lod; + heights[lod] = height >> lod; + shifts[lod] = shift - lod; + + if (!widths[lod]) + widths[lod] = 1; + if (!heights[lod]) + heights[lod] = 1; + if (shifts[lod] < 0) + shifts[lod] = 0; + + if (!(voodoo->params.tLOD[tmu] & LOD_SPLIT) || + ((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) || + (!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD))) + { + if (voodoo->params.tformat[tmu] & 8) + offset += (width >> lod) * (height >> lod) * 2; + else + offset += (width >> lod) * (height >> lod); + } + } + + + if ((voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR) && (voodoo->params.tLOD[tmu] & LOD_ODD)) + tex_lod++; /*Skip LOD 0*/ + +// pclog("TMU %i: %08x\n", tmu, voodoo->params.textureMode[tmu]); + for (lod = 0; lod <= LOD_MAX+1; lod++) + { + if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR) + { + switch (tex_lod) + { + case 0: + base = voodoo->params.texBaseAddr[tmu]; + break; + case 1: + base = voodoo->params.texBaseAddr1[tmu]; + break; + case 2: + base = voodoo->params.texBaseAddr2[tmu]; + break; + default: + base = voodoo->params.texBaseAddr38[tmu]; + break; + } + } + + voodoo->params.tex_base[tmu][lod] = base + offsets[tex_lod]; + if (voodoo->params.tformat[tmu] & 8) + voodoo->params.tex_end[tmu][lod] = base + offsets[tex_lod] + (widths[tex_lod] * heights[tex_lod] * 2); + else + voodoo->params.tex_end[tmu][lod] = base + offsets[tex_lod] + (widths[tex_lod] * heights[tex_lod]); + voodoo->params.tex_w_mask[tmu][lod] = widths[tex_lod] - 1; + voodoo->params.tex_w_nmask[tmu][lod] = ~(widths[tex_lod] - 1); + voodoo->params.tex_h_mask[tmu][lod] = heights[tex_lod] - 1; + voodoo->params.tex_shift[tmu][lod] = shifts[tex_lod]; + voodoo->params.tex_lod[tmu][lod] = tex_lod; + + if (!(voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR) || + ((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) || + (!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD))) + { + if (!(voodoo->params.tLOD[tmu] & LOD_ODD) || lod != 0) + { + if (voodoo->params.textureMode[tmu] & TEXTUREMODE_TRILINEAR) + tex_lod += 2; + else + tex_lod++; + } + } + } + + voodoo->params.tex_width[tmu] = width; +} + +#define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24)) + +void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) +{ + int c, d; + int lod; + int lod_min, lod_max; + uint32_t addr = 0, addr_end; + uint32_t palette_checksum; + + lod_min = (params->tLOD[tmu] >> 2) & 15; + lod_max = (params->tLOD[tmu] >> 8) & 15; + + if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) + { + if (voodoo->palette_dirty[tmu]) + { + palette_checksum = 0; + + for (c = 0; c < 256; c++) + palette_checksum ^= voodoo->palette[tmu][c].u; + + voodoo->palette_checksum[tmu] = palette_checksum; + voodoo->palette_dirty[tmu] = 0; + } + else + palette_checksum = voodoo->palette_checksum[tmu]; + } + else + palette_checksum = 0; + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) + addr = params->texBaseAddr1[tmu]; + else + addr = params->texBaseAddr[tmu]; + + /*Try to find texture in cache*/ + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->texture_cache[tmu][c].base == addr && + voodoo->texture_cache[tmu][c].tLOD == (params->tLOD[tmu] & 0xf00fff) && + voodoo->texture_cache[tmu][c].palette_checksum == palette_checksum) + { + params->tex_entry[tmu] = c; + voodoo->texture_cache[tmu][c].refcount++; + return; + } + } + + /*Texture not found, search for unused texture*/ + do + { + for (c = 0; c < TEX_CACHE_MAX; c++) + { + voodoo->texture_last_removed++; + voodoo->texture_last_removed &= (TEX_CACHE_MAX-1); + if (voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[0] && + (voodoo->render_threads == 1 || voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[1])) + break; + } + if (c == TEX_CACHE_MAX) + voodoo_wait_for_render_thread_idle(voodoo); + } while (c == TEX_CACHE_MAX); + if (c == TEX_CACHE_MAX) + fatal("Texture cache full!\n"); + + c = voodoo->texture_last_removed; + + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) + voodoo->texture_cache[tmu][c].base = params->texBaseAddr1[tmu]; + else + voodoo->texture_cache[tmu][c].base = params->texBaseAddr[tmu]; + voodoo->texture_cache[tmu][c].tLOD = params->tLOD[tmu] & 0xf00fff; + + lod_min = (params->tLOD[tmu] >> 2) & 15; + lod_max = (params->tLOD[tmu] >> 8) & 15; +// pclog(" add new texture to %i tformat=%i %08x LOD=%i-%i tmu=%i\n", c, voodoo->params.tformat[tmu], params->texBaseAddr[tmu], lod_min, lod_max, tmu); + lod_min = MIN(lod_min, 8); + lod_max = MIN(lod_max, 8); + for (lod = lod_min; lod <= lod_max; lod++) + { + uint32_t *base = &voodoo->texture_cache[tmu][c].data[texture_offset[lod]]; + uint32_t tex_addr = params->tex_base[tmu][lod] & voodoo->texture_mask; + int x, y; + int shift = 8 - params->tex_lod[tmu][lod]; + rgba_u *pal; + + //pclog(" LOD %i : %08x - %08x %i %i,%i\n", lod, params->tex_base[tmu][lod] & voodoo->texture_mask, addr, voodoo->params.tformat[tmu], voodoo->params.tex_w_mask[tmu][lod],voodoo->params.tex_h_mask[tmu][lod]); + + + switch (params->tformat[tmu]) + { + case TEX_RGB332: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(rgb332[dat].r, rgb332[dat].g, rgb332[dat].b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_Y4I2Q2: + pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_A8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(dat, dat, dat, dat); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_I8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(dat, dat, dat, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_AI8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba((dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0xf0) | ((dat >> 4) & 0x0f)); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_PAL8: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_APAL8: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + int r = ((pal[dat].rgba.r & 3) << 6) | ((pal[dat].rgba.g & 0xf0) >> 2) | (pal[dat].rgba.r & 3); + int g = ((pal[dat].rgba.g & 0xf) << 4) | ((pal[dat].rgba.b & 0xc0) >> 4) | ((pal[dat].rgba.g & 0xf) >> 2); + int b = ((pal[dat].rgba.b & 0x3f) << 2) | ((pal[dat].rgba.b & 0x30) >> 4); + int a = (pal[dat].rgba.r & 0xfc) | ((pal[dat].rgba.r & 0xc0) >> 6); + + base[x] = makergba(r, g, b, a); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_ARGB8332: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(rgb332[dat & 0xff].r, rgb332[dat & 0xff].g, rgb332[dat & 0xff].b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_A8Y4I2Q2: + pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_R5G6B5: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(rgb565[dat].r, rgb565[dat].g, rgb565[dat].b, 0xff); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_ARGB1555: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(argb1555[dat].r, argb1555[dat].g, argb1555[dat].b, argb1555[dat].a); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_ARGB4444: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(argb4444[dat].r, argb4444[dat].g, argb4444[dat].b, argb4444[dat].a); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_A8I8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(dat & 0xff, dat & 0xff, dat & 0xff, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_APAL88: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + default: + fatal("Unknown texture format %i\n", params->tformat[tmu]); + } + } + + voodoo->texture_cache[tmu][c].is16 = voodoo->params.tformat[tmu] & 8; + + if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) + voodoo->texture_cache[tmu][c].palette_checksum = palette_checksum; + else + voodoo->texture_cache[tmu][c].palette_checksum = 0; + + if (lod_min == 0) + { + voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->params.tex_base[tmu][0]; + voodoo->texture_cache[tmu][c].addr_end[0] = voodoo->params.tex_end[tmu][0]; + } + else + voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->texture_cache[tmu][c].addr_end[0] = 0; + + if (lod_min <= 1 && lod_max >= 1) + { + voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->params.tex_base[tmu][1]; + voodoo->texture_cache[tmu][c].addr_end[1] = voodoo->params.tex_end[tmu][1]; + } + else + voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->texture_cache[tmu][c].addr_end[1] = 0; + + if (lod_min <= 2 && lod_max >= 2) + { + voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->params.tex_base[tmu][2]; + voodoo->texture_cache[tmu][c].addr_end[2] = voodoo->params.tex_end[tmu][2]; + } + else + voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->texture_cache[tmu][c].addr_end[2] = 0; + + if (lod_max >= 3) + { + voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->params.tex_base[tmu][(lod_min > 3) ? lod_min : 3]; + voodoo->texture_cache[tmu][c].addr_end[3] = voodoo->params.tex_end[tmu][(lod_max < 8) ? lod_max : 8]; + } + else + voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->texture_cache[tmu][c].addr_end[3] = 0; + + + for (d = 0; d < 4; d++) + { + addr = voodoo->texture_cache[tmu][c].addr_start[d]; + addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + + if (addr_end != 0) + { + for (; addr <= addr_end; addr += (1 << TEX_DIRTY_SHIFT)) + voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; + } + } + + params->tex_entry[tmu] = c; + voodoo->texture_cache[tmu][c].refcount++; +} + +void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) +{ + int wait_for_idle = 0; + int c; + + memset(voodoo->texture_present[tmu], 0, sizeof(voodoo->texture_present[0])); +// pclog("Evict %08x %i\n", dirty_addr, sizeof(voodoo->texture_present)); + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->texture_cache[tmu][c].base != -1) + { + int d; + + for (d = 0; d < 4; d++) + { + int addr_start = voodoo->texture_cache[tmu][c].addr_start[d]; + int addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + + if (addr_end != 0) + { + int addr_start_masked = addr_start & voodoo->texture_mask & ~0x3ff; + int addr_end_masked = ((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff; + + if (addr_end_masked < addr_start_masked) + addr_end_masked = voodoo->texture_mask+1; + if (dirty_addr >= addr_start_masked && dirty_addr < addr_end_masked) + { +// pclog(" Evict texture %i %08x\n", c, voodoo->texture_cache[tmu][c].base); + + if (voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[0] || + (voodoo->render_threads == 2 && voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[1])) + wait_for_idle = 1; + + voodoo->texture_cache[tmu][c].base = -1; + } + else + { + for (; addr_start <= addr_end; addr_start += (1 << TEX_DIRTY_SHIFT)) + voodoo->texture_present[tmu][(addr_start & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; + } + } + } + } + } + if (wait_for_idle) + voodoo_wait_for_render_thread_idle(voodoo); +} + +void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) +{ + int lod, s, t; + voodoo_t *voodoo = (voodoo_t *)p; + int tmu; + + if (addr & 0x400000) + return; /*TREX != 0*/ + + tmu = (addr & 0x200000) ? 1 : 0; + + if (tmu && !voodoo->dual_tmus) + return; + + if (voodoo->type < VOODOO_BANSHEE) + { + if (!(voodoo->params.tformat[tmu] & 8) && voodoo->type >= VOODOO_BANSHEE) + { + lod = (addr >> 16) & 0xf; + t = (addr >> 8) & 0xff; + } + else + { + lod = (addr >> 17) & 0xf; + t = (addr >> 9) & 0xff; + } + if (voodoo->params.tformat[tmu] & 8) + s = (addr >> 1) & 0xfe; + else + { + if ((voodoo->params.textureMode[tmu] & (1 << 31)) || voodoo->type >= VOODOO_BANSHEE) + s = addr & 0xfc; + else + s = (addr >> 1) & 0xfc; + } + if (lod > LOD_MAX) + return; + +// if (addr >= 0x200000) +// return; + + if (voodoo->params.tformat[tmu] & 8) + addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2; + else + addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]); + } + else + addr = (addr & 0x1ffffc) + voodoo->params.tex_base[tmu][0]; + + if (voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu); + } + if (voodoo->type == VOODOO_3 && voodoo->texture_present[tmu^1][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// pclog("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu^1); + } + *(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val; +} diff --git a/src/vid_voodoo_texture.h b/src/vid_voodoo_texture.h new file mode 100644 index 0000000..e4c5602 --- /dev/null +++ b/src/vid_voodoo_texture.h @@ -0,0 +1,19 @@ +static const uint32_t texture_offset[LOD_MAX+3] = +{ + 0, + 256*256, + 256*256 + 128*128, + 256*256 + 128*128 + 64*64, + 256*256 + 128*128 + 64*64 + 32*32, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1 + 1 +}; + +void voodoo_recalc_tex(voodoo_t *voodoo, int tmu); +void voodoo_use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu); +void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p); +void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu); diff --git a/src/vid_wy700.c b/src/vid_wy700.c index df4cfad..1d80bf5 100644 --- a/src/vid_wy700.c +++ b/src/vid_wy700.c @@ -12,7 +12,6 @@ #define WY700_YSIZE 800 void updatewindowsize(int x, int y); -void loadfont(char *s, int format); /* The Wyse 700 is an unusual video card. Though it has an MC6845 CRTC, this @@ -149,6 +148,7 @@ static uint8_t mode_40x24[] = 0x0f, /* Maximum raster address */ }; +static uint32_t wy700_pal[4]; /* Font ROM: Two fonts, each containing 256 characters, 16x16 pixels */ extern uint8_t fontdatw[512][32]; @@ -189,8 +189,8 @@ typedef struct wy700_t int enabled; /* Display enabled, 0 or 1 */ int detach; /* Detach cursor, 0 or 1 */ - int dispontime, dispofftime; - int vidtime; + uint64_t dispontime, dispofftime; + pc_timer_t timer; int linepos, displine; int vc; @@ -489,8 +489,8 @@ void wy700_recalctimings(wy700_t *wy700) _dispofftime = disptime - _dispontime; _dispontime *= MDACONST; _dispofftime *= MDACONST; - wy700->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); - wy700->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + wy700->dispontime = (uint64_t)_dispontime; + wy700->dispofftime = (uint64_t)_dispofftime; } @@ -553,7 +553,7 @@ void wy700_textline(wy700_t *wy700) if (sc == 14 && mda && ((attr & 7) == 1)) { for (c = 0; c < cw; c++) - buffer->line[wy700->displine][(x * cw) + c] = + ((uint32_t *)buffer32->line[wy700->displine])[(x * cw) + c] = mdacols[attr][blink][1]; } else /* Draw 16 pixels of character */ @@ -565,21 +565,23 @@ void wy700_textline(wy700_t *wy700) int col; if (c < 8) col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; - else col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[1] & (1 << ((c & 7) ^ 7))) ? 1 : 0]; + else + col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[1] & (1 << ((c & 7) ^ 7))) ? 1 : 0]; if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) col = mdacols[0][0][0]; if (w == 40) { - buffer->line[wy700->displine][(x * cw) + 2*c] = col; - buffer->line[wy700->displine][(x * cw) + 2*c + 1] = col; + ((uint32_t *)buffer32->line[wy700->displine])[(x * cw) + 2*c] = col; + ((uint32_t *)buffer32->line[wy700->displine])[(x * cw) + 2*c + 1] = col; } - else buffer->line[wy700->displine][(x * cw) + c] = col; + else + ((uint32_t *)buffer32->line[wy700->displine])[(x * cw) + c] = col; } if (drawcursor) { for (c = 0; c < cw; c++) - buffer->line[wy700->displine][(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; + ((uint32_t *)buffer32->line[wy700->displine])[(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; } ++ma; } @@ -592,7 +594,7 @@ void wy700_cgaline(wy700_t *wy700) { int x, c; uint32_t dat; - uint8_t ink = 0; + uint32_t ink = 0; uint16_t addr; uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; @@ -614,11 +616,11 @@ void wy700_cgaline(wy700_t *wy700) { for (c = 0; c < 32; c++) { - ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + ink = (dat & 0x80000000) ? wy700_pal[3]: wy700_pal[0]; if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) - ink = 16; - buffer->line[wy700->displine][x*64 + 2*c] = - buffer->line[wy700->displine][x*64 + 2*c+1] = + ink = wy700_pal[0]; + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 2*c] = + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 2*c+1] = ink; dat = dat << 1; } @@ -627,19 +629,13 @@ void wy700_cgaline(wy700_t *wy700) { for (c = 0; c < 16; c++) { - switch ((dat >> 30) & 3) - { - case 0: ink = 16 + 0; break; - case 1: ink = 16 + 8; break; - case 2: ink = 16 + 7; break; - case 3: ink = 16 + 15; break; - } + ink = wy700_pal[(dat >> 30) & 3]; if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) - ink = 16; - buffer->line[wy700->displine][x*64 + 4*c] = - buffer->line[wy700->displine][x*64 + 4*c+1] = - buffer->line[wy700->displine][x*64 + 4*c+2] = - buffer->line[wy700->displine][x*64 + 4*c+3] = + ink = wy700_pal[0]; + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 4*c] = + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 4*c+1] = + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 4*c+2] = + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 4*c+3] = ink; dat = dat << 2; } @@ -652,7 +648,7 @@ void wy700_medresline(wy700_t *wy700) { int x, c; uint32_t dat; - uint8_t ink = 0; + uint32_t ink = 0; uint32_t addr; addr = (wy700->displine >> 1) * 80 + 4 * wy700->wy700_base; @@ -669,19 +665,14 @@ void wy700_medresline(wy700_t *wy700) { for (c = 0; c < 16; c++) { - switch ((dat >> 30) & 3) - { - case 0: ink = 16 + 0; break; - case 1: ink = 16 + 8; break; - case 2: ink = 16 + 7; break; - case 3: ink = 16 + 15; break; - } + ink = wy700_pal[(dat >> 30) & 3]; /* Display disabled? */ - if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*64 + 4*c] = - buffer->line[wy700->displine][x*64 + 4*c+1] = - buffer->line[wy700->displine][x*64 + 4*c+2] = - buffer->line[wy700->displine][x*64 + 4*c+3] = + if (!(wy700->wy700_mode & 8)) + ink = wy700_pal[0]; + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 4*c] = + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 4*c+1] = + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 4*c+2] = + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 4*c+3] = ink; dat = dat << 2; } @@ -690,11 +681,12 @@ void wy700_medresline(wy700_t *wy700) { for (c = 0; c < 32; c++) { - ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + ink = (dat & 0x80000000) ? wy700_pal[3]: wy700_pal[0]; /* Display disabled? */ - if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*64 + 2*c] = - buffer->line[wy700->displine][x*64 + 2*c+1] = + if (!(wy700->wy700_mode & 8)) + ink = wy700_pal[0]; + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 2*c] = + ((uint32_t *)buffer32->line[wy700->displine])[x*64 + 2*c+1] = ink; dat = dat << 1; } @@ -710,7 +702,7 @@ void wy700_hiresline(wy700_t *wy700) { int x, c; uint32_t dat; - uint8_t ink = 0; + uint32_t ink = 0; uint32_t addr; addr = (wy700->displine >> 1) * 160 + 4 * wy700->wy700_base; @@ -731,17 +723,12 @@ void wy700_hiresline(wy700_t *wy700) { for (c = 0; c < 16; c++) { - switch ((dat >> 30) & 3) - { - case 0: ink = 16 + 0; break; - case 1: ink = 16 + 8; break; - case 2: ink = 16 + 7; break; - case 3: ink = 16 + 15; break; - } + ink = wy700_pal[(dat >> 30) & 3]; /* Display disabled? */ - if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*32 + 2*c] = - buffer->line[wy700->displine][x*32 + 2*c+1] = + if (!(wy700->wy700_mode & 8)) + ink = wy700_pal[0]; + ((uint32_t *)buffer32->line[wy700->displine])[x*32 + 2*c] = + ((uint32_t *)buffer32->line[wy700->displine])[x*32 + 2*c+1] = ink; dat = dat << 2; } @@ -750,10 +737,11 @@ void wy700_hiresline(wy700_t *wy700) { for (c = 0; c < 32; c++) { - ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + ink = (dat & 0x80000000) ? wy700_pal[3]: wy700_pal[0]; /* Display disabled? */ - if (!(wy700->wy700_mode & 8)) ink = 16; - buffer->line[wy700->displine][x*32 + c] = ink; + if (!(wy700->wy700_mode & 8)) + ink = wy700_pal[0]; + ((uint32_t *)buffer32->line[wy700->displine])[x*32 + c] = ink; dat = dat << 1; } } @@ -770,7 +758,7 @@ void wy700_poll(void *p) if (!wy700->linepos) { - wy700->vidtime += wy700->dispofftime; + timer_advance_u64(&wy700->timer, wy700->dispofftime); wy700->cga_stat |= 1; wy700->mda_stat |= 1; wy700->linepos = 1; @@ -831,7 +819,7 @@ void wy700_poll(void *p) wy700->cga_stat &= ~1; wy700->mda_stat &= ~1; } - wy700->vidtime += wy700->dispontime; + timer_advance_u64(&wy700->timer, wy700->dispontime); wy700->linepos = 0; if (wy700->displine == 800) @@ -845,7 +833,7 @@ void wy700_poll(void *p) if (ysize < 32) ysize = 200; updatewindowsize(xsize, ysize); } - video_blit_memtoscreen_8(0, 0, xsize, ysize); + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); frames++; /* Fixed 1280x800 resolution */ @@ -879,7 +867,7 @@ void *wy700_init() /* 128k video RAM */ wy700->vram = malloc(0x20000); - timer_add(wy700_poll, &wy700->vidtime, TIMER_ALWAYS_ENABLED, wy700); + timer_add(&wy700->timer, wy700_poll, wy700, 1); /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in * high-resolution modes) */ @@ -888,72 +876,78 @@ void *wy700_init() io_sethandler(0x03b0, 0x000C, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); io_sethandler(0x03d0, 0x0010, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); + wy700_pal[0] = makecol(0x00, 0x00, 0x00); + wy700_pal[1] = makecol(0x55, 0x55, 0x55); + wy700_pal[2] = makecol(0xaa, 0xaa, 0xaa); + wy700_pal[3] = makecol(0xff, 0xff, 0xff); + /* Set up the emulated attributes. * CGA is done in four groups: 00-0F, 10-7F, 80-8F, 90-FF */ for (c = 0; c < 0x10; c++) { - cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16; - if (c & 8) cgacols[c][0][1] = 15 + 16; - else cgacols[c][0][1] = 7 + 16; + cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = wy700_pal[0]; + if (c & 8) cgacols[c][0][1] = wy700_pal[3]; + else cgacols[c][0][1] = wy700_pal[2]; } for (c = 0x10; c < 0x80; c++) { - cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16 + 7; - if (c & 8) cgacols[c][0][1] = 15 + 16; - else cgacols[c][0][1] = 0 + 16; + cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = wy700_pal[2]; + if (c & 8) cgacols[c][0][1] = wy700_pal[3]; + else cgacols[c][0][1] = wy700_pal[0]; - if ((c & 0x0F) == 8) cgacols[c][0][1] = 8 + 16; + if ((c & 0x0F) == 8) + cgacols[c][0][1] = wy700_pal[1]; } /* With special cases for 00, 11, 22, ... 77 */ - cgacols[0x00][0][1] = cgacols[0x00][1][1] = 16; + cgacols[0x00][0][1] = cgacols[0x00][1][1] = wy700_pal[0]; for (c = 0x11; c <= 0x77; c += 0x11) { - cgacols[c][0][1] = cgacols[c][1][1] = 16 + 7; + cgacols[c][0][1] = cgacols[c][1][1] = wy700_pal[2]; } for (c = 0x80; c < 0x90; c++) { - cgacols[c][0][0] = 16 + 8; - if (c & 8) cgacols[c][0][1] = 15 + 16; - else cgacols[c][0][1] = 7 + 16; + cgacols[c][0][0] = wy700_pal[1]; + if (c & 8) cgacols[c][0][1] = wy700_pal[3]; + else cgacols[c][0][1] = wy700_pal[2]; cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c-0x80][0][0]; } for (c = 0x90; c < 0x100; c++) { - cgacols[c][0][0] = 16 + 15; - if (c & 8) cgacols[c][0][1] = 8 + 16; - else cgacols[c][0][1] = 7 + 16; - if ((c & 0x0F) == 0) cgacols[c][0][1] = 16; + cgacols[c][0][0] = wy700_pal[3]; + if (c & 8) cgacols[c][0][1] = wy700_pal[1]; + else cgacols[c][0][1] = wy700_pal[2]; + if ((c & 0x0F) == 0) cgacols[c][0][1] = wy700_pal[0]; cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c-0x80][0][0]; } /* Also special cases for 99, AA, ..., FF */ for (c = 0x99; c <= 0xFF; c += 0x11) { - cgacols[c][0][1] = 16 + 15; + cgacols[c][0][1] = wy700_pal[3]; } /* Special cases for 08, 80 and 88 */ - cgacols[0x08][0][1] = 16 + 8; - cgacols[0x80][0][1] = 16; - cgacols[0x88][0][1] = 16 + 8; + cgacols[0x08][0][1] = wy700_pal[1]; + cgacols[0x80][0][1] = wy700_pal[0]; + cgacols[0x88][0][1] = wy700_pal[1]; /* MDA attributes */ 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[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = wy700_pal[0]; + if (c & 8) mdacols[c][0][1] = wy700_pal[3]; + else mdacols[c][0][1] = wy700_pal[2]; } - 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; + mdacols[0x70][0][1] = wy700_pal[0]; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = wy700_pal[3]; + mdacols[0xF0][0][1] = wy700_pal[0]; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = wy700_pal[3]; + mdacols[0x78][0][1] = wy700_pal[2]; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = wy700_pal[3]; + mdacols[0xF8][0][1] = wy700_pal[2]; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = wy700_pal[3]; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = wy700_pal[0]; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = wy700_pal[0]; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = wy700_pal[0]; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = wy700_pal[0]; /* Start off in 80x25 text mode */ wy700->cga_stat = 0xF4; diff --git a/src/video.c b/src/video.c index b2d477b..7c53f11 100644 --- a/src/video.c +++ b/src/video.c @@ -17,30 +17,59 @@ #include "vid_ati_mach64.h" #include "vid_cga.h" #include "vid_cl5429.h" +#include "vid_compaq_cga.h" #include "vid_ega.h" #include "vid_et4000.h" #include "vid_et4000w32.h" #include "vid_genius.h" #include "vid_hercules.h" +#include "vid_ht216.h" +#include "vid_im1024.h" #include "vid_incolor.h" #include "vid_colorplus.h" #include "vid_mda.h" +#include "vid_mga.h" #include "vid_olivetti_m24.h" +#include "vid_oti037.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_pgc.h" #include "vid_ps1_svga.h" #include "vid_s3.h" #include "vid_s3_virge.h" +#include "vid_sigma.h" #include "vid_tandy.h" #include "vid_tandysl.h" #include "vid_tgui9440.h" #include "vid_tvga.h" #include "vid_vga.h" #include "vid_wy700.h" +#include "vid_t3100e.h" +#include "vid_t1000.h" +#include "vid_voodoo_banshee.h" + +enum +{ + VIDEO_ISA = 0, + VIDEO_BUS +}; + +#define VIDEO_FLAG_TYPE_CGA 0 +#define VIDEO_FLAG_TYPE_MDA 1 +#define VIDEO_FLAG_TYPE_SPECIAL 2 +#define VIDEO_FLAG_TYPE_MASK 3 + + +typedef struct +{ + int type; + int write_b, write_w, write_l; + int read_b, read_w, read_l; +} video_timings_t; typedef struct { @@ -48,40 +77,88 @@ typedef struct char internal_name[24]; device_t *device; int legacy_id; + int flags; + video_timings_t timing; } VIDEO_CARD; static VIDEO_CARD video_cards[] = { - {"ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx", &mach64gx_device, GFX_MACH64GX}, - {"ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2}, - {"ATI VGA Charger (ATI-28800)", "ati28800", &ati28800_device, GFX_VGACHARGER}, - {"ATI VGA Edge-16 (ATI-18800)", "ati18800", &ati18800_device, GFX_VGAEDGE16}, - {"CGA", "cga", &cga_device, GFX_CGA}, - {"Cirrus Logic CL-GD5429", "cl_gd5429", &gd5429_device, GFX_CL_GD5429}, - {"Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32", &et4000w32p_device, GFX_ET4000W32}, - {"Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000", &s3_virge_device, GFX_VIRGE}, - {"EGA", "ega", &ega_device, GFX_EGA}, - {"Hercules", "hercules", &hercules_device, GFX_HERCULES}, - {"Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR}, - {"MDA", "mda", &mda_device, GFX_MDA}, - {"MDSI Genius", "genius", &genius_device, GFX_GENIUS}, - {"Number Nine 9FX (S3 Trio64)", "n9_9fx", &s3_9fx_device, GFX_N9_9FX}, - {"OAK OTI-067", "oti067", &oti067_device, GFX_OTI067}, - {"Paradise Bahamas 64 (S3 Vision864)", "bahamas64", &s3_bahamas64_device, GFX_BAHAMAS64}, - {"Phoenix S3 Trio32", "px_trio32", &s3_phoenix_trio32_device, GFX_PHOENIX_TRIO32}, - {"Phoenix S3 Trio64", "px_trio64", &s3_phoenix_trio64_device, GFX_PHOENIX_TRIO64}, - {"Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS}, - {"S3 ViRGE/DX", "virge375", &s3_virge_375_device, GFX_VIRGEDX}, - {"Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA}, - {"Tseng ET4000AX", "et4000ax", &et4000_device, GFX_ET4000}, - {"Trident TGUI9440", "tgui9440", &tgui9440_device, GFX_TGUI9440}, - {"VGA", "vga", &vga_device, GFX_VGA}, - {"Wyse 700", "wy700", &wy700_device, GFX_WY700}, - {"", "", NULL, 0} + {"3DFX Voodoo Banshee (reference)", "banshee", &voodoo_banshee_device, GFX_BANSHEE, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"3DFX Voodoo 3 2000", "v3_2000", &voodoo_3_2000_device, GFX_VOODOO_3_2000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"3DFX Voodoo 3 3000", "v3_3000", &voodoo_3_3000_device, GFX_VOODOO_3_3000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"Acumos AVGA2 / Cirrus Logic CL-GD5402", "avga2", &avga2_device, GFX_AVGA2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"ATI Graphics Pro Turbo (Mach64 GX)", "mach64gx", &mach64gx_device, GFX_MACH64GX, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"ATI Video Xpression (Mach64 VT2)", "mach64vt2", &mach64vt2_device, GFX_MACH64VT2, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"ATI EGA Wonder 800+ (ATI-18800)", "egawonder800", &ati_ega_wonder_800_device, GFX_EGAWONDER800, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"ATI Korean VGA (ATI-28800)", "ati28800k", &ati28800k_device, GFX_ATIKOREANVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"ATI VGA Charger (ATI-28800)", "ati28800", &ati28800_device, GFX_VGACHARGER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"ATI VGA Edge-16 (ATI-18800)", "ati18800", &ati18800_device, GFX_VGAEDGE16, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"CGA", "cga", &cga_device, GFX_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"Cirrus Logic CL-GD5428", "cl_gd5428", &gd5428_device, GFX_CL_GD5428, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"Cirrus Logic CL-GD5429", "cl_gd5429", &gd5429_device, GFX_CL_GD5429, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"Cirrus Logic CL-GD5430", "cl_gd5430", &gd5430_device, GFX_CL_GD5430, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"Cirrus Logic CL-GD5434", "cl_gd5434", &gd5434_device, GFX_CL_GD5434, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"Compaq CGA", "compaq_cga", &compaq_cga_device, GFX_COMPAQ_CGA, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"Creative Labs 3D Blaster Banshee PCI", "cl_banshee", &creative_voodoo_banshee_device, GFX_CL_BANSHEE, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 1, 20, 20, 21}}, + {"Diamond Stealth 32 (Tseng ET4000/w32p)", "stealth32", &et4000w32p_device, GFX_ET4000W32, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, + {"Diamond Stealth 3D 2000 (S3 ViRGE)", "stealth3d_2000", &s3_virge_device, GFX_VIRGE, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, + {"EGA", "ega", &ega_device, GFX_EGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"Hercules", "hercules", &hercules_device, GFX_HERCULES, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"Hercules InColor", "incolor", &incolor_device, GFX_INCOLOR, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"IBM 1MB SVGA Adapter/A (CL GD5428)", "ibm1mbsvga", &ibm_gd5428_device, GFX_IBM_GD5428, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"Image Manager 1024", "im1024", &im1024_device, GFX_IM1024, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"Kasan Hangulmadang-16 (Tseng ET4000AX)", "kasan16", &et4000_kasan_device, GFX_KASAN16VGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"Matrox Mystique", "mystique", &mystique_device, GFX_MYSTIQUE, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 4, 10, 10, 10}}, + {"MDA", "mda", &mda_device, GFX_MDA, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"MDSI Genius", "genius", &genius_device, GFX_GENIUS, VIDEO_FLAG_TYPE_MDA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"Number Nine 9FX (S3 Trio64)", "n9_9fx", &s3_9fx_device, GFX_N9_9FX, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"OAK OTI-037", "oti037", &oti037_device, GFX_OTI037, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, + {"OAK OTI-067", "oti067", &oti067_device, GFX_OTI067, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, + {"Olivetti GO481 (Paradise PVGA1A)", "olivetti_go481", ¶dise_pvga1a_oli_go481_device, GFX_OLIVETTI_GO481, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 6, 8, 16, 6, 8, 16}}, + {"Paradise Bahamas 64 (S3 Vision864)", "bahamas64", &s3_bahamas64_device, GFX_BAHAMAS64, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 5, 20, 20, 35}}, +/* Not offered as the emulation is very incomplete + {"Professional Graphics Controller", "pgc", &pgc_device, GFX_PGC, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, +*/ + {"Phoenix S3 Trio32", "px_trio32", &s3_phoenix_trio32_device, GFX_PHOENIX_TRIO32, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"Phoenix S3 Trio64", "px_trio64", &s3_phoenix_trio64_device, GFX_PHOENIX_TRIO64, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 3, 2, 4, 25, 25, 40}}, + {"Plantronics ColorPlus", "plantronics", &colorplus_device, GFX_COLORPLUS, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"S3 ViRGE/DX", "virge375", &s3_virge_375_device, GFX_VIRGEDX, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 2, 2, 3, 28, 28, 45}}, + {"Sigma Color 400", "sigma400", &sigma_device, GFX_SIGMA400, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"Trident TVGA8900D", "tvga8900d", &tvga8900d_device, GFX_TVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 8, 8, 12}}, + {"Trident TVGA9000B", "tvga9000b", &tvga9000b_device, GFX_TVGA9000B, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 7, 7, 12, 7, 7, 12}}, + {"Trident TGUI9400CXi", "tgui9400cxi", &tgui9400cxi_device, GFX_TGUI9400CXI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, + {"Trident TGUI9440", "tgui9440", &tgui9440_device, GFX_TGUI9440, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 8, 16, 4, 8, 16}}, + {"Trigem Korean VGA (Tseng ET4000AX)", "tgkorvga", &et4000k_device, GFX_TGKOREANVGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"Tseng ET4000AX", "et4000ax", &et4000_device, GFX_ET4000, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 3, 3, 6, 5, 5, 10}}, + {"VGA", "vga", &vga_device, GFX_VGA, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"Wyse 700", "wy700", &wy700_device, GFX_WY700, VIDEO_FLAG_TYPE_CGA, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, + {"", "", NULL, 0} }; +static video_timings_t timing_dram = {VIDEO_BUS, 0,0,0, 0,0,0}; /*No additional waitstates*/ +static video_timings_t timing_pc1512 = {VIDEO_BUS, 0,0,0, 0,0,0}; /*PC1512 video code handles waitstates itself*/ +static video_timings_t timing_pc1640 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_pc200 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_m24 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_pvga1a = {VIDEO_ISA, 6, 8,16, 6, 8,16}; +static video_timings_t timing_wd90c11 = {VIDEO_ISA, 3, 3, 6, 5, 5,10}; +static video_timings_t timing_avga2 = {VIDEO_ISA, 3, 3, 6, 5, 5,10}; +static video_timings_t timing_oti067 = {VIDEO_ISA, 6, 8,16, 6, 8,16}; +static video_timings_t timing_vga = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_ps1_svga = {VIDEO_ISA, 6, 8,16, 6, 8,16}; +static video_timings_t timing_t3100e = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_t1000 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_spc4620p = {VIDEO_ISA, 2, 2, 4, 4, 4, 8}; +static video_timings_t timing_pc425x = {VIDEO_BUS, 5, 5, 9, 20,20,30}; +static video_timings_t timing_pb410a = {VIDEO_BUS, 5, 5, 9, 20,20,30}; +static video_timings_t timing_pb570 = {VIDEO_BUS, 4, 4, 8, 10,10,20}; +static video_timings_t timing_pb520r = {VIDEO_BUS, 4, 4, 8, 10,10,20}; + int video_card_available(int card) { + if (card == GFX_BUILTIN) + return 1; + if (video_cards[card].device) return device_available(video_cards[card].device); @@ -90,17 +167,129 @@ int video_card_available(int card) char *video_card_getname(int card) { + if (card == GFX_BUILTIN) + return "Built-in video"; return video_cards[card].name; } -device_t *video_card_getdevice(int card) +device_t *video_card_getdevice(int card, int romset) { + switch (romset) + { + case ROM_IBMPCJR: + return &pcjr_video_device; + + case ROM_TANDY: + case ROM_TANDY1000HX: + return &tandy_device; + + case ROM_TANDY1000SL2: + return &tandysl_device; + + case ROM_PC1512: + return &pc1512_device; + + case ROM_PC1640: + if (card == GFX_BUILTIN) + return &pc1640_device; + break; + + case ROM_PC200: + if (card == GFX_BUILTIN) + return &pc200_device; + break; + + case ROM_PPC512: + if (card == GFX_BUILTIN) + return &ppc512_device; + break; + + case ROM_OLIM24: + return &m24_device; + + case ROM_PC2086: + if (card == GFX_BUILTIN) + return ¶dise_pvga1a_pc2086_device; + break; + + case ROM_PC3086: + if (card == GFX_BUILTIN) + return ¶dise_pvga1a_pc3086_device; + break; + + case ROM_MEGAPC: + return ¶dise_wd90c11_megapc_device; + + case ROM_SPC4620P: + if (card == GFX_BUILTIN) + return &ati28800k_spc4620p_device; + break; + + case ROM_SPC6033P: + if (card == GFX_BUILTIN) + return &ati28800k_spc6033p_device; + break; + + case ROM_ACER386: + return &oti067_acer386_device; + + case ROM_AMA932J: + return &oti067_ama932j_device; + + case ROM_IBMPS1_2011: + case ROM_IBMPS2_M30_286: + return &ps1vga_device; + + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: + case ROM_IBMPS2_M80: + if (card == GFX_BUILTIN) + return &ps1vga_device; + break; + + case ROM_IBMPS1_2121: + return &ps1_m2121_svga_device; + + case ROM_IBMPS1_2133_451: + return &gd5426_ps1_device; + + case ROM_T3100E: + return &t3100e_device; + + case ROM_T1000: + case ROM_T1200: + return &t1000_device; + + case ROM_ELX_PC425X: + return &tgui9400cxi_elx_device; + + case ROM_PB410A: + return &ht216_32_pb410a_device; + + case ROM_PB570: + return &gd5430_pb570_device; + + case ROM_PB520R: + return &gd5434_pb520r_device; + + case ROM_CBM_SL386SX25: + return &avga2_cbm_sl386sx_device; + } return video_cards[card].device; } -int video_card_has_config(int card) +int video_card_has_config(int card, int romset) { - return video_cards[card].device->config ? 1 : 0; + /* Allow builtin cards to have configuration */ + device_t *device = video_card_getdevice(card, romset); + + if (!device) + { + return 0; + } + return device->config ? 1 : 0; } int video_card_getid(char *s) @@ -114,6 +303,9 @@ int video_card_getid(char *s) c++; } + if (!strcmp(s, "Built-in video")) + return GFX_BUILTIN; + return 0; } @@ -121,6 +313,9 @@ int video_old_to_new(int card) { int c = 0; + if (card == GFX_BUILTIN) + return GFX_BUILTIN; + while (video_cards[c].device) { if (video_cards[c].legacy_id == card) @@ -133,11 +328,17 @@ int video_old_to_new(int card) int video_new_to_old(int card) { + if (card == GFX_BUILTIN) + return GFX_BUILTIN; + return video_cards[card].legacy_id; } char *video_get_internal_name(int card) { + if (card == GFX_BUILTIN) + return "builtin"; + return video_cards[card].internal_name; } @@ -145,6 +346,9 @@ int video_get_video_from_internal_name(char *s) { int c = 0; + if (!strcmp(s, "builtin")) + return GFX_BUILTIN; + while (video_cards[c].legacy_id != -1) { if (!strcmp(video_cards[c].internal_name, s)) @@ -155,6 +359,141 @@ int video_get_video_from_internal_name(char *s) return 0; } +int video_is_mda() +{ + switch (romset) + { + case ROM_PC200: + case ROM_PPC512: + if (gfxcard == GFX_BUILTIN) + { +/* The chipset here can emulate either CGA or MDA. Find out which */ + return (pc200_is_mda); + } + break; + + case ROM_PC1640: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_ACER386: + if (gfxcard != GFX_BUILTIN) + break; + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_OLIM24: + case ROM_IBMPS1_2011: + case ROM_IBMPS2_M30_286: + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: + case ROM_IBMPS2_M80: + case ROM_IBMPS1_2121: + case ROM_IBMPS1_2133_451: + case ROM_T3100E: + case ROM_T1000: + case ROM_ELX_PC425X: + case ROM_PB410A: + case ROM_PB570: + case ROM_PB520R: + case ROM_CBM_SL386SX25: + return 0; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_MDA; +} +int video_is_cga() +{ + switch (romset) + { + case ROM_PC200: + case ROM_PPC512: + if (gfxcard == GFX_BUILTIN) + { +/* The chipset here can emulate either CGA or MDA. Find out which */ + return (!pc200_is_mda); + } + break; + + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_OLIM24: + case ROM_T3100E: + case ROM_T1000: + return 1; + + case ROM_PC1640: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_ACER386: + if (gfxcard != GFX_BUILTIN) + break; + case ROM_IBMPS1_2011: + case ROM_IBMPS2_M30_286: + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: + case ROM_IBMPS2_M80: + case ROM_IBMPS1_2121: + case ROM_IBMPS1_2133_451: + case ROM_ELX_PC425X: + case ROM_PB410A: + case ROM_PB570: + case ROM_PB520R: + case ROM_CBM_SL386SX25: + return 0; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_CGA; +} +int video_is_ega_vga() +{ + switch (romset) + { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_PC200: + case ROM_PPC512: + case ROM_OLIM24: + case ROM_T3100E: + case ROM_T1000: + return 0; + + case ROM_PC1640: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_ACER386: + case ROM_AMA932J: + case ROM_IBMPS1_2011: + case ROM_IBMPS2_M30_286: + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: + case ROM_IBMPS2_M80: + case ROM_IBMPS1_2121: + case ROM_IBMPS1_2133_451: + case ROM_ELX_PC425X: + case ROM_PB410A: + case ROM_PB570: + case ROM_PB520R: + case ROM_CBM_SL386SX25: + return 1; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_SPECIAL; +} + int video_fullscreen = 0, video_fullscreen_scale, video_fullscreen_first; int video_force_aspect_ration = 0; int vid_disc_indicator = 0; @@ -167,6 +506,8 @@ int changeframecount=2; uint8_t rotatevga[8][256]; int frames = 0; +int video_frames = 0; +int video_refresh_rate = 0; int fullchange; @@ -205,14 +546,8 @@ Fast VLB/PCI - L = 4 bus clocks */ -enum -{ - VIDEO_ISA = 0, - VIDEO_BUS -}; - int video_speed = 0; -int video_timing[6][4] = +int video_timing[7][4] = { {VIDEO_ISA, 8, 16, 32}, {VIDEO_ISA, 6, 8, 16}, @@ -224,28 +559,176 @@ int video_timing[6][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 (video_speed == -1) + { + video_timings_t *timing; + int new_gfxcard = 0; + + new_gfxcard = video_old_to_new(gfxcard); + timing = &video_cards[new_gfxcard].timing; + + switch (romset) + { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + timing = &timing_dram; + break; + + case ROM_PC1512: + timing = &timing_pc1512; + break; + + case ROM_PC1640: + if (gfxcard == GFX_BUILTIN) + timing = &timing_pc1640; + break; + + case ROM_PC200: + case ROM_PPC512: + if (gfxcard == GFX_BUILTIN) + timing = &timing_pc200; + break; + + case ROM_OLIM24: + timing = &timing_m24; + break; + + case ROM_PC2086: + case ROM_PC3086: + if (gfxcard == GFX_BUILTIN) + timing = &timing_pvga1a; + break; + + case ROM_MEGAPC: + if (gfxcard == GFX_BUILTIN) + timing = &timing_wd90c11; + break; + + case ROM_SPC4620P: + case ROM_SPC6033P: + if (gfxcard == GFX_BUILTIN) + timing = &timing_spc4620p; + break; + + case ROM_ACER386: + if (gfxcard == GFX_BUILTIN) + timing = &timing_oti067; + break; + + case ROM_AMA932J: + if (gfxcard == GFX_BUILTIN) + timing = &timing_oti067; + break; + + case ROM_IBMPS1_2011: + case ROM_IBMPS2_M30_286: + timing = &timing_vga; + break; + + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: + case ROM_IBMPS2_M80: + if (gfxcard == GFX_BUILTIN) + timing = &timing_vga; + break; + + case ROM_IBMPS1_2121: + timing = &timing_ps1_svga; + break; + + case ROM_IBMPS1_2133_451: + timing = &timing_pb570; + break; + + case ROM_T3100E: + timing = &timing_t3100e; + break; + + case ROM_T1000: + timing = &timing_t1000; + break; + + case ROM_ELX_PC425X: + timing = &timing_pc425x; + break; + + case ROM_PB410A: + if (gfxcard == GFX_BUILTIN) + timing = &timing_pb410a; + break; + + case ROM_PB570: + timing = &timing_pb570; + break; + + case ROM_PB520R: + timing = &timing_pb520r; + break; + + case ROM_CBM_SL386SX25: + timing = &timing_avga2; + break; + } + + + if (timing->type == VIDEO_ISA) + { + video_timing_read_b = ISA_CYCLES(timing->read_b); + video_timing_read_w = ISA_CYCLES(timing->read_w); + video_timing_read_l = ISA_CYCLES(timing->read_l); + video_timing_write_b = ISA_CYCLES(timing->write_b); + video_timing_write_w = ISA_CYCLES(timing->write_w); + video_timing_write_l = ISA_CYCLES(timing->write_l); + } + else + { + video_timing_read_b = (int)(bus_timing * timing->read_b); + video_timing_read_w = (int)(bus_timing * timing->read_w); + video_timing_read_l = (int)(bus_timing * timing->read_l); + video_timing_write_b = (int)(bus_timing * timing->write_b); + video_timing_write_w = (int)(bus_timing * timing->write_w); + video_timing_write_l = (int)(bus_timing * timing->write_l); + } + } + else + { + if (video_timing[video_speed][0] == VIDEO_ISA) + { + video_timing_read_b = ISA_CYCLES(video_timing[video_speed][1]); + video_timing_read_w = ISA_CYCLES(video_timing[video_speed][2]); + video_timing_read_l = ISA_CYCLES(video_timing[video_speed][3]); + video_timing_write_b = ISA_CYCLES(video_timing[video_speed][1]); + video_timing_write_w = ISA_CYCLES(video_timing[video_speed][2]); + video_timing_write_l = ISA_CYCLES(video_timing[video_speed][3]); + } + else + { + video_timing_read_b = (int)(bus_timing * video_timing[video_speed][1]); + video_timing_read_w = (int)(bus_timing * video_timing[video_speed][2]); + video_timing_read_l = (int)(bus_timing * video_timing[video_speed][3]); + video_timing_write_b = (int)(bus_timing * video_timing[video_speed][1]); + video_timing_write_w = (int)(bus_timing * video_timing[video_speed][2]); + video_timing_write_l = (int)(bus_timing * video_timing[video_speed][3]); + } } + pclog("Video timing %i %i %i\n",video_timing_write_b, video_timing_write_w,video_timing_write_l); if (cpu_16bitbus) - video_timing_l = video_timing_w * 2; + { + video_timing_read_l = video_timing_read_w * 2; + video_timing_write_l = video_timing_write_w * 2; + } } -int video_timing_b, video_timing_w, video_timing_l; +int video_timing_read_b, video_timing_read_w, video_timing_read_l; +int video_timing_write_b, video_timing_write_w, video_timing_write_l; int video_res_x, video_res_y, video_bpp; void (*video_blit_memtoscreen_func)(int x, int y, int y1, int y2, int w, int h); -void (*video_blit_memtoscreen_8_func)(int x, int y, int w, int h); void video_init() { @@ -271,71 +754,182 @@ void video_init() return; case ROM_PC1640: - device_add(&pc1640_device); - return; + if (gfxcard == GFX_BUILTIN) + { + device_add(&pc1640_device); + return; + } + break; case ROM_PC200: - device_add(&pc200_device); - return; + if (gfxcard == GFX_BUILTIN) + { + device_add(&pc200_device); + return; + } + break; + + case ROM_PPC512: + if (gfxcard == GFX_BUILTIN) + { + device_add(&ppc512_device); + return; + } + break; case ROM_OLIM24: device_add(&m24_device); return; case ROM_PC2086: - device_add(¶dise_pvga1a_pc2086_device); - return; + if (gfxcard == GFX_BUILTIN) + { + device_add(¶dise_pvga1a_pc2086_device); + return; + } + break; case ROM_PC3086: - device_add(¶dise_pvga1a_pc3086_device); - return; + if (gfxcard == GFX_BUILTIN) + { + device_add(¶dise_pvga1a_pc3086_device); + return; + } + break; case ROM_MEGAPC: - device_add(¶dise_wd90c11_megapc_device); + if (gfxcard == GFX_BUILTIN) + { + device_add(¶dise_wd90c11_megapc_device); + return; + } + break; + + case ROM_SPC4620P: + if (gfxcard == GFX_BUILTIN) + { + device_add(&ati28800k_spc4620p_device); + return; + } + break; + + case ROM_SPC6033P: + if (gfxcard == GFX_BUILTIN) + { + device_add(&ati28800k_spc6033p_device); + return; + } + break; + + case ROM_ACER386: + device_add(&oti067_acer386_device); + if (gfxcard != GFX_BUILTIN) + { + svga_set_override(svga_get_pri(), 1); + break; + } return; - case ROM_ACER386: - device_add(&oti067_device); + case ROM_AMA932J: + device_add(&oti067_ama932j_device); return; case ROM_IBMPS1_2011: case ROM_IBMPS2_M30_286: - case ROM_IBMPS2_M50: - case ROM_IBMPS2_M55SX: - case ROM_IBMPS2_M80: device_add(&ps1vga_device); return; + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M70_TYPE3: + case ROM_IBMPS2_M70_TYPE4: + case ROM_IBMPS2_M80: + device_add(&ps1vga_device); + if (gfxcard == GFX_BUILTIN) + return; + break; + case ROM_IBMPS1_2121: device_add(&ps1_m2121_svga_device); return; + + case ROM_IBMPS1_2133_451: + device_add(&gd5426_ps1_device); + return; + + case ROM_T3100E: + device_add(&t3100e_device); + return; + + case ROM_T1000: + case ROM_T1200: + device_add(&t1000_device); + return; + + case ROM_ELX_PC425X: + device_add(&tgui9400cxi_elx_device); + return; + + case ROM_PB410A: + device_add(&ht216_32_pb410a_device); + if (gfxcard != GFX_BUILTIN) + { + svga_set_override(svga_get_pri(), 1); + break; + } + return; + + case ROM_PB570: + device_add(&gd5430_pb570_device); + if (gfxcard != GFX_BUILTIN) + { + svga_set_override(svga_get_pri(), 1); + break; + } + return; + + case ROM_PB520R: + device_add(&gd5434_pb520r_device); + if (gfxcard != GFX_BUILTIN) + { + svga_set_override(svga_get_pri(), 1); + break; + } + return; + + case ROM_CBM_SL386SX25: + device_add(&avga2_cbm_sl386sx_device); + return; } device_add(video_cards[video_old_to_new(gfxcard)].device); } -BITMAP *buffer, *buffer32; +BITMAP *buffer32; -uint8_t fontdat[256][8]; -uint8_t fontdatm[256][16]; +uint8_t fontdat[2048][8]; +uint8_t fontdatm[2048][16]; uint8_t fontdatw[512][32]; /* Wyse700 font */ uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ +uint8_t fontdat12x18[256][36]; /* IM1024 font */ +uint8_t fontdatksc5601[16384][32]; /* Korean KSC-5601 font */ +uint8_t fontdatksc5601_user[192][32]; /* Korean KSC-5601 user defined font */ int xsize=1,ysize=1; -PALETTE cgapal; - -void loadfont(char *s, int format) +void loadfont(char *s, fontformat_t format) { FILE *f=romfopen(s,"rb"); int c,d; + + pclog("loadfont %i %s %p\n", format, s, f); if (!f) { return; } switch (format) { - case 0: /* MDA */ + case FONT_MDA: /* MDA */ for (c=0;c<256;c++) { for (d=0;d<8;d++) @@ -359,34 +953,23 @@ void loadfont(char *s, int format) } } break; - case 1: /* PC200 */ - for (c=0;c<256;c++) - { - for (d=0;d<8;d++) + case FONT_PC200: /* PC200 */ + for (d=0;d<4;d++) /* There are 4 fonts in the ROM */ + { + for (c=0;c<256;c++) /* 8x14 MDA in 8x16 cell */ + { + fread(&fontdatm[256*d+c], 1, 16, f); + } + for (c=0;c<256; c++) /* 8x8 CGA in 8x16 cell */ { - fontdatm[c][d]=getc(f); + fread(fontdat[256*d+c], 1, 8, f); + fseek(f, 8, SEEK_CUR); } } - 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); - } break; default: - case 2: /* CGA */ - for (c=0;c<256;c++) + case FONT_CGA: /* CGA */ + for (c=0;c<2048;c++) /* Allow up to 2048 chars */ { for (d=0;d<8;d++) { @@ -394,7 +977,7 @@ void loadfont(char *s, int format) } } break; - case 3: /* Wyse 700 */ + case FONT_WY700: /* Wyse 700 */ for (c=0;c<512;c++) { for (d=0;d<32;d++) @@ -403,7 +986,7 @@ void loadfont(char *s, int format) } } break; - case 4: /* MDSI Genius */ + case FONT_MDSI: /* MDSI Genius */ for (c=0;c<256;c++) { for (d=0;d<16;d++) @@ -412,6 +995,64 @@ void loadfont(char *s, int format) } } break; + case FONT_T3100E: /* Toshiba 3100e */ + for (d = 0; d < 2048; d += 512) /* Four languages... */ + { + for (c = d; c < d+256; c++) + { + fread(&fontdatm[c][8], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdatm[c][8], 1, 8, f); + } + for (c = d; c < d+256; c++) + { + fread(&fontdatm[c][0], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdatm[c][0], 1, 8, f); + } + fseek(f, 4096, SEEK_CUR); /* Skip blank section */ + for (c = d; c < d+256; c++) + { + fread(&fontdat[c][0], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdat[c][0], 1, 8, f); + } + } + break; + case FONT_KSC5601: /* Korean KSC-5601 */ + for (c=0;c<16384;c++) + { + for (d=0;d<32;d++) + { + fontdatksc5601[c][d]=getc(f); + } + } + break; + case FONT_SIGMA400: /* Sigma Color 400 */ + /* The first 4k of the character ROM holds an 8x8 font */ + for (c = 0; c < 256; c++) + { + fread(&fontdat[c][0], 1, 8, f); + fseek(f, 8, SEEK_CUR); + } + /* The second 4k holds an 8x16 font */ + for (c = 0; c < 256; c++) + { + fread(&fontdatm[c][0], 1, 16, f); + } + break; + case FONT_IM1024: /* Image Manager 1024 native font */ + for (c=0;c<256;c++) + { + fread(&fontdat12x18[c][0], 1, 36, f); + } + break; } fclose(f); @@ -419,7 +1060,7 @@ void loadfont(char *s, int format) static struct { - int x, y, y1, y2, w, h, blit8; + int x, y, y1, y2, w, h; int busy; int buffer_in_use; @@ -431,29 +1072,14 @@ static struct static void blit_thread(void *param); +uint32_t cgapal[16]; + void initvideo() { int c, d, e; buffer32 = create_bitmap(2048, 2048); - buffer = create_bitmap(2048, 2048); - - 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; @@ -484,6 +1110,8 @@ void initvideo() for (c = 0; c < 65536; c++) video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19); + cgapal_rebuild(DISPLAY_RGB, 0); + blit_data.wake_blit_thread = thread_create_event(); blit_data.blit_complete = thread_create_event(); blit_data.buffer_not_in_use = thread_create_event(); @@ -499,7 +1127,6 @@ void closevideo() free(video_15to32); free(video_16to32); - destroy_bitmap(buffer); destroy_bitmap(buffer32); } @@ -511,10 +1138,7 @@ static void blit_thread(void *param) thread_wait_event(blit_data.wake_blit_thread, -1); thread_reset_event(blit_data.wake_blit_thread); - if (blit_data.blit8) - video_blit_memtoscreen_8_func(blit_data.x, blit_data.y, blit_data.w, blit_data.h); - else - video_blit_memtoscreen_func(blit_data.x, blit_data.y, blit_data.y1, blit_data.y2, blit_data.w, blit_data.h); + video_blit_memtoscreen_func(blit_data.x, blit_data.y, blit_data.y1, blit_data.y2, blit_data.w, blit_data.h); blit_data.busy = 0; thread_set_event(blit_data.blit_complete); @@ -542,6 +1166,9 @@ void video_wait_for_buffer() void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) { + video_frames++; + if (h <= 0) + return; video_wait_for_blit(); blit_data.busy = 1; blit_data.buffer_in_use = 1; @@ -551,18 +1178,158 @@ void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) blit_data.y2 = y2; blit_data.w = w; blit_data.h = h; - blit_data.blit8 = 0; thread_set_event(blit_data.wake_blit_thread); } -void video_blit_memtoscreen_8(int x, int y, int w, int h) +void cgapal_rebuild(int display_type, int contrast) { - video_wait_for_blit(); - blit_data.busy = 1; - blit_data.x = x; - blit_data.y = y; - blit_data.w = w; - blit_data.h = h; - blit_data.blit8 = 1; - thread_set_event(blit_data.wake_blit_thread); + switch (display_type) + { + case DISPLAY_GREEN: + if (contrast) + { + cgapal[0x0] = makecol(0x00, 0x00, 0x00); + cgapal[0x1] = makecol(0x00, 0x34, 0x0c); + cgapal[0x2] = makecol(0x04, 0x5d, 0x14); + cgapal[0x3] = makecol(0x04, 0x69, 0x18); + cgapal[0x4] = makecol(0x08, 0xa2, 0x24); + cgapal[0x5] = makecol(0x08, 0xb2, 0x28); + cgapal[0x6] = makecol(0x0c, 0xe7, 0x34); + cgapal[0x7] = makecol(0x0c, 0xf3, 0x38); + cgapal[0x8] = makecol(0x00, 0x1c, 0x04); + cgapal[0x9] = makecol(0x04, 0x4d, 0x10); + cgapal[0xa] = makecol(0x04, 0x7d, 0x1c); + cgapal[0xb] = makecol(0x04, 0x8e, 0x20); + cgapal[0xc] = makecol(0x08, 0xc7, 0x2c); + cgapal[0xd] = makecol(0x08, 0xd7, 0x30); + cgapal[0xe] = makecol(0x14, 0xff, 0x45); + cgapal[0xf] = makecol(0x34, 0xff, 0x5d); + } + else + { + cgapal[0x0] = makecol(0x00, 0x00, 0x00); + cgapal[0x1] = makecol(0x00, 0x34, 0x0c); + cgapal[0x2] = makecol(0x04, 0x55, 0x14); + cgapal[0x3] = makecol(0x04, 0x5d, 0x14); + cgapal[0x4] = makecol(0x04, 0x86, 0x20); + cgapal[0x5] = makecol(0x04, 0x92, 0x20); + cgapal[0x6] = makecol(0x08, 0xba, 0x2c); + cgapal[0x7] = makecol(0x08, 0xc7, 0x2c); + cgapal[0x8] = makecol(0x04, 0x8a, 0x20); + cgapal[0x9] = makecol(0x08, 0xa2, 0x24); + cgapal[0xa] = makecol(0x08, 0xc3, 0x2c); + cgapal[0xb] = makecol(0x08, 0xcb, 0x30); + cgapal[0xc] = makecol(0x0c, 0xe7, 0x34); + cgapal[0xd] = makecol(0x0c, 0xef, 0x38); + cgapal[0xe] = makecol(0x24, 0xff, 0x51); + cgapal[0xf] = makecol(0x34, 0xff, 0x5d); + } + break; + case DISPLAY_AMBER: + if (contrast) + { + cgapal[0x0] = makecol(0x00, 0x00, 0x00); + cgapal[0x1] = makecol(0x55, 0x14, 0x00); + cgapal[0x2] = makecol(0x82, 0x2c, 0x00); + cgapal[0x3] = makecol(0x92, 0x34, 0x00); + cgapal[0x4] = makecol(0xcf, 0x61, 0x00); + cgapal[0x5] = makecol(0xdf, 0x6d, 0x00); + cgapal[0x6] = makecol(0xff, 0x9a, 0x04); + cgapal[0x7] = makecol(0xff, 0xae, 0x18); + cgapal[0x8] = makecol(0x2c, 0x08, 0x00); + cgapal[0x9] = makecol(0x6d, 0x20, 0x00); + cgapal[0xa] = makecol(0xa6, 0x45, 0x00); + cgapal[0xb] = makecol(0xba, 0x51, 0x00); + cgapal[0xc] = makecol(0xef, 0x79, 0x00); + cgapal[0xd] = makecol(0xfb, 0x86, 0x00); + cgapal[0xe] = makecol(0xff, 0xcb, 0x28); + cgapal[0xf] = makecol(0xff, 0xe3, 0x34); + } + else + { + cgapal[0x0] = makecol(0x00, 0x00, 0x00); + cgapal[0x1] = makecol(0x55, 0x14, 0x00); + cgapal[0x2] = makecol(0x79, 0x24, 0x00); + cgapal[0x3] = makecol(0x86, 0x2c, 0x00); + cgapal[0x4] = makecol(0xae, 0x49, 0x00); + cgapal[0x5] = makecol(0xbe, 0x55, 0x00); + cgapal[0x6] = makecol(0xe3, 0x71, 0x00); + cgapal[0x7] = makecol(0xef, 0x79, 0x00); + cgapal[0x8] = makecol(0xb2, 0x4d, 0x00); + cgapal[0x9] = makecol(0xcb, 0x5d, 0x00); + cgapal[0xa] = makecol(0xeb, 0x79, 0x00); + cgapal[0xb] = makecol(0xf3, 0x7d, 0x00); + cgapal[0xc] = makecol(0xff, 0x9e, 0x04); + cgapal[0xd] = makecol(0xff, 0xaa, 0x10); + cgapal[0xe] = makecol(0xff, 0xdb, 0x30); + cgapal[0xf] = makecol(0xff, 0xe3, 0x34); + } + break; + case DISPLAY_WHITE: + if (contrast) + { + cgapal[0x0] = makecol(0x00, 0x00, 0x00); + cgapal[0x1] = makecol(0x37, 0x3d, 0x40); + cgapal[0x2] = makecol(0x55, 0x5c, 0x5f); + cgapal[0x3] = makecol(0x61, 0x67, 0x6b); + cgapal[0x4] = makecol(0x8f, 0x95, 0x95); + cgapal[0x5] = makecol(0x9b, 0xa0, 0x9f); + cgapal[0x6] = makecol(0xcc, 0xcf, 0xc8); + cgapal[0x7] = makecol(0xdf, 0xde, 0xd4); + cgapal[0x8] = makecol(0x24, 0x27, 0x29); + cgapal[0x9] = makecol(0x42, 0x48, 0x4c); + cgapal[0xa] = makecol(0x70, 0x76, 0x78); + cgapal[0xb] = makecol(0x81, 0x87, 0x87); + cgapal[0xc] = makecol(0xaf, 0xb3, 0xb0); + cgapal[0xd] = makecol(0xbb, 0xbf, 0xba); + cgapal[0xe] = makecol(0xef, 0xed, 0xdf); + cgapal[0xf] = makecol(0xff, 0xfd, 0xed); + } + else + { + cgapal[0x0] = makecol(0x00, 0x00, 0x00); + cgapal[0x1] = makecol(0x37, 0x3d, 0x40); + cgapal[0x2] = makecol(0x4a, 0x50, 0x54); + cgapal[0x3] = makecol(0x55, 0x5c, 0x5f); + cgapal[0x4] = makecol(0x78, 0x7e, 0x80); + cgapal[0x5] = makecol(0x81, 0x87, 0x87); + cgapal[0x6] = makecol(0xa3, 0xa7, 0xa6); + cgapal[0x7] = makecol(0xaf, 0xb3, 0xb0); + cgapal[0x8] = makecol(0x7a, 0x81, 0x83); + cgapal[0x9] = makecol(0x8c, 0x92, 0x92); + cgapal[0xa] = makecol(0xac, 0xb0, 0xad); + cgapal[0xb] = makecol(0xb3, 0xb7, 0xb4); + cgapal[0xc] = makecol(0xd1, 0xd3, 0xcb); + cgapal[0xd] = makecol(0xd9, 0xdb, 0xd2); + cgapal[0xe] = makecol(0xf7, 0xf5, 0xe7); + cgapal[0xf] = makecol(0xff, 0xfd, 0xed); + } + break; + + default: + cgapal[0x0] = makecol(0x00, 0x00, 0x00); + cgapal[0x1] = makecol(0x00, 0x00, 0xaa); + cgapal[0x2] = makecol(0x00, 0xaa, 0x00); + cgapal[0x3] = makecol(0x00, 0xaa, 0xaa); + cgapal[0x4] = makecol(0xaa, 0x00, 0x00); + cgapal[0x5] = makecol(0xaa, 0x00, 0xaa); + if (display_type == DISPLAY_RGB_NO_BROWN) + { + cgapal[0x6] = makecol(0xaa, 0xaa, 0x00); + } + else + { + cgapal[0x6] = makecol(0xaa, 0x55, 0x00); + } + cgapal[0x7] = makecol(0xaa, 0xaa, 0xaa); + cgapal[0x8] = makecol(0x55, 0x55, 0x55); + cgapal[0x9] = makecol(0x55, 0x55, 0xff); + cgapal[0xa] = makecol(0x55, 0xff, 0x55); + cgapal[0xb] = makecol(0x55, 0xff, 0xff); + cgapal[0xc] = makecol(0xff, 0x55, 0x55); + cgapal[0xd] = makecol(0xff, 0x55, 0xff); + cgapal[0xe] = makecol(0xff, 0xff, 0x55); + cgapal[0xf] = makecol(0xff, 0xff, 0xff); + break; + } } diff --git a/src/video.h b/src/video.h index f7fa3e7..459abcb 100644 --- a/src/video.h +++ b/src/video.h @@ -1,11 +1,3 @@ -#ifdef __unix - -#undef MAX_JOYSTICKS -#include "allegro-main.h" -#define MAX_JOYSTICKS 4 - -#else - typedef struct { int w, h; @@ -27,19 +19,20 @@ 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; +extern BITMAP *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); +struct device_t *video_card_getdevice(int card, int romset); +int video_card_has_config(int card, int romset); int video_card_getid(char *s); int video_old_to_new(int card); int video_new_to_old(int card); char *video_get_internal_name(int card); int video_get_video_from_internal_name(char *s); +int video_is_mda(); +int video_is_cga(); +int video_is_ega_vga(); extern int video_fullscreen, video_fullscreen_scale, video_fullscreen_first; extern int video_force_aspect_ration; @@ -58,8 +51,10 @@ extern int egareads,egawrites; extern int fullchange; extern int changeframecount; -extern uint8_t fontdat[256][8]; -extern uint8_t fontdatm[256][16]; +extern uint8_t fontdat[2048][8]; +extern uint8_t fontdatm[2048][16]; +extern uint8_t fontdatksc5601[16384][32]; +extern uint8_t fontdatksc5601_user[192][32]; extern uint32_t *video_15to32, *video_16to32; @@ -67,19 +62,18 @@ extern int xsize,ysize; extern float cpuclock; -extern int emu_fps, frames; +extern int emu_fps, frames, video_frames, video_refresh_rate; extern int readflash; extern void (*video_recalctimings)(); 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); extern void (*video_blit_memtoscreen_func)(int x, int y, int y1, int y2, int w, int h); -extern void (*video_blit_memtoscreen_8_func)(int x, int y, int w, int h); -extern int video_timing_b, video_timing_w, video_timing_l; +extern int video_timing_read_b, video_timing_read_w, video_timing_read_l; +extern int video_timing_write_b, video_timing_write_w, video_timing_write_l; extern int video_speed; extern int video_res_x, video_res_y, video_bpp; @@ -88,7 +82,21 @@ extern int vid_resize; void video_wait_for_blit(); void video_wait_for_buffer(); -void loadfont(char *s, int format); + +typedef enum +{ + FONT_MDA, /* MDA 8x14 */ + FONT_PC200, /* MDA 8x14 and CGA 8x8, four fonts */ + FONT_CGA, /* CGA 8x8, two fonts */ + FONT_WY700, /* Wy700 16x16, two fonts */ + FONT_MDSI, /* MDSI Genius 8x12 */ + FONT_T3100E, /* Toshiba T3100e, four fonts */ + FONT_KSC5601, /* Korean KSC-5601 */ + FONT_SIGMA400, /* Sigma Color 400, 8x8 and 8x16 */ + FONT_IM1024, /* Image Manager 1024 */ +} fontformat_t; + +void loadfont(char *s, fontformat_t format); void initvideo(); void video_init(); @@ -99,3 +107,14 @@ void video_updatetiming(); void hline(BITMAP *b, int x1, int y, int x2, int col); void destroy_bitmap(BITMAP *b); + +extern uint32_t cgapal[16]; + +#define DISPLAY_RGB 0 +#define DISPLAY_COMPOSITE 1 +#define DISPLAY_RGB_NO_BROWN 2 +#define DISPLAY_GREEN 3 +#define DISPLAY_AMBER 4 +#define DISPLAY_WHITE 5 + +void cgapal_rebuild(int display_type, int contrast); diff --git a/src/vl82c480.c b/src/vl82c480.c new file mode 100644 index 0000000..57bcce5 --- /dev/null +++ b/src/vl82c480.c @@ -0,0 +1,169 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "vl82c480.h" + +static struct +{ + int cfg_index; + uint8_t cfg_regs[256]; + + uint8_t port_92; +} vl82c480; + +#define CFG_ID 0x00 +#define CFG_AAXS 0x0d +#define CFG_BAXS 0x0e +#define CFG_CAXS 0x0f +#define CFG_DAXS 0x10 +#define CFG_EAXS 0x11 +#define CFG_FAXS 0x12 + +#define ID_VL82C480 0x90 + +static void shadow_control(uint32_t addr, uint32_t size, int state) +{ +// pclog("shadow_control: addr=%08x size=%04x state=%i\n", addr, size, state); + switch (state) + { + 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_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void vl82c480_write(uint16_t addr, uint8_t val, void *p) +{ +// if (addr != 0x92) pclog("vl82c480_write: addr=%04x val=%02x\n", addr, val); + switch (addr) + { + case 0x92: + if ((mem_a20_alt ^ val) & 2) + { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~vl82c480.port_92 & val) & 1) + { + softresetx86(); + cpu_set_edx(); + } + vl82c480.port_92 = val; + break; + + case 0xec: + vl82c480.cfg_index = val; + break; + + case 0xed: + if (vl82c480.cfg_index >= 0x01 && vl82c480.cfg_index <= 0x24) + { + vl82c480.cfg_regs[vl82c480.cfg_index] = val; + switch (vl82c480.cfg_index) + { + case CFG_AAXS: + shadow_control(0xa0000, 0x4000, val & 3); + shadow_control(0xa4000, 0x4000, (val >> 2) & 3); + shadow_control(0xa8000, 0x4000, (val >> 4) & 3); + shadow_control(0xac000, 0x4000, (val >> 6) & 3); + break; + case CFG_BAXS: + shadow_control(0xb0000, 0x4000, val & 3); + shadow_control(0xb4000, 0x4000, (val >> 2) & 3); + shadow_control(0xb8000, 0x4000, (val >> 4) & 3); + shadow_control(0xbc000, 0x4000, (val >> 6) & 3); + break; + case CFG_CAXS: + shadow_control(0xc0000, 0x4000, val & 3); + shadow_control(0xc4000, 0x4000, (val >> 2) & 3); + shadow_control(0xc8000, 0x4000, (val >> 4) & 3); + shadow_control(0xcc000, 0x4000, (val >> 6) & 3); + break; + case CFG_DAXS: + shadow_control(0xd0000, 0x4000, val & 3); + shadow_control(0xd4000, 0x4000, (val >> 2) & 3); + shadow_control(0xd8000, 0x4000, (val >> 4) & 3); + shadow_control(0xdc000, 0x4000, (val >> 6) & 3); + break; + case CFG_EAXS: + shadow_control(0xe0000, 0x4000, val & 3); + shadow_control(0xe4000, 0x4000, (val >> 2) & 3); + shadow_control(0xe8000, 0x4000, (val >> 4) & 3); + shadow_control(0xec000, 0x4000, (val >> 6) & 3); + break; + case CFG_FAXS: + shadow_control(0xf0000, 0x4000, val & 3); + shadow_control(0xf4000, 0x4000, (val >> 2) & 3); + shadow_control(0xf8000, 0x4000, (val >> 4) & 3); + shadow_control(0xfc000, 0x4000, (val >> 6) & 3); + break; + } + } + break; + + case 0xee: + if (mem_a20_alt) + { + vl82c480.port_92 &= ~2; + mem_a20_alt = 0; + mem_a20_recalc(); + } + break; + } +} + +uint8_t vl82c480_read(uint16_t addr, void *p) +{ + uint8_t ret = 0xff; + + switch (addr) + { + case 0x92: + ret = vl82c480.port_92; + break; + + case 0xec: + ret = vl82c480.cfg_index; + break; + + case 0xed: + ret = vl82c480.cfg_regs[vl82c480.cfg_index]; + break; + + case 0xee: + if (!mem_a20_alt) + { + vl82c480.port_92 |= 2; + mem_a20_alt = 1; + mem_a20_recalc(); + } + break; + + case 0xef: + softresetx86(); + cpu_set_edx(); + break; + } + +// pclog("vl82c480_read: addr=%04x ret=%02x\n", addr, ret); + return ret; +} + +void vl82c480_init(void) +{ + memset(&vl82c480, 0, sizeof(vl82c480)); + vl82c480.cfg_regs[CFG_ID] = ID_VL82C480; + + io_sethandler(0x0092, 0x0001, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, NULL); + io_sethandler(0x00ec, 0x0004, vl82c480_read, NULL, NULL, vl82c480_write, NULL, NULL, NULL); +} diff --git a/src/vl82c480.h b/src/vl82c480.h new file mode 100644 index 0000000..07cf6f7 --- /dev/null +++ b/src/vl82c480.h @@ -0,0 +1 @@ +void vl82c480_init(void); diff --git a/src/vt82c586b.c b/src/vt82c586b.c new file mode 100644 index 0000000..1235317 --- /dev/null +++ b/src/vt82c586b.c @@ -0,0 +1,526 @@ +#include + +#include "ibm.h" +#include "ide.h" +#include "ide_sff8038i.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "x86.h" + +#include "vt82c586b.h" + +static struct +{ + uint8_t pci_isa_bridge_regs[256]; + uint8_t ide_regs[256]; + uint8_t usb_regs[256]; + uint8_t power_regs[256]; + + uint8_t sysctrl; + + sff_busmaster_t busmaster[2]; + + struct + { + uint16_t io_base; + } usb; + struct + { + uint16_t io_base; + + uint16_t pm_status; + uint16_t pm_enable; + uint16_t pm_ctrl; + + uint16_t gbl_status; + uint16_t gbl_enable; + uint16_t gbl_ctrl; + + uint8_t smi_cmd; + } power; +} vt82c586b; + +#define ACPI_TIMER_FREQ 3579545 + +#define ACPI_IO_ENABLE (1 << 7) +#define ACPI_TIMER_32BIT (1 << 3) + +#define GBL_SW_SMI_STS (1 << 6) +#define GBL_SW_SMI_EN (1 << 6) + +#define PM_CTRL_SLP_EN (1 << 13) +#define PM_CTRL_SLP_TYP_MASK (7 << 10) + +static uint8_t vt82c586b_read(int func, int addr, void *priv) +{ + switch (func) + { + case 0: + return vt82c586b.pci_isa_bridge_regs[addr]; + + case 1: + return vt82c586b.ide_regs[addr]; + + case 2: + return vt82c586b.usb_regs[addr]; + + case 3: + return vt82c586b.power_regs[addr]; + + default: + return 0xff; + } +} + +static void vt82c586b_pci_isa_bridge_write(int addr, uint8_t val) +{ + /*Read-only addresses*/ + if ((addr < 4) || (addr == 5) || (addr == 6) + || (addr >= 8 && addr < 0x40) + || (addr == 0x49) + || (addr == 0x4b) + || (addr >= 0x51 && addr < 0x54) + || (addr >= 0x5d && addr < 0x60) + || (addr >= 0x68 && addr < 0x6a) + || (addr >= 0x71)) + return; + + switch (addr) + { + case 4: + vt82c586b.pci_isa_bridge_regs[4] = (val & 8) | 7; + break; + case 6: + vt82c586b.pci_isa_bridge_regs[6] &= ~(val & 0xb0); + break; + + case 0x47: + if ((val & 0x81) == 0x81) + resetx86(); + vt82c586b.pci_isa_bridge_regs[0x47] = val & 0xfe; + break; + + case 0x55: + if (!(val & 0xf0)) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val >> 4); + vt82c586b.pci_isa_bridge_regs[0x55] = val; + break; + case 0x56: + if (!(val & 0xf0)) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val >> 4); + if (!(val & 0x0f)) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + vt82c586b.pci_isa_bridge_regs[0x56] = val; + break; + case 0x57: + if (!(val & 0xf0)) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val >> 4); + vt82c586b.pci_isa_bridge_regs[0x57] = val; + break; + + default: + vt82c586b.pci_isa_bridge_regs[addr] = val; + break; + } +} +static void vt82c586b_ide_write(int addr, uint8_t val) +{ + /*Read-only addresses*/ + if ((addr < 4) || (addr == 5) || (addr == 8) + || (addr >= 0xa && addr < 0x0d) + || (addr >= 0x0e && addr < 0x20) + || (addr >= 0x22 && addr < 0x3c) + || (addr >= 0x3d && addr < 0x40) + || (addr >= 0x54 && addr < 0x60) + || (addr >= 0x52 && addr < 0x68) + || (addr >= 0x62)) + return; + + switch (addr) + { + case 4: + vt82c586b.ide_regs[4] = val & 0x85; + break; + case 6: + vt82c586b.ide_regs[6] &= ~(val & 0xb0); + break; + + case 9: + vt82c586b.ide_regs[9] = (vt82c586b.pci_isa_bridge_regs[9] & ~0x70) | 0x8a; + break; + + case 0x20: + vt82c586b.ide_regs[0x20] = (val & ~0xf) | 1; + break; + + default: + vt82c586b.ide_regs[addr] = val; + break; + } + + if (addr == 4 || (addr & ~3) == 0x20) /*Bus master base address*/ + { + uint16_t base = (vt82c586b.ide_regs[0x20] & 0xf0) | (vt82c586b.ide_regs[0x21] << 8); + io_removehandler(0, 0x10000, sff_bus_master_read, NULL, NULL, sff_bus_master_write, NULL, NULL, vt82c586b.busmaster); + if (vt82c586b.ide_regs[0x04] & 1) + io_sethandler(base, 0x10, sff_bus_master_read, NULL, NULL, sff_bus_master_write, NULL, NULL, vt82c586b.busmaster); + } + if (addr == 4 || addr == 0x40) + { + ide_pri_disable(); + ide_sec_disable(); + if (vt82c586b.ide_regs[0x04] & 1) + { + if (vt82c586b.ide_regs[0x40] & 0x02) + ide_pri_enable(); + if (vt82c586b.ide_regs[0x40] & 0x01) + ide_sec_enable(); + } + } +} + +static uint8_t usb_reg_read(uint16_t addr, void *p) +{ +// pclog("usb_reg_read: addr=%04x\n", addr); + switch (addr & 0x1f) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Port status*/ + return 0; + } + return 0xff; +} +static void usb_reg_write(uint16_t addr, uint8_t val, void *p) +{ +// pclog("usb_reg_write: addr=%04x val=%02x\n", addr, val); +} +static void usb_update_io_mapping() +{ + io_removehandler(vt82c586b.usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, NULL); + vt82c586b.usb.io_base = (vt82c586b.usb_regs[0x20] & ~0x1f) | (vt82c586b.usb_regs[0x21] << 8); + if (vt82c586b.usb_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + io_sethandler(vt82c586b.usb.io_base, 0x20, usb_reg_read, NULL, NULL, usb_reg_write, NULL, NULL, NULL); +} +static void vt82c586b_usb_write(int addr, uint8_t val) +{ + /*Read-only addresses*/ + if ((addr < 4) || (addr == 5) || (addr == 6) + || (addr >= 8 && addr < 0xd) + || (addr >= 0xe && addr < 0x20) + || (addr >= 0x22 && addr < 0x3c) + || (addr >= 0x3e && addr < 0x40) + || (addr >= 0x42 && addr < 0x44) + || (addr >= 0x46 && addr < 0xc0) + || (addr >= 0xc2)) + return; + + switch (addr) + { + case 4: + vt82c586b.usb_regs[4] = val & 0x97; + usb_update_io_mapping(); + break; + case 7: + vt82c586b.usb_regs[7] = val & 0x7f; + break; + + case 0x20: + vt82c586b.usb_regs[0x20] = (val & ~0x1f) | 1; + usb_update_io_mapping(); + break; + case 0x21: + vt82c586b.usb_regs[0x21] = val; + usb_update_io_mapping(); + break; + + default: + vt82c586b.usb_regs[addr] = val; + break; + } +// pclog(" USB write %02x %02x\n", addr, val); +} + +static uint8_t power_reg_read(uint16_t addr, void *p) +{ + uint32_t timer; + uint8_t ret = 0xff; + + switch (addr & 0xff) + { + case 0x00: case 0x01: + ret = vt82c586b.power.pm_status >> ((addr & 1) * 8); + break; + case 0x02: case 0x03: + ret = vt82c586b.power.pm_enable >> ((addr & 1) * 8); + break; + case 0x04: case 0x05: + ret = vt82c586b.power.pm_ctrl >> ((addr & 1) * 8); + break; + + case 0x08: case 0x09: case 0x0a: case 0x0b: /*ACPI timer*/ + timer = (tsc * ACPI_TIMER_FREQ) / cpu_get_speed(); + if (!(vt82c586b.power_regs[0x41] & ACPI_TIMER_32BIT)) + timer &= 0x00ffffff; + return (timer >> (8 * (addr & 3))) & 0xff; + + case 0x28: case 0x29: + ret = vt82c586b.power.gbl_status >> ((addr & 1) * 8); + break; + case 0x2a: case 0x2b: + ret = vt82c586b.power.gbl_enable >> ((addr & 1) * 8); + break; + case 0x2c: case 0x2d: + ret = vt82c586b.power.gbl_ctrl >> ((addr & 1) * 8); + break; + + case 0x2f: + ret = vt82c586b.power.smi_cmd; + break; + } +// pclog("power_reg_read: addr=%04x ret=%02x\n", addr, ret); + return ret; +} +static void power_reg_write(uint16_t addr, uint8_t val, void *p) +{ +// pclog("power_reg_write: addr=%04x val=%02x\n", addr, val); + switch (addr & 0xff) + { + case 0x00: + vt82c586b.power.pm_status &= ~(val & 0x31); + break; + case 0x01: + vt82c586b.power.pm_status &= ~((val & 0x8d) << 8); + break; + + case 0x02: + vt82c586b.power.pm_enable = (vt82c586b.power.pm_enable & ~0xff) | (val & 0x21); + break; + case 0x03: + vt82c586b.power.pm_enable = (vt82c586b.power.pm_enable & ~0xff00) | ((val & 0x05) << 8); + break; + + case 0x04: + vt82c586b.power.pm_ctrl = (vt82c586b.power.pm_ctrl & ~0xff) | (val & 0x07); + if (val & (1 << 2)) + pclog("VT82C586B set GBL_RLS\n"); + break; + case 0x05: + vt82c586b.power.pm_ctrl = (vt82c586b.power.pm_ctrl & ~0xff00) | ((val & 0x1c) << 8); + /*Note: PM_CTRL_SLP_EN is write-only, hence not stored in pm_ctrl*/ + if (val & (PM_CTRL_SLP_EN >> 8)) + { + pclog("VT82C586B transition to power state %i\n", (val >> 2) & 7); + if (!(vt82c586b.power.pm_ctrl & PM_CTRL_SLP_TYP_MASK)) + { + pclog("Power off\n"); + stop_emulation_now(); + } + } + break; + + case 0x28: + vt82c586b.power.gbl_status &= ~(val & 0x7f); + break; + + case 0x2a: + vt82c586b.power.gbl_enable = (vt82c586b.power.gbl_enable & ~0xff) | (val & 0x7f); + break; + + case 0x2c: + vt82c586b.power.gbl_ctrl = (vt82c586b.power.gbl_ctrl & ~0xff) | (val & 0x17); + if (val & (1 << 1)) + pclog("VT82C586B set BIOS_RLS\n"); + break; + case 0x2d: + if (val & 1) + vt82c586b.power.gbl_ctrl &= ~0x100; + break; + + case 0x2f: + vt82c586b.power.smi_cmd = val; + vt82c586b.power_regs[0x47] = val; + if (vt82c586b.power.gbl_enable & GBL_SW_SMI_EN) + { + vt82c586b.power.gbl_status |= GBL_SW_SMI_STS; + x86_smi_trigger(); + } + pclog("SMI_CMD write %02x\n", val); + break; + } +} +static void vt82c586b_power_write(int addr, uint8_t val) +{ + /*Read-only addresses*/ + if ((addr < 0xd) || (addr >= 0xe && addr < 0x40) + || (addr == 0x43) + || (addr == 0x48) + || (addr >= 0x4a && addr < 0x50) + || (addr >= 0x54)) + return; + + switch (addr) + { + case 0x41: + io_removehandler(vt82c586b.power.io_base, 0x0100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, NULL); + vt82c586b.power_regs[addr] = val; + if (vt82c586b.power_regs[0x41] & ACPI_IO_ENABLE) + io_sethandler(vt82c586b.power.io_base, 0x0100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, NULL); + break; + + case 0x49: + io_removehandler(vt82c586b.power.io_base, 0x0100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, NULL); + vt82c586b.power_regs[addr] = val; + vt82c586b.power.io_base = val << 8; + if (vt82c586b.power_regs[0x41] & ACPI_IO_ENABLE) + io_sethandler(vt82c586b.power.io_base, 0x0100, power_reg_read, NULL, NULL, power_reg_write, NULL, NULL, NULL); + break; + + default: + vt82c586b.power_regs[addr] = val; + break; + } +} + +static void vt82c586b_write(int func, int addr, uint8_t val, void *priv) +{ + switch (func) + { + case 0: + vt82c586b_pci_isa_bridge_write(addr, val); + break; + + case 1: + vt82c586b_ide_write(addr, val); + break; + + case 2: + vt82c586b_usb_write(addr, val); + break; + + case 3: + vt82c586b_power_write(addr, val); + break; + } +} + +uint8_t vt82c586b_read_sysctrl(uint16_t port, void *p) +{ + return vt82c586b.sysctrl; +} + +void vt82c586b_write_sysctrl(uint16_t port, uint8_t val, void *p) +{ + if ((mem_a20_alt ^ val) & 2) + { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~vt82c586b.sysctrl & val) & 1) + { + softresetx86(); + cpu_set_edx(); + } + vt82c586b.sysctrl = val; +} + +void vt82c586b_init(int card, int pci_a, int pci_b, int pci_c, int pci_d) +{ + pci_add_specific(card, vt82c586b_read, vt82c586b_write, NULL); + io_sethandler(0x0092, 0x0001, vt82c586b_read_sysctrl, NULL, NULL, vt82c586b_write_sysctrl, NULL, NULL, NULL); + + memset(&vt82c586b, 0, sizeof(vt82c586b)); + vt82c586b.pci_isa_bridge_regs[0x00] = 0x06; vt82c586b.pci_isa_bridge_regs[0x01] = 0x11; /*VIA*/ + vt82c586b.pci_isa_bridge_regs[0x02] = 0x86; vt82c586b.pci_isa_bridge_regs[0x03] = 0x05; /*VT82C586B*/ + vt82c586b.pci_isa_bridge_regs[0x04] = 0x0f; vt82c586b.pci_isa_bridge_regs[0x05] = 0x00; + vt82c586b.pci_isa_bridge_regs[0x06] = 0x00; vt82c586b.pci_isa_bridge_regs[0x07] = 0x02; + vt82c586b.pci_isa_bridge_regs[0x0a] = 0x01; + vt82c586b.pci_isa_bridge_regs[0x0b] = 0x06; + vt82c586b.pci_isa_bridge_regs[0x0e] = 0x80; + + /*ISA bus control*/ + vt82c586b.pci_isa_bridge_regs[0x48] = 0x01; + vt82c586b.pci_isa_bridge_regs[0x4a] = 0x04; + vt82c586b.pci_isa_bridge_regs[0x4f] = 0x03; + + /*Plug and Play control*/ + vt82c586b.pci_isa_bridge_regs[0x50] = 0x24; + vt82c586b.pci_isa_bridge_regs[0x59] = 0x04; + + vt82c586b.ide_regs[0x00] = 0x06; vt82c586b.ide_regs[0x01] = 0x11; /*VIA*/ + vt82c586b.ide_regs[0x02] = 0x71; vt82c586b.ide_regs[0x03] = 0x05; + vt82c586b.ide_regs[0x04] = 0x80; vt82c586b.ide_regs[0x05] = 0x00; + vt82c586b.ide_regs[0x06] = 0x80; vt82c586b.ide_regs[0x07] = 0x02; + vt82c586b.ide_regs[0x09] = 0x85; + vt82c586b.ide_regs[0x0a] = 0x01; + vt82c586b.ide_regs[0x0b] = 0x01; + + vt82c586b.ide_regs[0x10] = 0xf1; vt82c586b.ide_regs[0x11] = 0x01; + vt82c586b.ide_regs[0x14] = 0xf5; vt82c586b.ide_regs[0x15] = 0x03; + vt82c586b.ide_regs[0x18] = 0x71; vt82c586b.ide_regs[0x19] = 0x01; + vt82c586b.ide_regs[0x1c] = 0x75; vt82c586b.ide_regs[0x1d] = 0x03; + vt82c586b.ide_regs[0x20] = 0x01; vt82c586b.ide_regs[0x21] = 0xcc; + vt82c586b.ide_regs[0x3c] = 0x0e; + + vt82c586b.ide_regs[0x40] = 0x08; + vt82c586b.ide_regs[0x41] = 0x02; + vt82c586b.ide_regs[0x42] = 0x09; + vt82c586b.ide_regs[0x43] = 0x3a; + vt82c586b.ide_regs[0x44] = 0x68; + vt82c586b.ide_regs[0x46] = 0xc0; + vt82c586b.ide_regs[0x48] = 0xa8; + vt82c586b.ide_regs[0x49] = 0xa8; + vt82c586b.ide_regs[0x4a] = 0xa8; + vt82c586b.ide_regs[0x4b] = 0xa8; + vt82c586b.ide_regs[0x4c] = 0xff; + vt82c586b.ide_regs[0x4e] = 0xff; + vt82c586b.ide_regs[0x4f] = 0xff; + vt82c586b.ide_regs[0x50] = 0x03; + vt82c586b.ide_regs[0x51] = 0x03; + vt82c586b.ide_regs[0x52] = 0x03; + vt82c586b.ide_regs[0x53] = 0x03; + vt82c586b.ide_regs[0x61] = 0x02; + vt82c586b.ide_regs[0x68] = 0x02; + + vt82c586b.usb_regs[0x00] = 0x06; vt82c586b.usb_regs[0x01] = 0x11; /*VIA*/ + vt82c586b.usb_regs[0x02] = 0x38; vt82c586b.usb_regs[0x03] = 0x30; + vt82c586b.usb_regs[0x04] = 0x00; vt82c586b.usb_regs[0x05] = 0x00; + vt82c586b.usb_regs[0x06] = 0x00; vt82c586b.usb_regs[0x07] = 0x02; + vt82c586b.usb_regs[0x0a] = 0x03; + vt82c586b.usb_regs[0x0b] = 0x0c; + vt82c586b.usb_regs[0x0d] = 0x16; + vt82c586b.usb_regs[0x20] = 0x01; + vt82c586b.usb_regs[0x21] = 0x03; + vt82c586b.usb_regs[0x3d] = 0x04; + + vt82c586b.usb_regs[0x60] = 0x10; + vt82c586b.usb_regs[0xc1] = 0x20; + + vt82c586b.power_regs[0x00] = 0x06; vt82c586b.power_regs[0x01] = 0x11; /*VIA*/ + vt82c586b.power_regs[0x02] = 0x40; vt82c586b.power_regs[0x03] = 0x30; + vt82c586b.power_regs[0x04] = 0x00; vt82c586b.power_regs[0x05] = 0x00; + vt82c586b.power_regs[0x06] = 0x80; vt82c586b.power_regs[0x07] = 0x02; + vt82c586b.power_regs[0x08] = 0x10; /*Production version (3041)*/ + vt82c586b.power_regs[0x48] = 0x01; + + if (pci_a) + pci_set_card_routing(pci_a, PCI_INTA); + if (pci_b) + pci_set_card_routing(pci_b, PCI_INTB); + if (pci_c) + pci_set_card_routing(pci_c, PCI_INTC); + if (pci_d) + pci_set_card_routing(pci_d, PCI_INTD); + + sff_bus_master_init(vt82c586b.busmaster); + + ide_pri_disable(); + ide_sec_disable(); +} diff --git a/src/vt82c586b.h b/src/vt82c586b.h new file mode 100644 index 0000000..0f6981f --- /dev/null +++ b/src/vt82c586b.h @@ -0,0 +1 @@ +void vt82c586b_init(int card, int pci_a, int pci_b, int pci_c, int pci_d); diff --git a/src/w83877tf.c b/src/w83877tf.c new file mode 100644 index 0000000..bc4dccc --- /dev/null +++ b/src/w83877tf.c @@ -0,0 +1,264 @@ +#include "ibm.h" + +#include "fdc.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" +#include "w83877tf.h" + +enum +{ + CHIP_W83877F, + CHIP_W83877TF +}; + +typedef struct w83877tf_t +{ + int enable_regs; + uint8_t key[2]; + uint8_t unlock_key; + int index; + uint8_t regs[256]; + int chip; +} w83877tf_t; + +static w83877tf_t w83877tf_global; + +static void w83877tf_write_25x(uint16_t port, uint8_t val, void *p); +static uint8_t w83877tf_read_25x(uint16_t port, void *p); +static void w83877tf_write_3fx(uint16_t port, uint8_t val, void *p); +static uint8_t w83877tf_read_3fx(uint16_t port, void *p); + +static void w83877tf_write_reg(w83877tf_t *w83877tf, int index, uint8_t val) +{ +// pclog("w83877tf_write: index=%02x val=%02x\n", index, val); + switch (index) + { + case 0x0c: + if (w83877tf->regs[0x16] & 1) + w83877tf->unlock_key = (val & (1 << 5)) ? 0x87 : 0x86; + else + w83877tf->unlock_key = (val & (1 << 5)) ? 0x89 : 0x88; + break; + + case 0x16: + if (val == 2) /*Written by VA-503+ BIOS. Apparently should not change IO mapping*/ + return; + + io_removehandler(0x0250, 0x0003, w83877tf_read_25x, NULL, NULL, w83877tf_write_25x, NULL, NULL, &w83877tf_global); + io_removehandler(0x03f0, 0x0002, w83877tf_read_3fx, NULL, NULL, w83877tf_write_3fx, NULL, NULL, &w83877tf_global); + if (val & 0x01) + { + io_sethandler(0x03f0, 0x0002, w83877tf_read_3fx, NULL, NULL, w83877tf_write_3fx, NULL, NULL, &w83877tf_global); + w83877tf->unlock_key = (w83877tf->regs[0xc] & (1 << 5)) ? 0x87 : 0x86; + } + else + { + io_sethandler(0x0250, 0x0003, w83877tf_read_25x, NULL, NULL, w83877tf_write_25x, NULL, NULL, &w83877tf_global); + w83877tf->unlock_key = (w83877tf->regs[0xc] & (1 << 5)) ? 0x89 : 0x88; + } + + if ((w83877tf->regs[0x16] & 4) && !(val & 4)) + { + w83877tf->regs[0x20] = 0; + w83877tf->regs[0x23] = 0; + w83877tf->regs[0x24] = 0; + w83877tf->regs[0x25] = 0; + w83877tf->regs[0x26] = 0; + w83877tf->regs[0x27] = 0; + w83877tf->regs[0x28] = 0; + w83877tf->regs[0x29] = 0; + } + break; + } + + w83877tf->regs[index] = val; + + + fdc_remove(); + if (w83877tf->regs[0x20] >= 0x40) + fdc_add(); + + lpt1_remove(); + lpt2_remove(); + if (w83877tf->regs[0x23] >= 0x40) + lpt1_init(w83877tf->regs[0x23] << 2); + + serial1_remove(); + if (w83877tf->regs[0x24] >= 0x40) + serial1_set((w83877tf->regs[0x24] & ~1) << 2, w83877tf->regs[0x28] >> 4); + + serial2_remove(); + if (w83877tf->regs[0x25] >= 0x40) + serial2_set((w83877tf->regs[0x25] & ~1) << 2, w83877tf->regs[0x28] & 0xf); + +// pclog("LPT at %04x\n", w83877tf->regs[0x23] << 2); +// pclog("Serial1 at %04x %i\n", (w83877tf->regs[0x24] & ~1) << 2, w83877tf->regs[0x28] >> 4); +// pclog("Serial2 at %04x %i\n", (w83877tf->regs[0x25] & ~1) << 2, w83877tf->regs[0x28] & 0xf); +} + +static uint8_t w83877tf_read_reg(w83877tf_t *w83877tf, int index) +{ + switch (w83877tf->index) + { + case 0x09: + switch (w83877tf->chip) + { + case CHIP_W83877F: + return 0x0a; /*W83877F ID*/ + case CHIP_W83877TF: + return 0x0c; /*W83877TF ID*/ + } + break; + } + return w83877tf->regs[index]; +} + +static void w83877tf_write_25x(uint16_t port, uint8_t val, void *p) +{ + w83877tf_t *w83877tf = (w83877tf_t *)p; + +// pclog("w83877tf_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0x250: /*Enable register*/ + w83877tf->enable_regs = (val == w83877tf->unlock_key) ? 1 : 0; + break; + case 0x251: /*Index*/ + if (w83877tf->enable_regs) + w83877tf->index = val; + break; + case 0x252: /*Data*/ + if (w83877tf->enable_regs) + w83877tf_write_reg(w83877tf, w83877tf->index, val); + break; + } +} + +static uint8_t w83877tf_read_25x(uint16_t port, void *p) +{ + w83877tf_t *w83877tf = (w83877tf_t *)p; + + switch (port) + { + case 0x251: /*Index*/ + if (w83877tf->enable_regs) + return w83877tf->index; + break; + + case 0x252: /*Data*/ + if (w83877tf->enable_regs) + return w83877tf_read_reg(w83877tf, w83877tf->index); + break; + } + + return 0xff; +} + +static void w83877tf_write_3fx(uint16_t port, uint8_t val, void *p) +{ + w83877tf_t *w83877tf = (w83877tf_t *)p; + +// pclog("w83877tf_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0x3f0: /*Enable/index register*/ + if (val == 0xaa) + { + fdc_3f1_enable(1); + w83877tf->enable_regs = 0; + } + else if (!w83877tf->enable_regs) + { + w83877tf->key[1] = w83877tf->key[0]; + w83877tf->key[0] = val; + w83877tf->enable_regs = (w83877tf->key[0] == w83877tf->unlock_key && w83877tf->key[1] == w83877tf->unlock_key); + /*The FDC conflicts with the 3fx config registers, so disable + it when enabling config registers*/ + if (w83877tf->enable_regs) + fdc_3f1_enable(0); + } + else + w83877tf->index = val; + break; + case 0x3f1: /*Data*/ + if (w83877tf->enable_regs) + w83877tf_write_reg(w83877tf, w83877tf->index, val); + break; + } +} + +static uint8_t w83877tf_read_3fx(uint16_t port, void *p) +{ + w83877tf_t *w83877tf = (w83877tf_t *)p; + uint8_t ret = 0xff; + + switch (port) + { + case 0x3f0: /*Index*/ + if (w83877tf->enable_regs) + ret = w83877tf->index; + break; + + case 0x3f1: /*Data*/ + if (w83877tf->enable_regs) + ret = w83877tf_read_reg(w83877tf, w83877tf->index); + break; + } + +// pclog("w83877tf_read: port=%04x val=%02x\n", port, ret); + + return ret; +} + +static void w83877_common_init(int chip, uint16_t base, uint8_t key) +{ + memset(&w83877tf_global, 0, sizeof(w83877tf_t)); + + if (base == 0x250) + io_sethandler(0x0250, 0x0003, w83877tf_read_25x, NULL, NULL, w83877tf_write_25x, NULL, NULL, &w83877tf_global); + else + io_sethandler(0x03f0, 0x0002, w83877tf_read_3fx, NULL, NULL, w83877tf_write_3fx, NULL, NULL, &w83877tf_global); + + /*Defaults*/ + w83877tf_global.regs[0x03] = 0x30; + w83877tf_global.regs[0x09] = 0x0c; + w83877tf_global.regs[0x0b] = 0x0c; + if (key == 0x88 || key == 0x86) + w83877tf_global.regs[0x0c] = 0x08; + else + w83877tf_global.regs[0x0c] = 0x28; + w83877tf_global.regs[0x0d] = 0xa3; + if (base == 0x250) + w83877tf_global.regs[0x16] = 0x04; + else + w83877tf_global.regs[0x16] = 0x05; + w83877tf_global.regs[0x20] = 0; + w83877tf_global.regs[0x23] = 0; + w83877tf_global.regs[0x24] = 0; + w83877tf_global.regs[0x25] = 0; + w83877tf_global.regs[0x26] = 0; + w83877tf_global.regs[0x27] = 0; + w83877tf_global.regs[0x28] = 0; + w83877tf_global.regs[0x29] = 0; + + fdc_remove(); + lpt1_remove(); + lpt2_remove(); + serial1_remove(); + serial2_remove(); + + w83877tf_global.chip = chip; + w83877tf_global.unlock_key = key; +} + +void w83877f_init(uint16_t base, uint8_t key) +{ + w83877_common_init(CHIP_W83877F, base, key); +} +void w83877tf_init(uint16_t base, uint8_t key) +{ + w83877_common_init(CHIP_W83877TF, base, key); +} diff --git a/src/w83877tf.h b/src/w83877tf.h new file mode 100644 index 0000000..6371497 --- /dev/null +++ b/src/w83877tf.h @@ -0,0 +1,2 @@ +void w83877f_init(uint16_t base, uint8_t key); +void w83877tf_init(uint16_t base, uint8_t key); diff --git a/src/w83977tf.c b/src/w83977tf.c new file mode 100644 index 0000000..520b4ed --- /dev/null +++ b/src/w83977tf.c @@ -0,0 +1,197 @@ +#include "ibm.h" + +#include "fdc.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" +#include "w83977tf.h" + +typedef struct winbond_t +{ + int cur_reg; + int cur_device; + int index; + + uint8_t unlock_key; + uint8_t key[2]; + int enable_regs; + + struct + { + int enable; + uint16_t addr; + int irq; + int dma; + } dev[11]; +} winbond_t; + +static winbond_t winbond_global; + +#define DEV_FDC 0x0 +#define DEV_LPT 0x1 +#define DEV_COM1 0x2 +#define DEV_COM2 0x3 +#define DEV_KBC 0x5 +#define DEV_GPIO 0x7 +#define DEV_GPIO_II 0x8 +#define DEV_GPIO_III 0x9 +#define DEV_ACPI 0xa + +#define REG_DEVICE 0x07 +#define REG_DEVICE_ID 0x20 +#define REG_DEVICE_REV 0x21 +#define REG_ENABLE 0x30 +#define REG_ADDRHI 0x60 +#define REG_ADDRLO 0x61 +#define REG_IRQ 0x70 +#define REG_DMA 0x74 + +void winbond_write_reg(winbond_t *winbond, int index, uint8_t val) +{ + if (index == REG_DEVICE) + winbond->cur_device = val & 0xf; + else + { +// pclog("Write winbond %02x [%02x] %02x\n", winbond->cur_reg, winbond->cur_device, val); + switch (index) + { + case REG_ENABLE: + if (winbond->cur_device <= DEV_ACPI) + winbond->dev[winbond->cur_device].enable = val; + break; + case REG_ADDRLO: + if (winbond->cur_device <= DEV_ACPI) + winbond->dev[winbond->cur_device].addr = (winbond->dev[winbond->cur_device].addr & 0xff00) | val; + break; + case REG_ADDRHI: + if (winbond->cur_device <= DEV_ACPI) + winbond->dev[winbond->cur_device].addr = (winbond->dev[winbond->cur_device].addr & 0x00ff) | (val << 8); + break; + case REG_IRQ: + if (winbond->cur_device <= DEV_ACPI) + winbond->dev[winbond->cur_device].irq = val; + break; + case REG_DMA: + if (winbond->cur_device <= DEV_ACPI) + winbond->dev[winbond->cur_device].dma = val; + break; + } + + switch (winbond->cur_device) + { + case DEV_FDC: + fdc_remove(); + if (winbond->dev[DEV_FDC].enable & 1) + fdc_add(); + break; + case DEV_COM1: + serial1_remove(); + if (winbond->dev[DEV_COM1].enable & 1) + serial1_set(winbond->dev[DEV_COM1].addr, winbond->dev[DEV_COM1].irq); + break; + case DEV_COM2: + serial2_remove(); + if (winbond->dev[DEV_COM2].enable & 1) + serial2_set(winbond->dev[DEV_COM2].addr, winbond->dev[DEV_COM2].irq); + break; + case DEV_LPT: + lpt1_remove(); + lpt2_remove(); + if (winbond->dev[DEV_LPT].enable & 1) + lpt1_init(winbond->dev[DEV_LPT].addr); + break; + } + } +} + +uint8_t winbond_read_reg(winbond_t *winbond, int index) +{ +// pclog("Read winbond %02x\n", winbond->cur_reg); + + switch (index) + { + case REG_DEVICE: + return winbond->cur_device; + case REG_DEVICE_ID: + return 0x97; + case REG_DEVICE_REV: + return 0x73; + case REG_ENABLE: + return winbond->dev[winbond->cur_device].enable; + case REG_ADDRLO: + return winbond->dev[winbond->cur_device].addr & 0xff; + case REG_ADDRHI: + return winbond->dev[winbond->cur_device].addr >> 8; + case REG_IRQ: + return winbond->dev[winbond->cur_device].irq; + case REG_DMA: + return winbond->dev[winbond->cur_device].dma; + } + + return 0xff; +} + +static void winbond_write_3fx(uint16_t port, uint8_t val, void *p) +{ + winbond_t *winbond = (winbond_t *)p; + +// pclog("winbond_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0x3f0: /*Enable/index register*/ + if (val == 0xaa) + { + fdc_3f1_enable(1); + winbond->enable_regs = 0; + } + else if (!winbond->enable_regs) + { + winbond->key[1] = winbond->key[0]; + winbond->key[0] = val; + winbond->enable_regs = (winbond->key[0] == winbond->unlock_key && winbond->key[1] == winbond->unlock_key); + /*The FDC conflicts with the 3fx config registers, so disable + it when enabling config registers*/ + if (winbond->enable_regs) + fdc_3f1_enable(0); + } + else + winbond->index = val; + break; + case 0x3f1: /*Data*/ + if (winbond->enable_regs) + winbond_write_reg(winbond, winbond->index, val); + break; + } +} + +static uint8_t winbond_read_3fx(uint16_t port, void *p) +{ + winbond_t *winbond = (winbond_t *)p; + uint8_t ret = 0xff; + + switch (port) + { + case 0x3f0: /*Index*/ + if (winbond->enable_regs) + ret = winbond->index; + break; + + case 0x3f1: /*Data*/ + if (winbond->enable_regs) + ret = winbond_read_reg(winbond, winbond->index); + break; + } + +// pclog("winbond_read: port=%04x val=%02x\n", port, ret); + + return ret; +} + +void w83977tf_init(uint16_t base, uint8_t key) +{ + memset(&winbond_global, 0, sizeof(winbond_t)); + + winbond_global.unlock_key = key; + io_sethandler(base, 0x0002, winbond_read_3fx, NULL, NULL, winbond_write_3fx, NULL, NULL, &winbond_global); +} diff --git a/src/w83977tf.h b/src/w83977tf.h new file mode 100644 index 0000000..290f571 --- /dev/null +++ b/src/w83977tf.h @@ -0,0 +1 @@ +void w83977tf_init(uint16_t base, uint8_t key); diff --git a/src/wd76c10.c b/src/wd76c10.c index e164ed6..5416c62 100644 --- a/src/wd76c10.c +++ b/src/wd76c10.c @@ -2,6 +2,7 @@ #include "fdc.h" #include "io.h" #include "mem.h" +#include "rom.h" #include "serial.h" #include "wd76c10.h" @@ -9,6 +10,7 @@ static uint16_t wd76c10_0092; static uint16_t wd76c10_2072; static uint16_t wd76c10_2872; static uint16_t wd76c10_5872; +static uint16_t wd76c10_6072; uint16_t wd76c10_read(uint16_t port, void *priv) { @@ -25,6 +27,9 @@ uint16_t wd76c10_read(uint16_t port, void *priv) case 0x5872: return wd76c10_5872; + + case 0x6072: + return wd76c10_6072; } return 0; } @@ -44,19 +49,29 @@ void wd76c10_write(uint16_t port, uint16_t val, void *priv) case 0x2072: wd76c10_2072 = val; - switch ((val >> 5) & 7) + serial1_remove(); + if (!(val & 0x10)) { - 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 >> 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; + default: serial1_remove(); break; + } } - switch ((val >> 1) & 7) + serial2_remove(); + if (!(val & 0x01)) { - 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; + 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; + default: serial2_remove(); break; + } } break; @@ -71,6 +86,10 @@ void wd76c10_write(uint16_t port, uint16_t val, void *priv) case 0x5872: wd76c10_5872 = val; break; + + case 0x6072: + wd76c10_6072 = val; + break; } } @@ -96,4 +115,5 @@ void wd76c10_init() 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); + io_sethandler(0x6072, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); } diff --git a/src/win-config.c b/src/win-config.c deleted file mode 100644 index 0a4032f..0000000 --- a/src/win-config.c +++ /dev/null @@ -1,821 +0,0 @@ -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include - -#include "ibm.h" -#include "cpu.h" -#include "device.h" -#include "fdd.h" -#include "gameport.h" -#include "hdd.h" -#include "mem.h" -#include "model.h" -#include "mouse.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_mouse_to_list[20], settings_list_to_mouse[20]; -static char *hdd_names[16]; - -int has_been_inited = 0; - -static int mouse_valid(int type, int model) -{ - if ((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_PS2 && !(models[model].flags & MODEL_PS2)) - return 0; - if ((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_AMSTRAD && !(models[model].flags & MODEL_AMSTRAD)) - return 0; - if ((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_OLIM24 && !(models[model].flags & MODEL_OLIM24)) - return 0; - return 1; -} - -static void recalc_vid_list(HWND hdlg, int model) -{ - HWND h = GetDlgItem(hdlg, IDC_COMBOVID); - int c = 0, d = 0; - int found_card = 0; - - SendMessage(h, CB_RESETCONTENT, 0, 0); - SendMessage(h, CB_SETCURSEL, 0, 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)] && - ((models[model].flags & MODEL_PCI) || !(video_card_getdevice(c)->flags & DEVICE_PCI))) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - if (video_new_to_old(c) == gfxcard) - { - SendMessage(h, CB_SETCURSEL, d, 0); - found_card = 1; - } - - d++; - } - - c++; - } - if (!found_card) - SendMessage(h, CB_SETCURSEL, 0, 0); - EnableWindow(h, models[model].fixed_gfxcard ? FALSE : TRUE); - - h = GetDlgItem(hdlg, IDC_CHECKVOODOO); - EnableWindow(h, (models[model].flags & MODEL_PCI) ? TRUE : FALSE); - h = GetDlgItem(hdlg, IDC_CONFIGUREVOODOO); - EnableWindow(h, (models[model].flags & MODEL_PCI) ? TRUE : FALSE); -} - -static void recalc_snd_list(HWND hdlg, int model) -{ - HWND h = GetDlgItem(hdlg, IDC_COMBOSND); - int c = 0, d = 0; - - SendMessage(h, CB_RESETCONTENT, 0, 0); - - while (1) - { - char *s = sound_card_getname(c); - - if (!s[0]) - break; - - settings_sound_to_list[c] = d; - - if (sound_card_available(c)) - { - device_t *sound_dev = sound_card_getdevice(c); - - if (!sound_dev || (sound_dev->flags & DEVICE_MCA) == (models[model].flags & MODEL_MCA)) - { - 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); -} - -static void recalc_hdd_list(HWND hdlg, int model, int use_selected_hdd) -{ - HWND h; - - h = GetDlgItem(hdlg, IDC_COMBOHDD); - - if (models[model].flags & MODEL_HAS_IDE) - { - SendMessage(h, CB_RESETCONTENT, 0, 0); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Internal IDE"); - EnableWindow(h, FALSE); - SendMessage(h, CB_SETCURSEL, 0, 0); - } - else - { - char *s; - int valid = 0; - char old_name[16]; - int c, d; - - if (use_selected_hdd) - { - c = SendMessage(h, CB_GETCURSEL, 0, 0); - - if (c != -1 && hdd_names[c]) - strncpy(old_name, hdd_names[c], sizeof(old_name)-1); - else - strcpy(old_name, "none"); - } - else - strncpy(old_name, hdd_controller_name, sizeof(old_name)-1); - - SendMessage(h, CB_RESETCONTENT, 0, 0); - c = d = 0; - while (1) - { - s = hdd_controller_get_name(c); - if (s[0] == 0) - break; - if ((((hdd_controller_get_flags(c) & DEVICE_AT) && !(models[model].flags & MODEL_AT)) || - (hdd_controller_get_flags(c) & DEVICE_MCA) != (models[model].flags & MODEL_MCA)) && c) - { - c++; - continue; - } - if (!hdd_controller_available(c)) - { - c++; - continue; - } - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - hdd_names[d] = hdd_controller_get_internal_name(c); - if (!strcmp(old_name, hdd_names[d])) - { - SendMessage(h, CB_SETCURSEL, d, 0); - valid = 1; - } - c++; - d++; - } - - if (!valid) - SendMessage(h, CB_SETCURSEL, 0, 0); - - EnableWindow(h, TRUE); - } -} - -static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - char temp_str[256]; - HWND h; - int c, d; - int 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_joystick_type; - int cpu_type; - int temp_mouse_type; - int hdd_changed = 0; - - 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); - - recalc_vid_list(hdlg, romstomodel[romset]); - - 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); - - recalc_snd_list(hdlg, romstomodel[romset]); - - 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_CHECKSYNC); - SendMessage(h, BM_SETCHECK, enable_sync, 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_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].flags & MODEL_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_CONFIGUREMOD); - if (model_getdevice(model)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - 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_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].flags & MODEL_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); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"System default"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"0 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"1 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"2 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"4 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"6 W/S"); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"7 W/S"); - SendMessage(h, CB_SETCURSEL, cpu_waitstates, 0); - cpu_type = models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].cpu_type; - if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_COMBOMOUSE); - c = d = 0; - while (1) - { - char *s = mouse_get_name(c); - int type; - - if (!s) - break; - - type = mouse_get_type(c); - settings_mouse_to_list[c] = d; - - if (mouse_valid(type, model)) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - - settings_list_to_mouse[d] = c; - d++; - } - c++; - } - SendMessage(h, CB_SETCURSEL, settings_mouse_to_list[mouse_type], 0); - - recalc_hdd_list(hdlg, romstomodel[romset], 0); - - 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].flags & MODEL_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_CHECKSYNC); - enable_sync = 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_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); - h = GetDlgItem(hdlg, IDC_COMBOMOUSE); - temp_mouse_type = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - h = GetDlgItem(hdlg, IDC_COMBOHDD); - c = SendMessage(h, CB_GETCURSEL, 0, 0); - if (hdd_names[c]) - hdd_changed = strncmp(hdd_names[c], hdd_controller_name, sizeof(hdd_controller_name)-1); - - if (temp_model != model || gfx != gfxcard || mem != mem_size || - 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_fda_type != fdd_get_type(0) || temp_fdb_type != fdd_get_type(1) || - temp_mouse_type != mouse_type || hdd_changed) - { - if (!has_been_inited || 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; - mouse_type = temp_mouse_type; - - fdd_set_type(0, temp_fda_type); - fdd_set_type(1, temp_fdb_type); - - if (hdd_names[c]) - strncpy(hdd_controller_name, hdd_names[c], sizeof(hdd_controller_name)-1); - else - strcpy(hdd_controller_name, "none"); - - if (has_been_inited) - { - 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); - - cpu_manufacturer = temp_cpu_m; - cpu = temp_cpu; - cpu_set(); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - cpu_waitstates = SendMessage(h, CB_GETCURSEL, 0, 0); - cpu_update_waitstates(); - - if (has_been_inited) - saveconfig(NULL); - - 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)]; - - /*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].flags & MODEL_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); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - cpu_type = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_CONFIGUREMOD); - if (model_getdevice(temp_model)) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - h = GetDlgItem(hdlg, IDC_COMBOMOUSE); - temp_mouse_type = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; - SendMessage(h, CB_RESETCONTENT, 0, 0); - c = d = 0; - while (1) - { - char *s = mouse_get_name(c); - int type; - - if (!s) - break; - - type = mouse_get_type(c); - settings_mouse_to_list[c] = d; - - if (mouse_valid(type, temp_model)) - { - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - - settings_list_to_mouse[d] = c; - d++; - } - - c++; - } - if (mouse_valid(temp_mouse_type, temp_model)) - SendMessage(h, CB_SETCURSEL, settings_mouse_to_list[temp_mouse_type], 0); - else - SendMessage(h, CB_SETCURSEL, 0, 0); - - recalc_vid_list(hdlg, temp_model); - - recalc_hdd_list(hdlg, temp_model, 1); - - recalc_snd_list(hdlg, temp_model); - } - 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); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - cpu_type = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - - } - 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); - - h = GetDlgItem(hdlg, IDC_COMBOWS); - cpu_type = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; - if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) - EnableWindow(h, TRUE); - else - EnableWindow(h, FALSE); - } - break; - - case IDC_CONFIGUREMOD: - h = GetDlgItem(hdlg, IDC_COMBO1); - temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; - - deviceconfig_open(hdlg, (void *)model_getdevice(temp_model)); - 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_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, (DLGPROC)config_dlgproc); -} diff --git a/src/win-config_sel.c b/src/win-config_sel.c deleted file mode 100644 index 9e3ef03..0000000 --- a/src/win-config_sel.c +++ /dev/null @@ -1,185 +0,0 @@ -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include - -#include "ibm.h" -#include "config.h" -#include "resources.h" -#include "win.h" - -static void config_list_update(HWND hdlg) -{ - char s[512]; - int num, c; - HWND h; - - strcpy(s, pcempath); - put_backslash(s); - strcat(s, "configs\\*.cfg"); - pclog("Dir %s\n", s); - - DlgDirList(hdlg, s, IDC_LIST, 0, 0); - - h = GetDlgItem(hdlg, IDC_LIST); - num = SendMessage(h, LB_GETCOUNT, 0, 0); - - for (c = 0; c < num; c++) - { - char *ext; - - SendMessage(h, LB_GETTEXT, c, (LPARAM)s); - ext = get_extension(s); - if (ext && ext[0]) - { - ext--; - *ext = 0; - } - - SendMessage(h, LB_DELETESTRING, c, 0); - SendMessage(h, LB_INSERTSTRING, c, (LPARAM)s); - } -} - -static BOOL CALLBACK config_selection_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) -{ - //HWND h; - - switch (message) - { - case WM_INITDIALOG: -// pause = 1; - config_list_update(hdlg); -// h = GetDlgItem(hdlg, IDC_LIST); -// SendMessage(h, LB_ADDSTRING, 0, (LPARAM)(LPCSTR)"AAA"); -// SendMessage(h, LB_ADDSTRING, 0, (LPARAM)(LPCSTR)"BBB"); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) - { - case IDOK: - { - char s[512]; - - int ret = DlgDirSelectEx(hdlg, s, 512, IDC_LIST); - - pclog("DlgDirSelectEx returned %i %s\n", ret, s); - if (s[0]) - { - char cfg[512]; - - strcpy(cfg, pcempath); - put_backslash(cfg); - strcat(cfg, "configs\\"); - strcat(cfg, s); - strcat(cfg, "cfg"); -// sprintf(cfg, "%s\\configs\\%scfg", pcempath, s); - pclog("Config name %s\n", cfg); - - strcpy(config_file_default, cfg); - - EndDialog(hdlg, 1); -// pause = 0; - return TRUE; - } - } - return FALSE; - - case IDCANCEL: - EndDialog(hdlg, 0); -// pause = 0; - return TRUE; - - case IDC_NEW: - { - char s[512]; - - strcpy(s, pcempath); - put_backslash(s); - strcat(s, "configs\\"); - pclog("Dir %s\n", s); - - if (!getsfile(hdlg, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", "", s)) - { - config_open(hdlg); - - saveconfig(openfilestring); - } - - config_list_update(hdlg); - - return TRUE; - } - - case IDC_CONFIG: - { - char s[512]; - - int ret = DlgDirSelectEx(hdlg, s, 512, IDC_LIST); - - pclog("DlgDirSelectEx returned %i %s\n", ret, s); - if (s[0]) - { - char cfg[512]; - - strcpy(cfg, pcempath); - put_backslash(cfg); - strcat(cfg, "configs\\"); - strcat(cfg, s); - strcat(cfg, "cfg"); - pclog("Config name %s\n", cfg); - - loadconfig(cfg); - config_open(hdlg); - saveconfig(cfg); - } - - return TRUE; - } - - case IDC_HDCONF: - { - char s[512]; - - int ret = DlgDirSelectEx(hdlg, s, 512, IDC_LIST); - - pclog("DlgDirSelectEx returned %i %s\n", ret, s); - if (s[0]) - { - char cfg[512]; - - strcpy(cfg, pcempath); - put_backslash(cfg); - strcat(cfg, "configs\\"); - strcat(cfg, s); - strcat(cfg, "cfg"); - pclog("Config name %s\n", cfg); - - loadconfig(cfg); - hdconf_open(hdlg); - saveconfig(cfg); - } - - return TRUE; - } - } - break; - } - return FALSE; -} - -int config_selection_open(HWND hwnd, int inited) -{ - int ret; - - has_been_inited = inited; - - ret = DialogBox(hinstance, TEXT("ConfigureSelectionDlg"), hwnd, (DLGPROC)config_selection_dlgproc); - - has_been_inited = 1; - - return ret; -} diff --git a/src/win-d3d-fs.cc b/src/win-d3d-fs.cc deleted file mode 100644 index 340cb9c..0000000 --- a/src/win-d3d-fs.cc +++ /dev/null @@ -1,522 +0,0 @@ -#include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#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); - -extern "C" void video_blit_complete(); - -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 - DWORD color; - 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, 0xffffff, 0.0f, 0.0f}, - {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, - { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, - - { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, - {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, - {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, - - { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, - {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, - { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, - - { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, - {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, - {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f} -}; - -void d3d_fs_init(HWND h) -{ - int c; - 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 v12", - 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; - - d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); - - d3d_fs_init_objects(); - - video_blit_memtoscreen_func = d3d_fs_blit_memtoscreen; - video_blit_memtoscreen_8_func = 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() -{ - D3DLOCKED_RECT dr; - int y; - RECT r; - - d3ddev->CreateVertexBuffer(12*sizeof(CUSTOMVERTEX), - 0, - D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, - D3DPOOL_MANAGED, - &v_buffer, - NULL); - - d3ddev->CreateTexture(2048, 2048, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); - - r.top = r.left = 0; - r.bottom = r.right = 2047; - - if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) - fatal("LockRect failed\n"); - - for (y = 0; y < 2048; y++) - { - uint32_t *p = (uint32_t *)((uintptr_t)dr.pBits + (y * dr.Pitch)); - memset(p, 0, 2048 * 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() -{ - d3d_fs_close_objects(); - 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; - int yy; - double l, t, r, b; - - if (y1 == y2) - { - video_blit_complete(); - return; /*Nothing to do*/ - } - - 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 = 2047; - - if (FAILED(d3dTexture->LockRect(0, &dr, &lock_rect, 0))) - fatal("LockRect failed\n"); - - for (yy = y1; yy < y2; yy++) - memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); - - video_blit_complete(); - d3dTexture->UnlockRect(0); - } - else - video_blit_complete(); - - 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 / 2048.0; - d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; - d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = - d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = - d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = - d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; - - 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; - d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = r - 40.5; - d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = t + 8.5; - d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = r - 8.5; - d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = t + 14.5; - - 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) - 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_DIFFUSE | 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 && readflash && vid_disc_indicator) - hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 6, 2); - - 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; - int xx, yy; - double l, t, r, b; - - if (!h) - { - video_blit_complete(); - return; /*Nothing to do*/ - } - - if (hr == D3D_OK) - { - RECT lock_rect; - - lock_rect.top = 0; - lock_rect.left = 0; - lock_rect.bottom = 2047; - lock_rect.right = 2047; - - if (FAILED(d3dTexture->LockRect(0, &dr, &lock_rect, 0))) - fatal("LockRect failed\n"); - - for (yy = 0; yy < h; yy++) - { - uint32_t *p = (uint32_t *)((uintptr_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]]; - } - } - - video_blit_complete(); - - d3dTexture->UnlockRect(0); - } - else - video_blit_complete(); - - 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 / 2048.0; - d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; - d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = - d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = - d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = - d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; - - 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; - d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = r - 40.5; - d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = t + 8.5; - d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = r - 8.5; - d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = t + 14.5; - - 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) - 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_DIFFUSE | 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 && readflash && vid_disc_indicator) - hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 6, 2); - - 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); -} diff --git a/src/win-d3d-fs.h b/src/win-d3d-fs.h deleted file mode 100644 index 821537d..0000000 --- a/src/win-d3d-fs.h +++ /dev/null @@ -1,10 +0,0 @@ -#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 deleted file mode 100644 index 58ef2b6..0000000 --- a/src/win-d3d.cc +++ /dev/null @@ -1,425 +0,0 @@ -#include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#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(); -extern "C" void video_blit_complete(); - -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 - DWORD color; - 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, 0xffffff, 0.0f, 0.0f}, - {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, - { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, - - { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, - {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, - {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, - - { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, - {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, - { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, - - { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, - {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, - {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f} -}; - -void d3d_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); - - 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; - - d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); - - d3d_init_objects(); - - video_blit_memtoscreen_func = d3d_blit_memtoscreen; - video_blit_memtoscreen_8_func = 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() -{ - D3DLOCKED_RECT dr; - int y; - RECT r; - - d3ddev->CreateVertexBuffer(12*sizeof(CUSTOMVERTEX), - 0, - D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, - D3DPOOL_MANAGED, - &v_buffer, - NULL); - - d3ddev->CreateTexture(2048, 2048, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); - - r.top = r.left = 0; - r.bottom = r.right = 2047; - - if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) - fatal("LockRect failed\n"); - - for (y = 0; y < 2048; y++) - { - uint32_t *p = (uint32_t *)((uintptr_t)dr.pBits + (y * dr.Pitch)); - memset(p, 0, 2048 * 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) -{ - d3dpp.BackBufferWidth = x; - d3dpp.BackBufferHeight = y; - - d3d_reset(); -} - -void d3d_reset() -{ - HRESULT hr; - - if (!d3ddev) - return; - 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; - int yy; - - if (y1 == y2) - { - video_blit_complete(); - return; /*Nothing to do*/ - } - - r.top = y1; - r.left = 0; - r.bottom = y2; - r.right = 2047; - - if (hr == D3D_OK) - { - if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) - fatal("LockRect failed\n"); - - for (yy = y1; yy < y2; yy++) - memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); - - video_blit_complete(); - d3dTexture->UnlockRect(0); - } - else - video_blit_complete(); - - 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 / 2048.0; - d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; - d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = - d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = - d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = - d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; - - 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; - d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = (r.right - r.left) - 40.5; - d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = 8.5; - d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = (r.right - r.left) - 8.5; - d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = 14.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 - - 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_DIFFUSE | 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 && readflash && vid_disc_indicator) - hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 6, 2); - - 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; - int yy, xx; - HRESULT hr = D3D_OK; - - if (h == 0) - { - video_blit_complete(); - return; /*Nothing to do*/ - } - - r.top = 0; - r.left = 0; - r.bottom = h; - r.right = 2047; - - 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 *)((uintptr_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]]; - } - } - video_blit_complete(); - - d3dTexture->UnlockRect(0); - } - else - video_blit_complete(); - - 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 / 2048.0; - d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; - d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = - d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = - d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = - d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; - - 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; - d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = (r.right - r.left) - 40.5; - d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = 8.5; - d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = (r.right - r.left) - 8.5; - d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = 14.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 - - 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_DIFFUSE | 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 && readflash && vid_disc_indicator) - hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 6, 2); - - 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); -} diff --git a/src/win-d3d.h b/src/win-d3d.h deleted file mode 100644 index bd90795..0000000 --- a/src/win-d3d.h +++ /dev/null @@ -1,10 +0,0 @@ -#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 deleted file mode 100644 index 9f16819..0000000 --- a/src/win-ddraw-fs.cc +++ /dev/null @@ -1,336 +0,0 @@ -#include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#include "win-ddraw-fs.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(); - -extern "C" void video_blit_complete(); - -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 = 2048; - ddsd.dwHeight = 2048; - 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_func = ddraw_fs_blit_memtoscreen; - video_blit_memtoscreen_8_func = 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) - { - video_blit_complete(); - return; - } - for (yy = y1; yy < y2; yy++) - memcpy((void *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); - video_blit_complete(); - 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 && vid_disc_indicator) - { - 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) - { - video_blit_complete(); - return; - } - for (yy = 0; yy < h; yy++) - { - if ((y + yy) >= 0 && (y + yy) < buffer->h) - { - uint32_t *p = (uint32_t *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)); - for (xx = 0; xx < w; xx++) - p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; - } - } - video_blit_complete(); - 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 && vid_disc_indicator) - { - 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); -} diff --git a/src/win-ddraw-fs.h b/src/win-ddraw-fs.h deleted file mode 100644 index 122b98d..0000000 --- a/src/win-ddraw-fs.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - void ddraw_fs_init(HWND h); - void ddraw_fs_close(); -#ifdef __cplusplus -} -#endif diff --git a/src/win-ddraw.cc b/src/win-ddraw.cc deleted file mode 100644 index a46dbf9..0000000 --- a/src/win-ddraw.cc +++ /dev/null @@ -1,309 +0,0 @@ -#include -#define BITMAP WINDOWS_BITMAP -#include -#undef BITMAP -#include "win-ddraw.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(); - -extern "C" void video_blit_complete(); - -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 = 2048; - ddsd.dwHeight = 2048; - 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 = 2048; - ddsd.dwHeight = 2048; - 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_func = ddraw_blit_memtoscreen; - video_blit_memtoscreen_8_func = 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) - { - video_blit_complete(); - return; - } - for (yy = y1; yy < y2; yy++) - { - if ((y + yy) >= 0 && (y + yy) < buffer->h) - memcpy((void *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); - } - video_blit_complete(); - 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 && vid_disc_indicator) - { - readflash = 0; - 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 *)((uintptr_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) - { - video_blit_complete(); - return; - } - for (yy = 0; yy < h; yy++) - { - if ((y + yy) >= 0 && (y + yy) < buffer->h) - { - p = (uint32_t *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)); - for (xx = 0; xx < w; xx++) - p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; - } - } - p = (uint32_t *)((uintptr_t)ddsd.lpSurface + (4 * ddsd.lPitch)); - lpdds_back->Unlock(NULL); - video_blit_complete(); - - 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 && vid_disc_indicator) - { - readflash = 0; - 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 *)((uintptr_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); - } -} diff --git a/src/win-ddraw.h b/src/win-ddraw.h deleted file mode 100644 index 7561cca..0000000 --- a/src/win-ddraw.h +++ /dev/null @@ -1,9 +0,0 @@ -#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 deleted file mode 100644 index 4160523..0000000 --- a/src/win-deviceconfig.c +++ /dev/null @@ -1,352 +0,0 @@ -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include "ibm.h" -#include "config.h" -#include "device.h" -#include "plat-midi.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; - int num; - char s[80]; - - switch (config->type) - { - case CONFIG_BINARY: - val_int = config_get_int(CFG_MACHINE, 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(CFG_MACHINE, 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(CFG_MACHINE, 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; - - switch (config->type) - { - case CONFIG_BINARY: - val_int = config_get_int(CFG_MACHINE, 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(CFG_MACHINE, 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(CFG_MACHINE, 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 (has_been_inited && 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); - - switch (config->type) - { - case CONFIG_BINARY: - config_set_int(CFG_MACHINE, 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(CFG_MACHINE, config_device->name, config->name, selection->value); - - id += 2; - break; - - case CONFIG_MIDI: - c = SendMessage(h, CB_GETCURSEL, 0, 0); - config_set_int(CFG_MACHINE, NULL, config->name, c); - - id += 2; - break; - } - config++; - } - - saveconfig(NULL); - - if (has_been_inited) - 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 (((uintptr_t)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 (((uintptr_t)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 (((uintptr_t)data) & 2) - data++; - - y += 20; - break; - } - - if (((uintptr_t)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 (((uintptr_t)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, (DLGPROC)deviceconfig_dlgproc); - - free(data_block); -} diff --git a/src/win-hdconf.c b/src/win-hdconf.c deleted file mode 100644 index 184b370..0000000 --- a/src/win-hdconf.c +++ /dev/null @@ -1,930 +0,0 @@ -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include "ibm.h" -#include "hdd.h" -#include "ide.h" -#include "resources.h" -#include "win.h" - -static struct -{ - int cylinders; - int heads; -} hd_types[] = -{ - {306, 4}, {615, 4}, {615, 6}, {940, 8}, - {940, 6}, {615, 4}, {462, 8}, {733, 5}, - {900, 15}, {820, 3}, {855, 5}, {855, 7}, - {306, 8}, {733, 7}, {0, 0}, {612, 4}, - {977, 5}, {977, 7}, {1024, 7}, {733, 5}, - {733, 7}, {733, 5}, {306, 4}, {925, 7}, - {925, 9}, {754, 7}, {754, 11}, {699, 7}, - {823, 10}, {918, 7}, {1024, 11}, {1024, 15}, - {1024, 5}, {612, 2}, {1024, 9}, {1024, 8}, - {615, 8}, {987, 3}, {462, 7}, {820, 6}, - {977, 5}, {981, 5}, {830, 7}, {830, 10}, - {917, 15}, {1224, 15} -}; - -static int hd_changed = 0; - -static char hd_new_name[512]; -static int hd_new_spt, hd_new_hpc, hd_new_cyl; -static int hd_new_type; -static int new_cdrom_channel; - -static void check_hd_type(off64_t sz) -{ - int c; - - hd_new_type = 0; - - if (hdd_controller_current_is_mfm()) - { - for (c = 0; c < 46; c++) - { - if ((hd_types[c].cylinders * hd_types[c].heads * 17 * 512) == sz) - { - hd_new_spt = 17; - hd_new_hpc = hd_types[c].heads; - hd_new_cyl = hd_types[c].cylinders; - hd_new_type = c+1; - return; - } - } - hd_new_spt = 63; - hd_new_hpc = 16; - hd_new_cyl = ((sz / 512) / 16) / 63; - } - else - { - if ((sz % 17) == 0 && sz <= 133693440) - { - hd_new_spt = 17; - - if (sz <= 26738688) - hd_new_hpc = 4; - else if (sz <= 53477376) - hd_new_hpc = 6; - else if (sz <= 71303168) - hd_new_hpc = 8; - else - hd_new_hpc = 15; - - hd_new_cyl = (int)((sz / 512) / hd_new_hpc) / 17; - } - else - { - hd_new_spt = 63; - hd_new_hpc = 16; - hd_new_cyl = ((sz / 512) / 16) / 63; - } - } -} - -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); -} - -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]; - int hd_type; - - 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); - -// hd_type = 0; - h = GetDlgItem(hdlg, IDC_HDTYPE); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Custom type"); - for (c = 1; c <= 46; c++) - { - sprintf(s, "Type %02i : cylinders=%i, heads=%i, size=%iMB", c, hd_types[c-1].cylinders, hd_types[c-1].heads, (hd_types[c-1].cylinders * hd_types[c-1].heads * 17 * 512) / (1024 * 1024)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - } - SendMessage(h, CB_SETCURSEL, 0, 0); - - 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", "", NULL)) - { - 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); - pclog("EDIT1: %s\n", s); - sscanf(s, "%i", &hd[0].spt); - h = GetDlgItem(hdlg, IDC_EDIT2); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - pclog("EDIT2: %s\n", s); - sscanf(s, "%i", &hd[0].hpc); - h = GetDlgItem(hdlg, IDC_EDIT3); - SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); - pclog("EDIT3: %s\n", s); - sscanf(s, "%i", &hd[0].tracks); - - h = GetDlgItem(hdlg, IDC_TEXT1); - sprintf(s, "Size : %imb", (int)(((((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); - - hd_type = 0; - for (c = 1; c <= 46; c++) - { - pclog("Compare %i,%i %i,%i %i,%i\n", hd[0].spt,17, hd[0].hpc,hd_types[c-1].heads, hd[0].tracks,hd_types[c-1].cylinders); - if (hd[0].spt == 17 && hd[0].hpc == hd_types[c-1].heads && hd[0].tracks == hd_types[c-1].cylinders) - { - hd_type = c; - break; - } - } - h = GetDlgItem(hdlg, IDC_HDTYPE); - SendMessage(h, CB_SETCURSEL, hd_type, 0); - - return TRUE; - - case IDC_HDTYPE: - if (HIWORD(wParam) == CBN_SELCHANGE) - { - h = GetDlgItem(hdlg, IDC_HDTYPE); - hd_type = SendMessage(h, CB_GETCURSEL, 0, 0); - if (hd_type) - { - h = GetDlgItem(hdlg, IDC_EDIT3); - sprintf(s, "%i", hd_types[hd_type-1].cylinders); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT2); - sprintf(s, "%i", hd_types[hd_type-1].heads); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); - h = GetDlgItem(hdlg, IDC_EDIT1); - SendMessage(h, WM_SETTEXT, 0, (LPARAM)"17"); - - h = GetDlgItem(hdlg, IDC_TEXT1); - sprintf(s, "Size : %imb", (int)(((uint64_t)hd_types[hd_type-1].cylinders*hd_types[hd_type-1].heads*17*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]; - int c; - - switch (message) - { - case WM_INITDIALOG: - h = GetDlgItem(hdlg, IDC_HDTYPE); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Custom type"); - for (c = 1; c <= 46; c++) - { - sprintf(s, "Type %02i : cylinders=%i, heads=%i, size=%iMB", c, hd_types[c-1].cylinders, hd_types[c-1].heads, (hd_types[c-1].cylinders * hd_types[c-1].heads * 17 * 512) / (1024 * 1024)); - SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); - } - SendMessage(h, CB_SETCURSEL, hd_new_type, 0); - - 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", (int)((((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", (int)(((((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", (int)(((((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", (int)(((((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", (int)(((((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", (int)(((((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 (!has_been_inited || 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; - - if (has_been_inited) - { - saveconfig(NULL); - - 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, hdd_controller_current_is_mfm() ? TEXT("HdNewDlgMfm") : TEXT("HdNewDlg"), hdlg, (DLGPROC)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", (int)(((((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); - check_hd_type(sz); - - if (DialogBox(hinstance, hdd_controller_current_is_mfm() ? TEXT("HdSizeDlgMfm") : TEXT("HdSizeDlg"), hdlg, (DLGPROC)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", (int)(((((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, hdd_controller_current_is_mfm() ? TEXT("HdNewDlgMfm") : TEXT("HdNewDlg"), hdlg, (DLGPROC)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", (int)(((((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); - check_hd_type(sz); - - if (DialogBox(hinstance, hdd_controller_current_is_mfm() ? TEXT("HdSizeDlgMfm") : TEXT("HdSizeDlg"), hdlg, (DLGPROC)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", (int)(((((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, (DLGPROC)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", (int)(((((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); - check_hd_type(sz); - - if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, (DLGPROC)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", (int)(((((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, (DLGPROC)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", (int)(((((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); - check_hd_type(sz); - - if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, (DLGPROC)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", (int)(((((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; - } - break; - - } - return FALSE; -} - -void hdconf_open(HWND hwnd) -{ - if (hdd_controller_current_is_mfm()) - DialogBox(hinstance, TEXT("HdConfDlgMfm"), hwnd, (DLGPROC)hdconf_dlgproc); - else - DialogBox(hinstance, TEXT("HdConfDlg"), hwnd, (DLGPROC)hdconf_dlgproc); -} diff --git a/src/win-joystick.cc b/src/win-joystick.cc deleted file mode 100644 index 48ed2cc..0000000 --- a/src/win-joystick.cc +++ /dev/null @@ -1,275 +0,0 @@ -#define DIRECTINPUT_VERSION 0x0700 -#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 LPDIRECTINPUT lpdi; -static LPDIRECTINPUTDEVICE2 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(DirectInputCreate(hinstance, DIRECTINPUT_VERSION, &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++) - { - LPDIRECTINPUTDEVICE lpdi_joystick_temp = NULL; - DIPROPRANGE joy_axis_range; - DIDEVICEINSTANCE device_instance; - DIDEVCAPS devcaps; - - if (FAILED(lpdi->CreateDevice(joystick_guids[c], &lpdi_joystick_temp, NULL))) - fatal("joystick_init : CreateDevice failed\n"); - if (FAILED(lpdi_joystick_temp->QueryInterface(IID_IDirectInputDevice2, (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; - } -} - -static int joystick_get_axis(int joystick_nr, int mapping) -{ - if (mapping & POV_X) - { - int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; - - if (LOWORD(pov) == 0xFFFF) - return 0; - else - return sin((2*M_PI * (double)pov) / 36000.0) * 32767; - } - else if (mapping & POV_Y) - { - int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; - - if (LOWORD(pov) == 0xFFFF) - return 0; - else - return -cos((2*M_PI * (double)pov) / 36000.0) * 32767; - } - else - return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; -} - -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++) - joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); - 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]]; - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) - { - int x, y; - double angle, magnitude; - - x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); - y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); - - angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); - magnitude = sqrt((double)x*(double)x + (double)y*(double)y); - - if (magnitude < 16384) - joystick_state[c].pov[d] = -1; - else - joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360; - } - } - 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; - for (d = 0; d < joystick_get_pov_count(joystick_type); d++) - joystick_state[c].pov[d] = -1; - } - } -} - diff --git a/src/win-joystickconfig.c b/src/win-joystickconfig.c deleted file mode 100644 index 48ede2c..0000000 --- a/src/win-joystickconfig.c +++ /dev/null @@ -1,541 +0,0 @@ -#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; - } - - for (c = 0; c < joystick_get_pov_count(joystick_config_type)*2; 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_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); - } - 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); - } - SendMessage(h, CB_SETCURSEL, sel, 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 int get_pov(HWND hdlg, int id) -{ - HWND h = GetDlgItem(hdlg, id); - int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0); - int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_povs*2; - - if (axis_sel < nr_povs) - { - if (axis_sel & 1) - return POV_Y | (axis_sel >> 1); - else - return POV_X | (axis_sel >> 1); - } - - return axis_sel - nr_povs; -} - -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; - 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; - int nr_povs = plat_joystick_state[joystick-1].nr_povs; - 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; - } - for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++) - { - int mapping; - - h = GetDlgItem(hdlg, id); - mapping = joystick_state[joystick_nr].pov_mapping[c][0]; - if (mapping & POV_X) - SendMessage(h, CB_SETCURSEL, (mapping & 3)*2, 0); - else if (mapping & POV_Y) - SendMessage(h, CB_SETCURSEL, (mapping & 3)*2 + 1, 0); - else - SendMessage(h, CB_SETCURSEL, mapping + nr_povs*2, 0); - id += 2; - h = GetDlgItem(hdlg, id); - mapping = joystick_state[joystick_nr].pov_mapping[c][1]; - if (mapping & POV_X) - SendMessage(h, CB_SETCURSEL, (mapping & 3)*2, 0); - else if (mapping & POV_Y) - SendMessage(h, CB_SETCURSEL, (mapping & 3)*2 + 1, 0); - else - SendMessage(h, CB_SETCURSEL, mapping + nr_povs*2, 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 c; - 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; - } - for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) - { - h = GetDlgItem(hdlg, id); - joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(hdlg, id); - id += 2; - h = GetDlgItem(hdlg, id); - joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(hdlg, id); - 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 (((uintptr_t)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 (((uintptr_t)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 (((uintptr_t)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 (((uintptr_t)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 (((uintptr_t)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 (((uintptr_t)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 (((uintptr_t)data) & 2) - data++; - - y += 20; - } - - for (c = 0; c < joystick_get_pov_count(type)*2; c++) - { - char s[80]; - - /*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 - - if (c & 1) - sprintf(s, "%s (Y axis)", joystick_get_pov_name(type, c/2)); - else - sprintf(s, "%s (X axis)", joystick_get_pov_name(type, c/2)); - data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); - *data++ = 0; // no creation data - - if (((uintptr_t)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, s, -1, data, 256); - *data++ = 0; // no creation data - - if (((uintptr_t)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 (((uintptr_t)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, (DLGPROC)joystickconfig_dlgproc); - - free(data_block); -} diff --git a/src/win-keyboard.cc b/src/win-keyboard.cc deleted file mode 100644 index 360dad4..0000000 --- a/src/win-keyboard.cc +++ /dev/null @@ -1,47 +0,0 @@ -#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() -{ - 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(); -} diff --git a/src/win-mouse.cc b/src/win-mouse.cc deleted file mode 100644 index df37162..0000000 --- a/src/win-mouse.cc +++ /dev/null @@ -1,70 +0,0 @@ -#define DIRECTINPUT_VERSION 0x0700 -#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, int *z); - -static LPDIRECTINPUT lpdi; -static LPDIRECTINPUTDEVICE lpdi_mouse = NULL; -static DIMOUSESTATE mousestate; -static int mouse_x = 0, mouse_y = 0, mouse_z = 0; -int mouse_buttons = 0; - -void mouse_init() -{ - if (FAILED(DirectInputCreate(hinstance, DIRECTINPUT_VERSION, &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; - mouse_z += mousestate.lZ/120; - if (!mousecapture && !video_fullscreen) - mouse_x = mouse_y = mouse_z = mouse_buttons = 0; -} - -void mouse_get_mickeys(int *x, int *y, int *z) -{ - *x = mouse_x; - *y = mouse_y; - *z = mouse_z; - mouse_x = mouse_y = mouse_z = 0; -} diff --git a/src/win-status.c b/src/win-status.c deleted file mode 100644 index f60fa2c..0000000 --- a/src/win-status.c +++ /dev/null @@ -1,103 +0,0 @@ -#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 - 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, (DLGPROC)status_dlgproc); - ShowWindow(status_hwnd, SW_SHOW); -} diff --git a/src/win-video.c b/src/win-video.c deleted file mode 100644 index 2228481..0000000 --- a/src/win-video.c +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include -#include -#include "video.h" - -BITMAP *screen; - -void hline(BITMAP *b, int x1, int y, int x2, int 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 deleted file mode 100644 index e839c5c..0000000 --- a/src/win.c +++ /dev/null @@ -1,1456 +0,0 @@ -#define _WIN32_WINNT 0x0501 -#define BITMAP WINDOWS_BITMAP -#include -#include -#undef BITMAP - -#include -#include - -#include - -#include -#include -#include -#include -#include "ibm.h" -#include "cdrom-ioctl.h" -#include "cdrom-iso.h" -#include "config.h" -#include "cpu.h" -#include "device.h" -#include "disc.h" -#include "disc_img.h" -#include "ide.h" -#include "mem.h" -#include "model.h" -#include "mouse.h" -#include "nvr.h" -#include "resources.h" -#include "sound.h" -#include "thread.h" -#include "video.h" - -#include "plat-joystick.h" -#include "plat-midi.h" -#include "plat-mouse.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 gfx_present[GFX_MAX]; - -HANDLE ghMutex; - -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 warning(const char *format, ...) -{ - char buf[1024]; - va_list ap; - - va_start(ap, format); - vsprintf(buf, format, ap); - va_end(ap); - - MessageBox(ghwnd, buf, "PCem", MB_OK); -} - -void updatewindowsize(int x, int y) -{ - if (vid_resize) return; - - if (video_force_aspect_ration) - { - float aspect = (float)x / (float)y; - - if (aspect > 1.33) - y = (x * 3) / 4; - else - x = (y * 4) / 3; - } - - winsizex=x; winsizey=y; - win_doresize = 1; -} - -void releasemouse() -{ - if (mousecapture) - { - ClipCursor(&oldclip); - ShowCursor(TRUE); - mousecapture = 0; - } -} - -void startblit() -{ - WaitForSingleObject(ghMutex, INFINITE); -} - -void endblit() -{ - ReleaseMutex(ghMutex); -} - -void leave_fullscreen() -{ - leave_fullscreen_flag = 1; -} - -uint64_t main_time; - -void mainthread(LPVOID param) -{ - 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; - video_wait_for_blit(); - 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(const 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 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; - pclog("Preparing scan code map list...\n"); - /* 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, (LPBYTE)buf, &bufSize) == ERROR_SUCCESS) - { - UINT32 *bufEx2 = (UINT32 *) buf; - int scMapCount = bufEx2[2]; - pclog("%lu scan code mappings found!\n", scMapCount); - if ((bufSize != 0) && (scMapCount != 0)) - { - UINT16 *bufEx = (UINT16 *) (buf + 12); - pclog("More than zero scan code mappings found, processing...\n"); - 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); - - scancode_map[scancode_unmapped] = scancode_mapped; - pclog("Scan code mapping %u detected: %X -> %X\n", scancode_unmapped, scancode_mapped, scancode_map[scancode_unmapped]); - } - pclog("Done processing!\n"); - } - } - RegCloseKey(hKey); - } - pclog("Done preparing!\n"); -} - -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 (NULL, IDI_APPLICATION); - wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); - 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; - - getpath(); - - 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) - { - MessageBox(NULL, "No ROMs present!\nYou must have at least one romset to use PCem.","PCem fatal error",MB_OK); - return 0; - } - - romset = d; - - for (c = 0; c < GFX_MAX; c++) - gfx_present[c] = video_card_available(video_old_to_new(c)); - - timeBeginPeriod(1); - - atexit(releasemouse); - - QueryPerformanceFrequency(&qpc_freq); - timer_freq = qpc_freq.QuadPart; - - sound_init(); - - initpc(argc, argv); - - while (1) - { - quited = 0; - - if (!config_override) - { - if (!config_selection_open(NULL, 0)) - break; - } - - ghMutex = CreateMutex(NULL, FALSE, NULL); - 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 v12", /* 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); - - 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; - - loadconfig(NULL); - - 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); - - if (!cdrom_enabled) - CheckMenuItem(menu, IDM_CDROM_DISABLED, MF_CHECKED); - else - { - if (cdrom_drive == CDROM_ISO) - CheckMenuItem(menu, IDM_CDROM_ISO, MF_CHECKED); - else - CheckMenuItem(menu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); - } - if (vid_resize) - CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED); - if (video_force_aspect_ration) - CheckMenuItem(menu, IDM_VID_ASPECT, MF_CHECKED); - CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED); - CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); - CheckMenuItem(menu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(menu, IDM_BPB_DISABLE, bpb_disable ? MF_CHECKED : MF_UNCHECKED); - CheckMenuItem(menu, IDM_VID_DISC, vid_disc_indicator ? MF_CHECKED : MF_UNCHECKED); - - if (!loadbios()) - { - if (romset != -1) - MessageBox(hwnd,"Configured romset not available.\nDefaulting to available romset.","PCem error",MB_OK); - for (c = 0; c < ROM_MAX; c++) - { - if (romspresent[c]) - { - romset = c; - model = model_getmodel(romset); - break; - } - } - } - - if (!video_card_available(video_old_to_new(gfxcard))) - { - if (romset != -1) - MessageBox(hwnd,"Configured video BIOS not available.\nDefaulting to available romset.","PCem error",MB_OK); - for (c = GFX_MAX-1; c >= 0; c--) - { - if (gfx_present[c]) - { - gfxcard = c; - break; - } - } - } - - loadbios(); - resetpchard(); - - vid_apis[0][vid_api].init(ghwnd); - - mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL); - SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST); - - updatewindowsize(640, 480); - - keyboard_init(); - mouse_init(); - joystick_init(); - midi_init(); - - 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) - { - 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) - { - ClipCursor(&oldclip); - ShowCursor(TRUE); - mousecapture=0; - } - } - - quited=1; - } - - startblit(); -// pclog("Sleep 1000\n"); - Sleep(200); -// pclog("TerminateThread\n"); - TerminateThread(mainthreadh,0); - -// endblit(); - -// pclog("Quited? %i\n",quited); -// pclog("Closepc\n"); - savenvr(); - if (save_window_pos && window_remember) - saveconfig(NULL); -// pclog("dumpregs\n"); - - vid_apis[video_fullscreen][vid_api].close(); - - if (mousecapture) - { - ClipCursor(&oldclip); - ShowCursor(TRUE); - } - - keyboard_close(); - mouse_close(); - joystick_close(); - midi_close(); - - DestroyWindow(hwnd); - CloseHandle(ghMutex); - - if (config_override) - break; - } - - closepc(); - - timeEndPeriod(1); -// dumpregs(); - - 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, char *dir) -{ - 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 = dir; - 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 CDROM_ISO: - iso_close(); - break; - default: - ioctl_close(); - break; - } -} - -LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - HMENU hmenu; - RECT rect; - 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)) - { - case IDM_FILE_RESET: - pause=1; - Sleep(100); - savenvr(); - resetpc(); - pause=0; - break; - case IDM_FILE_HRESET: - pause=1; - Sleep(100); - savenvr(); - resetpchard(); - pause=0; - break; - case IDM_FILE_RESET_CAD: - pause=1; - Sleep(100); - savenvr(); - 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(NULL); - } - 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(NULL); - } - break; - case IDM_EJECT_A: - disc_close(0); - saveconfig(NULL); - break; - case IDM_EJECT_B: - disc_close(1); - saveconfig(NULL); - break; - case IDM_BPB_DISABLE: - bpb_disable = !bpb_disable; - CheckMenuItem(hmenu, IDM_BPB_DISABLE, bpb_disable ? MF_CHECKED : MF_UNCHECKED); - saveconfig(NULL); - 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(NULL); - break; - case IDM_VID_ASPECT: - video_force_aspect_ration = !video_force_aspect_ration; - CheckMenuItem(hmenu, IDM_VID_ASPECT, video_force_aspect_ration ? MF_CHECKED : MF_UNCHECKED); - saveconfig(NULL); - 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(NULL); - break; - - case IDM_VID_DDRAW: case IDM_VID_D3D: - startblit(); - video_wait_for_blit(); - 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(NULL); - 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(); - video_wait_for_blit(); - 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(NULL); - break; - - case IDM_VID_DISC: - vid_disc_indicator = !vid_disc_indicator; - CheckMenuItem(hmenu, IDM_VID_DISC, vid_disc_indicator ? MF_CHECKED : MF_UNCHECKED); - saveconfig(NULL); - 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(); - ioctl_set_drive(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(NULL); - 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(); - ioctl_set_drive(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(NULL); - if (!cdrom_enabled) - { - pause = 1; - Sleep(100); - cdrom_enabled = 1; - saveconfig(NULL); - 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 == CDROM_ISO) && 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 = CDROM_ISO; - CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_CHECKED); - saveconfig(NULL); - if (!cdrom_enabled) - { - pause = 1; - Sleep(100); - cdrom_enabled = 1; - saveconfig(NULL); - 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_set_drive(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(NULL); - if (!cdrom_enabled) - { - pause = 1; - Sleep(100); - cdrom_enabled = 1; - saveconfig(NULL); - 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); - - /* Here we read the raw input data for the keyboard */ - GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); - - /* 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)) - { - 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); - } - } - 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: - if (!(mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON)) - releasemouse(); - break; - - case WM_ENTERMENULOOP: -// if (key[KEY_ALT] || key[KEY_ALTGR]) return 0; - break; - - case WM_SIZING: - if (video_force_aspect_ration && vid_resize) - { - RECT *r = (RECT *)lParam; - int x = r->right - r->left; - int y = r->bottom - r->top; - float aspect = (float)x / (float)y; - - switch (wParam) - { - case WMSZ_LEFT: - case WMSZ_RIGHT: - r->bottom = r->top + ((x * 3) / 4); - break; - case WMSZ_TOP: - case WMSZ_BOTTOM: - r->right = r->left + ((y * 4) / 3); - break; - - case WMSZ_TOPLEFT: - if (aspect > 1.33) - r->top = r->bottom - ((x * 3) / 4); - else - r->left = r->right - ((y * 4) / 3); - break; - case WMSZ_TOPRIGHT: - if (aspect > 1.33) - r->top = r->bottom - ((x * 3) / 4); - else - r->right = r->left + ((y * 4) / 3); - break; - case WMSZ_BOTTOMLEFT: - if (aspect > 1.33) - r->bottom = r->top + ((x * 3) / 4); - else - r->left = r->right - ((y * 4) / 3); - break; - case WMSZ_BOTTOMRIGHT: - if (aspect > 1.33) - r->bottom = r->top + ((x * 3) / 4); - else - r->right = r->left + ((y * 4) / 3); - break; - } - - return TRUE; - } - break; - - case WM_SIZE: - winsizex=lParam&0xFFFF; - winsizey=lParam>>16; - - if (vid_apis[video_fullscreen][vid_api].resize) - { - startblit(); - video_wait_for_blit(); - 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 deleted file mode 100644 index ed12875..0000000 --- a/src/win.h +++ /dev/null @@ -1,41 +0,0 @@ -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); - -int config_selection_open(HWND hwnd, int inited); - -struct device_t; - -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, char *dir); - -extern int pause; - -extern int has_been_inited; diff --git a/src/wx-app.cc b/src/wx-app.cc new file mode 100644 index 0000000..cbe4f17 --- /dev/null +++ b/src/wx-app.cc @@ -0,0 +1,260 @@ +#include "wx-app.h" + +#include +#include +#include "wx-utils.h" +#include "wx-common.h" + +#ifdef _WIN32 +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#endif + +extern "C" +{ + int wx_load_config(void*); + int wx_start(void*); + int wx_stop(void*); + void wx_show(void*); + void wx_handle_command(void*, int, int); + + int start_emulation(void*); + int resume_emulation(); + int pause_emulation(); + int stop_emulation(); +} + +extern int config_override; + +extern void InitXmlResource(); + +wxDEFINE_EVENT(WX_CALLBACK_EVENT, CallbackEvent); +wxDEFINE_EVENT(WX_EXIT_EVENT, wxCommandEvent); +wxDEFINE_EVENT(WX_STOP_EMULATION_EVENT, wxCommandEvent); +wxDEFINE_EVENT(WX_STOP_EMULATION_NOW_EVENT, wxCommandEvent); +wxDEFINE_EVENT(WX_EXIT_COMPLETE_EVENT, wxCommandEvent); +wxDEFINE_EVENT(WX_SHOW_WINDOW_EVENT, wxCommandEvent); +wxDEFINE_EVENT(WX_POPUP_MENU_EVENT, PopupMenuEvent); +#ifdef _WIN32 +wxDEFINE_EVENT(WX_WIN_SEND_MESSAGE_EVENT, WinSendMessageEvent); +#endif + +wxBEGIN_EVENT_TABLE(Frame, wxFrame) +wxEND_EVENT_TABLE() + +wxIMPLEMENT_APP_NO_MAIN(App); + +App::App() +{ + this->frame = NULL; +} + +bool App::OnInit() +{ + wxImage::AddHandler( new wxPNGHandler ); + wxXmlResource::Get()->InitAllHandlers(); +// if (!wxXmlResource::Get()->Load("src/pc.xrc")) +// { +// std::cout << "Could not load resource file" << std::endl; +// return false; +// } + InitXmlResource(); + + frame = new Frame(this, "null frame", wxPoint(500, 500), + wxSize(100, 100)); + frame->Start(); + return true; +} + +int App::OnRun() +{ + return wxApp::OnRun(); +} + +#include + +Frame::Frame(App* app, const wxString& title, const wxPoint& pos, + const wxSize& size) : + wxFrame(NULL, wxID_ANY, title, pos, size, 0)//wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER)) +{ + this->closing = false; + this->menu = wxXmlResource::Get()->LoadMenu(wxT("main_menu")); + + Bind(wxEVT_CLOSE_WINDOW, &Frame::OnClose, this); + Bind(wxEVT_MENU, &Frame::OnCommand, this); + Bind(wxEVT_TOOL, &Frame::OnCommand, this); + Bind(WX_SHOW_WINDOW_EVENT, &Frame::OnShowWindowEvent, this); + Bind(WX_POPUP_MENU_EVENT, &Frame::OnPopupMenuEvent, this); + Bind(WX_EXIT_EVENT, &Frame::OnExitEvent, this); + Bind(WX_EXIT_COMPLETE_EVENT, &Frame::OnExitCompleteEvent, this); + Bind(WX_STOP_EMULATION_EVENT, &Frame::OnStopEmulationEvent, this); + Bind(WX_STOP_EMULATION_NOW_EVENT, &Frame::OnStopEmulationNowEvent, this); + Bind(WX_CALLBACK_EVENT, &Frame::OnCallbackEvent, this); +#ifdef _WIN32 + Bind(WX_WIN_SEND_MESSAGE_EVENT, &Frame::OnWinSendMessageEvent, this); +#endif + + CenterOnScreen(); +} + +void Frame::Start() +{ + if (wx_start(this)) + ShowConfigSelection(); + else + Quit(0); +} + +void Frame::ShowConfigSelection() +{ + if (wx_load_config(this)) + start_emulation(this); + else + Quit(1); +} + +void Frame::OnCallbackEvent(CallbackEvent& event) +{ + WX_CALLBACK callback = event.GetCallback(); + callback(event.GetData()); +} + +void Frame::OnStopEmulationEvent(wxCommandEvent& event) +{ + if (emulation_state != EMULATION_STOPPED) + { + pause_emulation(); + int ret = wxID_OK; + + if (confirm_on_stop_emulation) + { + wxDialog dlg; + wxXmlResource::Get()->LoadDialog(&dlg, this, "ConfirmRememberDlg"); + dlg.FindWindow("IDC_CONFIRM_LABEL")->SetLabel("Stop emulation?"); + dlg.FindWindow("IDC_CONFIRM_REMEMBER")->SetLabel("Do not ask again"); + dlg.Fit(); + ret = dlg.ShowModal(); + if (ret == wxID_OK) + confirm_on_stop_emulation = !((wxCheckBox*)dlg.FindWindow("IDC_CONFIRM_REMEMBER"))->IsChecked(); + } + + if (ret == wxID_OK) + { + stop_emulation(); + if (!config_override) + ShowConfigSelection(); + else + Quit(1); + } + else + resume_emulation(); + } +} + +void Frame::OnStopEmulationNowEvent(wxCommandEvent& event) +{ + stop_emulation(); + if (!config_override) + ShowConfigSelection(); + else + Quit(1); +} + +void Frame::OnShowWindowEvent(wxCommandEvent& event) +{ + wxWindow* window = (wxWindow*)event.GetEventObject(); + int shown = window->IsShown(); + int value = event.GetInt(); + if (value < 0) + window->Show(!shown); + else + window->Show(value > 0); + if (!shown) + window->Refresh(); +} + +void Frame::OnPopupMenuEvent(PopupMenuEvent& event) +{ + wxWindow* window = event.GetWindow(); + wxMenu* menu = event.GetMenu(); + int* x = event.GetX(); + int* y = event.GetY(); + + if (x && y) + window->PopupMenu(menu, *x, *y); + else + window->PopupMenu(menu); +} + +void Frame::OnCommand(wxCommandEvent& event) +{ + wx_handle_command(this, event.GetId(), event.IsChecked()); +} + +void Frame::OnClose(wxCloseEvent& event) +{ + wx_exit(this, 0); +} + +wxMenu* Frame::GetMenu() +{ + return menu; +} + +/* Exit */ + +void Frame::Quit(bool stop_emulator) +{ + if (closing) + return; + closing = true; + if (stop_emulator) + { + if (!wx_stop(this)) + { + // cancel quit + closing = false; + return; + } + } + Destroy(); +} + +void Frame::OnExitEvent(wxCommandEvent& event) +{ + if (closing) + return; + closing = true; + CExitThread* exitThread = new CExitThread(this); + exitThread->Run(); +} + +void Frame::OnExitCompleteEvent(wxCommandEvent& event) +{ + if (event.GetInt()) + Destroy(); + else + closing = false; +} + +CExitThread::CExitThread(Frame* frame) +{ + this->frame = frame; +} + +wxThread::ExitCode CExitThread::Entry() +{ + wxCommandEvent* event = new wxCommandEvent(WX_EXIT_COMPLETE_EVENT, wxID_ANY); + event->SetInt(wx_stop(frame)); + wxQueueEvent(frame, event); + return 0; +} + +#ifdef _WIN32 +void Frame::OnWinSendMessageEvent(WinSendMessageEvent& event) +{ + SendMessage((HWND)event.GetHWND(), event.GetMessage(), event.GetWParam(), event.GetLParam()); +} +#endif diff --git a/src/wx-app.h b/src/wx-app.h new file mode 100644 index 0000000..4c6d29a --- /dev/null +++ b/src/wx-app.h @@ -0,0 +1,178 @@ +#ifndef SRC_WX_APP_H_ +#define SRC_WX_APP_H_ + +#include +#ifndef WX_PRECOMP +#include +#endif + +#include "wx-utils.h" + +class CallbackEvent; +class PopupMenuEvent; + +wxDECLARE_EVENT(WX_CALLBACK_EVENT, CallbackEvent); +wxDECLARE_EVENT(WX_EXIT_EVENT, wxCommandEvent); +wxDECLARE_EVENT(WX_STOP_EMULATION_EVENT, wxCommandEvent); +wxDECLARE_EVENT(WX_STOP_EMULATION_NOW_EVENT, wxCommandEvent); +wxDECLARE_EVENT(WX_EXIT_COMPLETE_EVENT, wxCommandEvent); +wxDECLARE_EVENT(WX_SHOW_WINDOW_EVENT, wxCommandEvent); +wxDECLARE_EVENT(WX_POPUP_MENU_EVENT, PopupMenuEvent); + +#ifdef _WIN32 +class WinSendMessageEvent; +wxDECLARE_EVENT(WX_WIN_SEND_MESSAGE_EVENT, WinSendMessageEvent); +class WinSendMessageEvent: public wxCommandEvent +{ +public: + WinSendMessageEvent(void* hwnd, int message, INT_PARAM wParam, LONG_PARAM lParam) : wxCommandEvent(WX_WIN_SEND_MESSAGE_EVENT) + { + this->hwnd = hwnd; + this->message = message; + this->wParam = wParam; + this->lParam = lParam; + } + WinSendMessageEvent(const WinSendMessageEvent& event) : wxCommandEvent(event) + { + this->hwnd = event.GetHWND(); + this->message = event.GetMessage(); + this->wParam = event.GetWParam(); + this->lParam = event.GetLParam(); + } + + wxEvent* Clone() const { return new WinSendMessageEvent(*this); } + + void* GetHWND() const { return hwnd; } + int GetMessage() const { return message; } + INT_PARAM GetWParam() const { return wParam; } + LONG_PARAM GetLParam() const { return lParam; } + +private: + void* hwnd; + int message; + INT_PARAM wParam; + LONG_PARAM lParam; +}; +#endif + +class CallbackEvent: public wxCommandEvent +{ +public: + CallbackEvent(WX_CALLBACK callback, void* data) : wxCommandEvent(WX_CALLBACK_EVENT) + { + this->callback = callback; + this->data = data; + } + CallbackEvent(const CallbackEvent& event) : wxCommandEvent(event) + { + this->callback = event.GetCallback(); + this->data = event.GetData(); + } + + wxEvent* Clone() const { return new CallbackEvent(*this); } + + WX_CALLBACK GetCallback() const { return callback; } + void* GetData() const { return data; } + +private: + WX_CALLBACK callback; + void* data; + + +}; + +class PopupMenuEvent: public wxCommandEvent +{ +public: + PopupMenuEvent(wxWindow* window, wxMenu* menu, int* x, int* y) : wxCommandEvent(WX_POPUP_MENU_EVENT) + { + this->window = window; + this->menu = menu; + this->x = x; + this->y = y; + } + PopupMenuEvent(const PopupMenuEvent& event) : wxCommandEvent(event) + { + this->window = event.GetWindow(); + this->menu = event.GetMenu(); + this->x = event.GetX(); + this->y = event.GetY(); + } + + wxEvent* Clone() const { return new PopupMenuEvent(*this); } + + wxWindow* GetWindow() const { return window; } + wxMenu* GetMenu() const { return menu; } + int* GetX() const { return x; } + int* GetY() const { return y; } + +private: + int* x; + int* y; + wxMenu* menu; + wxWindow* window; +}; + +class Frame; + +class App: public wxApp +{ +public: + App(); + virtual bool OnInit(); + virtual int OnRun(); + Frame* GetFrame() + { + return frame; + } +private: + Frame* frame; +}; + +class CExitThread: public wxThread +{ +public: + CExitThread(Frame* frame); + virtual ~CExitThread() {} +private: + wxThread::ExitCode Entry(); + Frame* frame; +}; + +class Frame: public wxFrame +{ +public: + Frame(App* app, const wxString& title, const wxPoint& pos, + const wxSize& size); + + virtual ~Frame() {} + + void Start(); + + wxMenu* GetMenu(); + +private: + void OnCommand(wxCommandEvent& event); + void OnExitEvent(wxCommandEvent& event); + void OnExitCompleteEvent(wxCommandEvent& event); + void OnStopEmulationEvent(wxCommandEvent& event); + void OnStopEmulationNowEvent(wxCommandEvent& event); + void OnShowWindowEvent(wxCommandEvent& event); + void OnPopupMenuEvent(PopupMenuEvent& event); + void OnCallbackEvent(CallbackEvent& event); + void OnClose(wxCloseEvent& event); +#ifdef _WIN32 + void OnWinSendMessageEvent(WinSendMessageEvent& event); +#endif + + void ShowConfigSelection(); + wxMenu* menu; + + bool closing; + + void Quit(bool stop_emulator = 1); + + wxDECLARE_EVENT_TABLE(); +}; + +#endif /* SRC_WX_APP_H_ */ diff --git a/src/wx-common.c b/src/wx-common.c new file mode 100644 index 0000000..55ef6e6 --- /dev/null +++ b/src/wx-common.c @@ -0,0 +1,34 @@ +#include "wx-common.h" +#include "config.h" + +void wx_loadconfig() +{ + show_machine_info = config_get_int(CFG_GLOBAL, "wxWidgets", "show_machine_info", show_machine_info); + show_disc_activity = config_get_int(CFG_GLOBAL, "wxWidgets", "show_disc_activity", show_disc_activity); + show_speed_history = config_get_int(CFG_GLOBAL, "wxWidgets", "show_speed_history", show_speed_history); + show_mount_paths = config_get_int(CFG_GLOBAL, "wxWidgets", "show_mount_paths", show_mount_paths); + show_status = config_get_int(CFG_GLOBAL, "wxWidgets", "show_status", show_status); + show_machine_on_start = config_get_int(CFG_GLOBAL, "wxWidgets", "show_machine_on_start", show_machine_on_start); + + confirm_on_reset_machine = config_get_int(CFG_GLOBAL, "wxWidgets", "confirm_on_reset_machine", confirm_on_reset_machine); + confirm_on_stop_emulation = config_get_int(CFG_GLOBAL, "wxWidgets", "confirm_on_stop_emulation", confirm_on_stop_emulation); + + wx_window_x = config_get_int(CFG_GLOBAL, "wxWidgets", "window_x", wx_window_x); + wx_window_y = config_get_int(CFG_GLOBAL, "wxWidgets", "window_y", wx_window_y); +} + +void wx_saveconfig() +{ + config_set_int(CFG_GLOBAL, "wxWidgets", "show_machine_info", show_machine_info); + config_set_int(CFG_GLOBAL, "wxWidgets", "show_disc_activity", show_disc_activity); + config_set_int(CFG_GLOBAL, "wxWidgets", "show_speed_history", show_speed_history); + config_set_int(CFG_GLOBAL, "wxWidgets", "show_mount_paths", show_mount_paths); + config_set_int(CFG_GLOBAL, "wxWidgets", "show_status", show_status); + config_set_int(CFG_GLOBAL, "wxWidgets", "show_machine_on_start", show_machine_on_start); + + config_set_int(CFG_GLOBAL, "wxWidgets", "confirm_on_reset_machine", confirm_on_reset_machine); + config_set_int(CFG_GLOBAL, "wxWidgets", "confirm_on_stop_emulation", confirm_on_stop_emulation); + + config_set_int(CFG_GLOBAL, "wxWidgets", "window_x", wx_window_x); + config_set_int(CFG_GLOBAL, "wxWidgets", "window_y", wx_window_y); +} diff --git a/src/wx-common.h b/src/wx-common.h new file mode 100644 index 0000000..294a0ee --- /dev/null +++ b/src/wx-common.h @@ -0,0 +1,26 @@ +extern int show_machine_info; +extern int show_status; +extern int show_machine_on_start; +extern int confirm_on_stop_emulation; +extern int confirm_on_reset_machine; +extern int show_speed_history; +extern int show_disc_activity; +extern int show_mount_paths; +extern int wx_window_x; +extern int wx_window_y; + +typedef enum { EMULATION_STOPPED, EMULATION_PAUSED, EMULATION_RUNNING } emulation_state_t; +extern emulation_state_t emulation_state; + +#define IS_PAUSED (emulation_state == EMULATION_PAUSED) + +typedef enum { DRIVE_TYPE_HDD, DRIVE_TYPE_FDD, DRIVE_TYPE_CDROM } drive_type_t; + +typedef struct drive_info_t { + drive_type_t type; + char fn[256]; + int enabled; + int drive; + char drive_letter; + int readflash; +} drive_info_t; diff --git a/src/wx-config.c b/src/wx-config.c new file mode 100644 index 0000000..9bc5c8d --- /dev/null +++ b/src/wx-config.c @@ -0,0 +1,2498 @@ +#include "wx-utils.h" +#include "wx-sdl2.h" +#include "wx-joystickconfig.h" + +#include "ibm.h" +#include "ide.h" +#include "cpu.h" +#include "device.h" +#include "fdd.h" +#include "gameport.h" +#include "hdd.h" +#include "lpt.h" +#include "model.h" +#include "mouse.h" +#include "mem.h" +#include "nethandler.h" +#include "nvr.h" +#include "scsi_cd.h" +#include "sound.h" +#include "video.h" +#include "vid_voodoo.h" + +#include "minivhd/minivhd.h" + +//#define MAX_CYLINDERS ((((1 << 28)-1) / 16) / 63) +#define MAX_CYLINDERS 265264 /*Award 430VX won't POST with a larger drive*/ +extern int pause; + +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_mouse_to_list[20], settings_list_to_mouse[20]; +#ifdef USE_NETWORKING +static int settings_network_to_list[20], settings_list_to_network[20]; +#endif +static char *hdd_names[16]; + +int has_been_inited = 0; + +static int hd_changed = 0; + +static char hd_new_name[512]; +static int hd_new_spt, hd_new_hpc, hd_new_cyl; +static int hd_new_type; +static int new_cdrom_channel; +static int new_zip_channel; + +extern int pause; + +static int memspin_old; + +extern void deviceconfig_open(void* hwnd, device_t *device); +extern int hdconf_init(void* hdlg); +extern int hdconf_update(void* hdlg); + +static int hdd_controller_selected_is_ide(void* hdlg); +static int hdd_controller_selected_is_scsi(void* hdlg); +static int hdd_controller_selected_has_config(void *hdlg); +static device_t *hdd_controller_selected_get_device(void *hdlg); + +static int mouse_valid(int type, int model) +{ + if (((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_PS2) + && !(models[model].flags & MODEL_PS2)) + return 0; + if (((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_AMSTRAD) + && !(models[model].flags & MODEL_AMSTRAD)) + return 0; + if (((type & MOUSE_TYPE_IF_MASK) == MOUSE_TYPE_OLIM24) + && !(models[model].flags & MODEL_OLIM24)) + return 0; + return 1; +} + +/*static int mpu401_available(int sound_card) +{ + char* name = sound_card_get_internal_name(sound_card); + if (name && (!strcmp(name, "sb16") || !strcmp(name, "sbawe32"))) + return TRUE; + + return FALSE; +}*/ + +static void recalc_fpu_list(void *hdlg, int model, int manu, int cpu, int fpu) +{ + void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU")); + int c = 0; + + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + + while (1) + { + const char *name = fpu_get_name_from_index(model, manu, cpu, c); + int type = fpu_get_type_from_index(model, manu, cpu, c); + if (!name) + break; + + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)name); + if (!c || type == fpu) + wx_sendmessage(h, WX_CB_SETCURSEL, c, 0); + + c++; + } + if (c > 1) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); +} + +static void recalc_vid_list(void* hdlg, int model, int force_builtin_video) +{ + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID")); + int c = 0, d = 0; + int found_card = 0; + int cur_gfxcard = gfxcard; + int romset = model_getromset_from_model(model); + + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + + if (model_has_fixed_gfx(model)) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Built-in video"); + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + wx_enablewindow(h, FALSE); + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID")); + wx_enablewindow(h, video_card_has_config(gfxcard, romset)); + return; + } + + if (model_has_optional_gfx(model)) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Built-in video"); + if (gfxcard == GFX_BUILTIN || force_builtin_video) + { + wx_sendmessage(h, WX_CB_SETCURSEL, d, 0); + found_card = 1; + cur_gfxcard = GFX_BUILTIN; + } + d++; + } + + if (cur_gfxcard == GFX_BUILTIN && !model_has_fixed_gfx(model) && !model_has_optional_gfx(model)) + cur_gfxcard = 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)] && + ((models[model].flags & MODEL_PCI) || !(video_card_getdevice(c, romset)->flags & DEVICE_PCI)) && + ((models[model].flags & MODEL_MCA) || !(video_card_getdevice(c, romset)->flags & DEVICE_MCA)) && + (!(models[model].flags & MODEL_MCA) || (video_card_getdevice(c, romset)->flags & DEVICE_MCA)) + ) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + if (video_new_to_old(c) == gfxcard && !found_card) + { + wx_sendmessage(h, WX_CB_SETCURSEL, d, 0); + found_card = 1; + } + + d++; + } + + c++; + } + if (!found_card) + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + wx_enablewindow(h, TRUE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID")); + if (video_card_has_config(video_old_to_new(cur_gfxcard), romset)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKVOODOO")); + wx_enablewindow(h, (models[model].flags & MODEL_PCI) ? TRUE : FALSE); + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVOODOO")); + wx_enablewindow(h, (models[model].flags & MODEL_PCI) ? TRUE : FALSE); +} + +static void recalc_snd_list(void* hdlg, int model) +{ + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSND")); + int c = 0, d = 0; + + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + + while (1) + { + char *s = sound_card_getname(c); + + if (!s[0]) + break; + + settings_sound_to_list[c] = d; + + if (sound_card_available(c)) + { + device_t *sound_dev = sound_card_getdevice(c); + + if (!sound_dev || (sound_dev->flags & DEVICE_MCA) == (models[model].flags & MODEL_MCA)) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) s); + settings_list_to_sound[d] = c; + d++; + } + } + + c++; + } + wx_sendmessage(h, WX_CB_SETCURSEL, settings_sound_to_list[sound_card_current], 0); +} + +static void recalc_hdd_list(void* hdlg, int model, int use_selected_hdd, int force_ide) +{ + void* h; + char *s; + int valid = 0; + char old_name[16]; + int c, d; + int hdd_type; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD")); + + if (force_ide) + strcpy(old_name, "ide"); + else if (use_selected_hdd) + { + c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + if (c != -1 && hdd_names[c]) + strncpy(old_name, hdd_names[c], sizeof(old_name)-1); + else + { + if (models[model].flags & MODEL_HAS_IDE) + strcpy(old_name, "none"); + else + strcpy(old_name, "ide"); + } + } + else + strncpy(old_name, hdd_controller_name, sizeof(old_name)-1); + + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + c = d = 0; + while (1) + { + s = hdd_controller_get_name(c); + if (s[0] == 0) + break; + if ((((hdd_controller_get_flags(c) & DEVICE_AT) && !(models[model].flags & MODEL_AT)) || + (hdd_controller_get_flags(c) & DEVICE_MCA) != (models[model].flags & MODEL_MCA)) && c) + { + c++; + continue; + } + if ((((hdd_controller_get_flags(c) & DEVICE_PS1) && models[model].id != ROM_IBMPS1_2011) || + (!(hdd_controller_get_flags(c) & DEVICE_PS1) && models[model].id == ROM_IBMPS1_2011)) && c) + { + c++; + continue; + } + if (!hdd_controller_available(c)) + { + c++; + continue; + } + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + hdd_names[d] = hdd_controller_get_internal_name(c); + + if (!strcmp(old_name, hdd_names[d])) + { + wx_sendmessage(h, WX_CB_SETCURSEL, d, 0); + valid = 1; + } + c++; + d++; + } + + if (!valid) + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + + wx_enablewindow(h, TRUE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREHDD")); + if (hdd_controller_selected_has_config(hdlg)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD")); + hdd_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDCBOOK")); + + while (wx_sendmessage(h, WX_CHB_GETPAGECOUNT, 0, 0)) + wx_sendmessage(h, WX_CHB_REMOVEPAGE, 0, 0); + + for (c = 0; c < 7; c++) + { + void *page; + char s[80]; + + sprintf(s, "IDC_HDPANEL[%i]", c); + + page = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(page, WX_REPARENT, (LONG_PARAM)h, 0); + wx_sendmessage(h, WX_CHB_ADDPAGE, (LONG_PARAM)page, (LONG_PARAM)"dummy name"); + } + if (hdd_controller_is_scsi(hdd_names[hdd_type])) + { + for (c = 0; c < 7; c++) + { + void *page; + char s[80]; + + sprintf(s, "IDC_HDPANEL[%i]", c); + page = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(page, WX_REPARENT, (LONG_PARAM)h, 0); + sprintf(s, "SCSI ID %i (%c:)", c, 'C'+c); + wx_sendmessage(h, WX_CHB_SETPAGETEXT, c, (LONG_PARAM)s); + } + } + else if (hdd_controller_is_ide(hdd_names[hdd_type])) + { + for (c = 0; c < 4; c++) + { + void *page; + char s[80]; + + sprintf(s, "IDC_HDPANEL[%i]", c); + page = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(page, WX_REPARENT, (LONG_PARAM)h, 0); + sprintf(s, "Drive %i %s %s (%c:)", c, (c & 2) ? "Secondary" : "Primary", (c & 1) ? "Slave" : "Master", 'C'+c); + wx_sendmessage(h, WX_CHB_SETPAGETEXT, c, (LONG_PARAM)s); + } + for (c = 6; c >= 4; c--) + { + wx_sendmessage(h, WX_CHB_REMOVEPAGE, c, 0); + } + } + else + { + for (c = 0; c < 2; c++) + { + void *page; + char s[80]; + + sprintf(s, "IDC_HDPANEL[%i]", c); + page = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(page, WX_REPARENT, (LONG_PARAM)h, 0); + sprintf(s, "Drive %i %s (%c:)", c, (c & 1) ? "Secondary" : "Primary", 'C'+c); + wx_sendmessage(h, WX_CHB_SETPAGETEXT, c, (LONG_PARAM)s); + } + for (c = 6; c >= 2; c--) + { + wx_sendmessage(h, WX_CHB_REMOVEPAGE, c, 0); + } + } +} + +// TODO: split this into model/speed recalcs? +static void recalc_cd_list(void *hdlg, int cur_speed, char *cur_model) +{ + int temp_model = -1; + void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL")); + int c = 0; + int found = 0; + + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + if (hdd_controller_selected_is_ide(hdlg) || hdd_controller_selected_is_scsi(hdlg)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + while (1) + { + char s[40]; + char *model; + + if ((cd_get_model_interfaces(c) == CD_MODEL_INTERFACE_ALL) || + (cd_get_model_interfaces(c) == CD_MODEL_INTERFACE_IDE && hdd_controller_selected_is_ide(hdlg)) || + (cd_get_model_interfaces(c) == CD_MODEL_INTERFACE_SCSI && hdd_controller_selected_is_scsi(hdlg))) + { + + model = cd_get_model(c); + sprintf(s, "%s", model); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + + if (!strncmp(s, cur_model, 40)) + { + wx_sendmessage(h, WX_CB_SETCURSEL, c, 0); + temp_model = c; + found = 1; + } + } + + c++; + if (c > MAX_CD_MODEL) + break; + } + if (!found) + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); // assume that there is always at least one TODO: is this necessary? + + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED")); + c = 0; + found = 0; + + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + if (temp_model >= 0 && cd_get_model_speed(temp_model) != -1) + { + // this model has a specific speed + wx_enablewindow(h, FALSE); + cur_speed = cd_get_model_speed(temp_model); + } + else if (hdd_controller_selected_is_ide(hdlg) || hdd_controller_selected_is_scsi(hdlg)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + while (1) + { + char s[8]; + int speed; + + speed = cd_get_speed(c); + sprintf(s, "%iX", speed); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + + if (speed == cur_speed) + { + wx_sendmessage(h, WX_CB_SETCURSEL, c, 0); + found = 1; + } + + c++; + if (speed >= MAX_CD_SPEED) + break; + } + if (!found) + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); // fall back TODO: is this necessary? +} + +#ifdef USE_NETWORKING +static void recalc_net_list(void *hdlg, int model) +{ + void *h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETCARD")); + int c = 0, d = 0; + int found_card = 0; + + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + + while (1) + { + char *s = network_card_getname(c); + device_t *dev; + + if (!s[0]) + break; + + settings_network_to_list[c] = d; + + dev = network_card_getdevice(c); + + if (network_card_available(c) && + (!dev || (models[model].flags & MODEL_PCI) || !(dev->flags & DEVICE_PCI))) + { + device_t *network_dev = network_card_getdevice(c); + + if (!network_dev || (network_dev->flags & DEVICE_MCA) == (models[model].flags & MODEL_MCA)) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + settings_list_to_network[d] = c; + if (c == network_card_current) + { + wx_sendmessage(h, WX_CB_SETCURSEL, d, 0); + found_card = 1; + } + d++; + } + } + + c++; + } + if (!found_card) + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); +} +#endif + +int config_dlgsave(void* hdlg) +{ + char temp_str[256]; + void* h; + int c; + int gfx;//, fpu; + int temp_cpu, temp_cpu_m, temp_model, temp_fpu; + int temp_GAMEBLASTER, temp_GUS, temp_SSI2001, temp_voodoo, temp_sound_card_current; + int temp_dynarec; + int temp_fda_type, temp_fdb_type; + int temp_mouse_type; + int temp_lpt1_device; + int temp_joystick_type; +#ifdef USE_NETWORKING + int temp_network_card; +#endif + int hdd_changed = 0; + char s[260]; + PcemHDC hd[7]; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_MEMSPIN")); + int mem = wx_sendmessage(h, WX_UDM_GETPOS, 0, 0); + 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].flags & MODEL_AT) && models[temp_model].ram_granularity < 128) + mem *= 1024; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID")); + wx_sendmessage(h, WX_CB_GETLBTEXT, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0), + (LONG_PARAM) temp_str); + gfx = video_new_to_old(video_card_getid(temp_str)); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM")); + temp_cpu_m = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3")); + temp_cpu = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); +// fpu = (models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type +// >= CPU_i486DX) ? 1 : 0; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU")); + temp_fpu = fpu_get_type_from_index(temp_model, temp_cpu_m, temp_cpu, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECK3")); + temp_GAMEBLASTER = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKGUS")); + temp_GUS = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKSSI")); + temp_SSI2001 = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKSYNC")); + enable_sync = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKVOODOO")); + temp_voodoo = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSND")); + temp_sound_card_current = settings_list_to_sound[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC")); + temp_dynarec = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBODRA")); + temp_fda_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBODRB")); + temp_fdb_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY")); + temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOMOUSE")); + temp_mouse_type = settings_list_to_mouse[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD")); + c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (hdd_names[c]) + hdd_changed = strncmp(hdd_names[c], hdd_controller_name, sizeof(hdd_controller_name)-1); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOLPT1")); + temp_lpt1_device = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + +#ifdef USE_NETWORKING + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETCARD")); + temp_network_card = settings_list_to_network[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; +#endif + + if (temp_model != model || gfx != gfxcard || mem != mem_size || temp_fpu != fpu_type || + 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_fda_type != fdd_get_type(0) || temp_fdb_type != fdd_get_type(1) || + temp_mouse_type != mouse_type || hdd_changed || hd_changed || cdrom_channel != new_cdrom_channel || + zip_channel != new_zip_channel || strcmp(lpt1_device_name, lpt_device_get_internal_name(temp_lpt1_device)) +#ifdef USE_NETWORKING + || temp_network_card != network_card_current +#endif + ) + { + if (!has_been_inited || confirm()) + { + savenvr(); + model = temp_model; + romset = model_getromset(); + gfxcard = gfx; + mem_size = mem; + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + fpu_type = temp_fpu; + 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; + mouse_type = temp_mouse_type; + strcpy(lpt1_device_name, lpt_device_get_internal_name(temp_lpt1_device)); +#ifdef USE_NETWORKING + network_card_current = temp_network_card; +#endif + + fdd_set_type(0, temp_fda_type); + fdd_set_type(1, temp_fdb_type); + + if (hdd_names[c]) + strncpy(hdd_controller_name, hdd_names[c], sizeof(hdd_controller_name)-1); + else + strcpy(hdd_controller_name, "none"); + + for (c = 0; c < 7; c++) + { + sprintf(s, "IDC_EDIT_SPT[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd[c].spt); + sprintf(s, "IDC_EDIT_HPC[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd[c].hpc); + sprintf(s, "IDC_EDIT_CYL[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd[c].tracks); + sprintf(s, "IDC_EDIT_FN[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(h, WX_WM_GETTEXT, 511, (LONG_PARAM)ide_fn[c]); + + hdc[c] = hd[c]; + } + + cdrom_channel = new_cdrom_channel; + zip_channel = new_zip_channel; + + if (has_been_inited) + { + mem_alloc(); + loadbios(); + resetpchard(); + } + } + else + return TRUE; + } + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSPD")); + video_speed = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0) - 1; + + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + cpu_set(); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS")); + cpu_waitstates = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + cpu_update_waitstates(); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED")); + cd_speed = cd_get_speed(wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)); + cd_set_speed(cd_speed); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL")); + cd_model = cd_get_model(wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)); + cd_set_model(cd_model); + + if (has_been_inited) + saveconfig(NULL); + + speedchanged(); + + joystick_type = temp_joystick_type; + gameport_update_joystick_type(); + + + return TRUE; +} + +static int prev_model; +int config_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + char temp_str[256]; + void* h; + int c, d; + int gfx, mem; + int temp_cpu, temp_cpu_m, temp_model, temp_fpu; + int temp_sound_card_current; + int temp_dynarec; + int cpu_flags; + int cpu_type; + int temp_cd_model, temp_cd_speed; + int temp_mouse_type; +#ifdef USE_NETWORKING + int temp_network_card; +#endif + + switch (message) + { + case WX_INITDIALOG: + { + pause = 1; + h = wx_getdlgitem(hdlg, WX_ID("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]) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) models[c].name); + modeltolist[c] = d; + listtomodel[d] = c; + romstolist[models[c].id] = d; + romstomodel[models[c].id] = c; + d++; + } + c++; + } + wx_sendmessage(h, WX_CB_SETCURSEL, modeltolist[model], 0); + model = listtomodel[modeltolist[model]]; + romset = model_getromset(); + prev_model = model; + + recalc_vid_list(hdlg, romstomodel[romset], 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM")); + c = 0; + while (models[romstomodel[romset]].cpu[c].cpus != NULL && c < 4) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, + (LONG_PARAM) models[romstomodel[romset]].cpu[c].name); + c++; + } + wx_enablewindow(h, TRUE); + wx_sendmessage(h, WX_CB_SETCURSEL, cpu_manufacturer, 0); + if (c == 1) + wx_enablewindow(h, FALSE); + else + wx_enablewindow(h, TRUE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3")); + c = 0; + while (models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].cpu_type != -1) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, + (LONG_PARAM) models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].name); + c++; + } + wx_enablewindow(h, TRUE); + wx_sendmessage(h, WX_CB_SETCURSEL, cpu, 0); + + recalc_fpu_list(hdlg, romstomodel[romset], cpu_manufacturer, cpu, fpu_type); + + recalc_snd_list(hdlg, romstomodel[romset]); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECK3")); + wx_sendmessage(h, WX_BM_SETCHECK, GAMEBLASTER, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKGUS")); + wx_sendmessage(h, WX_BM_SETCHECK, GUS, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKSSI")); + wx_sendmessage(h, WX_BM_SETCHECK, SSI2001, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKSYNC")); + wx_sendmessage(h, WX_BM_SETCHECK, enable_sync, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKVOODOO")); + wx_sendmessage(h, WX_BM_SETCHECK, voodoo_enabled, 0); + + cpu_flags = + models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC")); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + wx_enablewindow(h, FALSE); + else + wx_enablewindow(h, TRUE); + wx_sendmessage(h, WX_BM_SETCHECK, + ((cpu_flags & CPU_SUPPORTS_DYNAREC) && cpu_use_dynarec) + || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSPD")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "Default"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "8-bit"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "Slow 16-bit"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "Fast 16-bit"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "Slow VLB/PCI"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "Mid VLB/PCI"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "Fast VLB/PCI"); + wx_sendmessage(h, WX_CB_SETCURSEL, video_speed+1, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_MEMSPIN")); + printf("%d\n", models[model].ram_granularity); + wx_sendmessage(h, WX_UDM_SETRANGE, 0, + (models[romstomodel[romset]].min_ram << 16) + | models[romstomodel[romset]].max_ram); + wx_sendmessage(h, WX_UDM_SETINCR, 0, models[model].ram_granularity); + if (!((models[model].flags & MODEL_AT) && models[model].ram_granularity < 128)) + { + wx_sendmessage(h, WX_UDM_SETPOS, 0, mem_size); + memspin_old = mem_size; + } + else + { + wx_sendmessage(h, WX_UDM_SETPOS, 0, mem_size / 1024); + memspin_old = mem_size / 1024; + } + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREMOD")); + if (model_getdevice(model)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURESND")); + if (sound_card_has_config(sound_card_current)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBODRA")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"None"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 360k"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 1.2M"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 1.2M Dual RPM"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 720k"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 1.44M"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 1.44M 3-Mode"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 2.88M"); + wx_sendmessage(h, WX_CB_SETCURSEL, fdd_get_type(0), 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBODRB")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"None"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 360k"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 1.2M"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"5.25\" 1.2M Dual RPM"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 720k"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 1.44M"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 1.44M 3-Mode"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"3.5\" 2.88M"); + wx_sendmessage(h, WX_CB_SETCURSEL, fdd_get_type(1), 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_TEXT_MB")); + if ((models[model].flags & MODEL_AT) && (models[model].ram_granularity < 128)) + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM) "MB"); + else + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM) "KB"); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY")); + c = 0; + while (joystick_get_name(c)) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)joystick_get_name(c)); + c++; + } + wx_enablewindow(h, TRUE); + wx_sendmessage(h, WX_CB_SETCURSEL, joystick_type, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY1")); + wx_enablewindow(h, (joystick_get_max_joysticks(joystick_type) >= 1) ? TRUE : FALSE); + h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY2")); + wx_enablewindow(h, (joystick_get_max_joysticks(joystick_type) >= 2) ? TRUE : FALSE); + h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY3")); + wx_enablewindow(h, (joystick_get_max_joysticks(joystick_type) >= 3) ? TRUE : FALSE); + h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY4")); + wx_enablewindow(h, (joystick_get_max_joysticks(joystick_type) >= 4) ? TRUE : FALSE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "System default"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "0 W/S"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "1 W/S"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "2 W/S"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "3 W/S"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "4 W/S"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "5 W/S"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "6 W/S"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) "7 W/S"); + wx_sendmessage(h, WX_CB_SETCURSEL, cpu_waitstates, 0); + cpu_type = + models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].cpu_type; + if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOMOUSE")); + c = d = 0; + while (1) + { + char *s = mouse_get_name(c); + int type; + + if (!s) + break; + + type = mouse_get_type(c); + + settings_mouse_to_list[c] = d; + + if (mouse_valid(type, model)) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) s); + + settings_list_to_mouse[d] = c; + d++; + } + c++; + } + wx_sendmessage(h, WX_CB_SETCURSEL, settings_mouse_to_list[mouse_type], 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOLPT1")); + c = d = 0; + while (1) + { + char *s = lpt_device_get_name(c); + + if (!s) + break; + + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + if (!strcmp(lpt1_device_name, lpt_device_get_internal_name(c))) + d = c; + + c++; + } + wx_sendmessage(h, WX_CB_SETCURSEL, d, 0); + + recalc_hdd_list(hdlg, romstomodel[romset], 0, 0); + + hd_changed = 0; + new_cdrom_channel = cdrom_channel; + new_zip_channel = zip_channel; + + hdconf_init(hdlg); + + for (c = 0; c < 7; c++) + { + char s[80]; + + sprintf(s, "IDC_COMBODRIVETYPE[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Hard drive"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"CD-ROM"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Iomega Zip"); + if (cdrom_channel == c) + wx_sendmessage(h, WX_CB_SETCURSEL, 1, 0); + else if (zip_channel == c) + wx_sendmessage(h, WX_CB_SETCURSEL, 2, 0); + else + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + } + + recalc_cd_list(hdlg, cd_speed, cd_model); + +#ifdef USE_NETWORKING + recalc_net_list(hdlg, romstomodel[romset]); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURE_NETCARD")); + if (network_card_has_config(network_card_current)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); +#endif + + return TRUE; + } + break; + case WX_COMMAND: + { + if (wParam == WX_ID("IDC_COMBO1")) + { + int force_ide = 0; + int force_builtin_video = 0; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + if (temp_model == prev_model) + break; + + if ((models[temp_model].flags & MODEL_HAS_IDE) && !(models[prev_model].flags & MODEL_HAS_IDE)) + force_ide = 1; + if (model_has_optional_gfx(temp_model)) + force_builtin_video = 1; + + prev_model = temp_model; + + /*Rebuild manufacturer list*/ + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM")); + temp_cpu_m = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[c].cpus != NULL && c < 4) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, + (LONG_PARAM) models[temp_model].cpu[c].name); + c++; + } + if (temp_cpu_m >= c) + temp_cpu_m = c - 1; + wx_sendmessage(h, WX_CB_SETCURSEL, temp_cpu_m, 0); + if (c == 1) + wx_enablewindow(h, FALSE); + else + wx_enablewindow(h, TRUE); + + /*Rebuild CPU list*/ + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3")); + temp_cpu = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, + (LONG_PARAM) models[temp_model].cpu[temp_cpu_m].cpus[c].name); + c++; + } + if (temp_cpu >= c) + temp_cpu = c - 1; + wx_sendmessage(h, WX_CB_SETCURSEL, temp_cpu, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU")); + temp_fpu = fpu_get_type_from_index(temp_model, temp_cpu_m, temp_cpu, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)); + recalc_fpu_list(hdlg, temp_model, temp_cpu_m, temp_cpu, temp_fpu); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC")); + temp_dynarec = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + cpu_flags = + models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC")); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + wx_enablewindow(h, FALSE); + else + wx_enablewindow(h, TRUE); + wx_sendmessage(h, WX_BM_SETCHECK, + ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) + || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_TEXT_MB")); + if ((models[temp_model].flags & MODEL_AT) && models[temp_model].ram_granularity < 128) + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM) "MB"); + else + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM) "KB"); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_MEMSPIN")); + mem = wx_sendmessage(h, WX_UDM_GETPOS, 0, 0); + wx_sendmessage(h, WX_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; + wx_sendmessage(h, WX_UDM_SETPOS, 0, mem); + wx_sendmessage(h, WX_UDM_SETINCR, 0, models[temp_model].ram_granularity); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS")); + cpu_type = + models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREMOD")); + if (model_getdevice(temp_model)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOMOUSE")); + temp_mouse_type = settings_list_to_mouse[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + c = d = 0; + while (1) + { + char *s = mouse_get_name(c); + int type; + + if (!s) + break; + + type = mouse_get_type(c); + settings_mouse_to_list[c] = d; + + if (mouse_valid(type, temp_model)) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) s); + + settings_list_to_mouse[d] = c; + d++; + } + + c++; + } + + if (mouse_valid(mouse_get_type(temp_mouse_type), temp_model)) + wx_sendmessage(h, WX_CB_SETCURSEL, settings_mouse_to_list[temp_mouse_type], 0); + else + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + + recalc_vid_list(hdlg, temp_model, force_builtin_video); + + recalc_hdd_list(hdlg, temp_model, 1, force_ide); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL")); + temp_cd_model = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED")); + temp_cd_speed = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + recalc_cd_list(hdlg, cd_get_speed(temp_cd_speed), cd_get_model(temp_cd_model)); + + recalc_snd_list(hdlg, temp_model); +#ifdef USE_NETWORKING + recalc_net_list(hdlg, temp_model); +#endif + } + else if (wParam == WX_ID("IDC_COMBOCPUM")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM")); + temp_cpu_m = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + /*Rebuild CPU list*/ + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3")); + temp_cpu = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, + (LONG_PARAM) models[temp_model].cpu[temp_cpu_m].cpus[c].name); + c++; + } + if (temp_cpu >= c) + temp_cpu = c - 1; + wx_sendmessage(h, WX_CB_SETCURSEL, temp_cpu, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU")); + temp_fpu = fpu_get_type_from_index(temp_model, temp_cpu_m, temp_cpu, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)); + recalc_fpu_list(hdlg, temp_model, temp_cpu_m, temp_cpu, temp_fpu); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC")); + temp_dynarec = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + cpu_flags = + models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC")); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + wx_enablewindow(h, FALSE); + else + wx_enablewindow(h, TRUE); + wx_sendmessage(h, WX_BM_SETCHECK, + ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) + || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS")); + cpu_type = + models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + } + else if (wParam == WX_ID("IDC_COMBO3")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOCPUM")); + temp_cpu_m = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO3")); + temp_cpu = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOFPU")); + temp_fpu = fpu_get_type_from_index(temp_model, temp_cpu_m, temp_cpu, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)); + recalc_fpu_list(hdlg, temp_model, temp_cpu_m, temp_cpu, temp_fpu); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC")); + temp_dynarec = wx_sendmessage(h, WX_BM_GETCHECK, 0, 0); + + cpu_flags = + models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h = wx_getdlgitem(hdlg, WX_ID("IDC_CHECKDYNAREC")); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + wx_enablewindow(h, FALSE); + else + wx_enablewindow(h, TRUE); + wx_sendmessage(h, WX_BM_SETCHECK, + ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) + || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOWS")); + cpu_type = + models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if (cpu_type >= CPU_286 && cpu_type <= CPU_386DX) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + } + else if (wParam == WX_ID("IDC_CONFIGUREMOD")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *) model_getdevice(temp_model)); + } + else if (wParam == WX_ID("IDC_CONFIGUREVID")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID")); + wx_sendmessage(h, WX_CB_GETLBTEXT, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0), (LONG_PARAM) temp_str); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(temp_str), model_getromset_from_model(temp_model))); + } + else if (wParam == WX_ID("IDC_COMBOVID")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOVID")); + wx_sendmessage(h, WX_CB_GETLBTEXT, wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0), + (LONG_PARAM) temp_str); + gfx = video_card_getid(temp_str); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREVID")); + if (video_card_has_config(gfx, model_getromset_from_model(temp_model))) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + } + else if (wParam == WX_ID("IDC_CONFIGURESND")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSND")); + temp_sound_card_current = settings_list_to_sound[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *) sound_card_getdevice(temp_sound_card_current)); + } + else if (wParam == WX_ID("IDC_COMBOSND")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOSND")); + temp_sound_card_current = settings_list_to_sound[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURESND")); + if (sound_card_has_config(temp_sound_card_current)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + } + else if (wParam == WX_ID("IDC_CONFIGUREVOODOO")) + { + deviceconfig_open(hdlg, (void *) &voodoo_device); + } + else if (wParam == WX_ID("IDC_COMBOHDD")) + { + hdconf_update(hdlg); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + recalc_hdd_list(hdlg, temp_model, 1, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL")); + temp_cd_model = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED")); + temp_cd_speed = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + recalc_cd_list(hdlg, cd_get_speed(temp_cd_speed), cd_get_model(temp_cd_model)); + } + else if (wParam == WX_ID("IDC_CONFIGUREHDD")) + { + deviceconfig_open(hdlg, (void *)hdd_controller_selected_get_device(hdlg)); + } + else if (wParam == WX_ID("IDC_COMBO_CDMODEL")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDMODEL")); + temp_cd_model = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_CDSPEED")); + temp_cd_speed = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + recalc_cd_list(hdlg, cd_get_speed(temp_cd_speed), cd_get_model(temp_cd_model)); + } +#ifdef USE_NETWORKING + else if (wParam == WX_ID("IDC_COMBO_NETCARD")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETCARD")); + temp_network_card = settings_list_to_network[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGURE_NETCARD")); + if (network_card_has_config(temp_network_card)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + } + else if (wParam == WX_ID("IDC_CONFIGURE_NETCARD")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETCARD")); + temp_network_card = settings_list_to_network[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_network_card)); + } +#endif + else if (wParam == WX_ID("IDC_COMBOJOY")) + { + int temp_joystick_type; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY")); + temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY1")); + wx_enablewindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 1) ? TRUE : FALSE); + h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY2")); + wx_enablewindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 2) ? TRUE : FALSE); + h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY3")); + wx_enablewindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 3) ? TRUE : FALSE); + h = wx_getdlgitem(hdlg, WX_ID("IDC_JOY4")); + wx_enablewindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 4) ? TRUE : FALSE); + } + else if (wParam == WX_ID("IDC_JOY1")) + { + int temp_joystick_type; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY")); + temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 0, temp_joystick_type); + } + else if (wParam == WX_ID("IDC_JOY2")) + { + int temp_joystick_type; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY")); + temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 1, temp_joystick_type); + } + else if (wParam == WX_ID("IDC_JOY3")) + { + int temp_joystick_type; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY")); + temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 2, temp_joystick_type); + } + else if (wParam == WX_ID("IDC_JOY4")) + { + int temp_joystick_type; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOJOY")); + temp_joystick_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 3, temp_joystick_type); + } +#ifndef __WXGTK__ + /*Emulate spinner granularity on systems that don't implement wxSpinCtrl->SetIncrement()*/ + else if (wParam == WX_ID("IDC_MEMSPIN")) + { + int mem; + int granularity; + int granularity_mask; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO1")); + temp_model = listtomodel[wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0)]; + + granularity = models[temp_model].ram_granularity; + granularity_mask = granularity - 1; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_MEMSPIN")); + mem = wx_sendmessage(h, WX_UDM_GETPOS, 0, 0); + if (mem < memspin_old) + { + /*Assume decrease*/ + mem &= ~granularity_mask; + } + else + { + /*Assume increase*/ + mem = (mem + granularity_mask) & ~granularity_mask; + } + wx_sendmessage(h, WX_UDM_SETPOS, 0, mem); + memspin_old = mem; + } +#endif + return 0; + } + } + return 0; +} + +static struct +{ + int cylinders; + int heads; +} hd_types[] = +{ + {306, 4}, {615, 4}, {615, 6}, {940, 8}, + {940, 6}, {615, 4}, {462, 8}, {733, 5}, + {900, 15}, {820, 3}, {855, 5}, {855, 7}, + {306, 8}, {733, 7}, {0, 0}, {612, 4}, + {977, 5}, {977, 7}, {1024, 7}, {733, 5}, + {733, 7}, {733, 5}, {306, 4}, {925, 7}, + {925, 9}, {754, 7}, {754, 11}, {699, 7}, + {823, 10}, {918, 7}, {1024, 11}, {1024, 15}, + {1024, 5}, {612, 2}, {1024, 9}, {1024, 8}, + {615, 8}, {987, 3}, {462, 7}, {820, 6}, + {977, 5}, {981, 5}, {830, 7}, {830, 10}, + {917, 15}, {1224, 15} +}; + +static int hdd_controller_selected_is_mfm(void* hdlg) +{ + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD")); + int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (hdd_names[c]) + return hdd_controller_is_mfm(hdd_names[c]); + return 0; +} +static int hdd_controller_selected_is_ide(void* hdlg) +{ + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD")); + int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (hdd_names[c]) + return hdd_controller_is_ide(hdd_names[c]); + return 0; +} +static int hdd_controller_selected_is_scsi(void* hdlg) +{ + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD")); + int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (hdd_names[c]) + return hdd_controller_is_scsi(hdd_names[c]); + return 0; +} +static int hdd_controller_selected_has_config(void* hdlg) +{ + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD")); + int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (hdd_names[c]) + return hdd_controller_has_config(hdd_names[c]); + return 0; +} +static device_t *hdd_controller_selected_get_device(void *hdlg) +{ + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBOHDD")); + int c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (hdd_names[c]) + return hdd_controller_get_device(hdd_names[c]); + return NULL; +} + +static void check_hd_type(void* hdlg, off64_t sz) +{ + int c; + + hd_new_type = 0; + + if (hdd_controller_selected_is_mfm(hdlg)) + { + for (c = 0; c < 46; c++) + { + if ((hd_types[c].cylinders * hd_types[c].heads * 17 * 512) == sz) + { + hd_new_spt = 17; + hd_new_hpc = hd_types[c].heads; + hd_new_cyl = hd_types[c].cylinders; + hd_new_type = c+1; + return; + } + } + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + } + else + { + if ((sz % 17) == 0 && sz <= 142606336) + { + hd_new_spt = 17; + + if (sz <= 26738688) + hd_new_hpc = 4; + else if ((sz % 3072) == 0 && sz <= 53477376) + hd_new_hpc = 6; + else + { + for (c=5;c<16;c++) + { + if((sz % (c * 512)) == 0 && sz <= 1024*c*17*512) break; + if (c == 5) c++; + } + hd_new_hpc = c; + } + hd_new_cyl = (int)((sz / 512) / hd_new_hpc) / 17; + } + else + { + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + } + } +} + +static void update_hdd_cdrom(void* hdlg) +{ + void* h; + int i, j, b; + char s[25]; + + int is_mfm = hdd_controller_selected_is_mfm(hdlg); + + for (i = 0; i < 7; ++i) + { + b = !is_mfm && ((new_cdrom_channel == i) || (new_zip_channel == i)); + pclog("update_hdd_cdrom: i=%i b=%i new_cdrom_channel=%i new_zip_channel=%i\n", i, b, new_cdrom_channel, new_zip_channel); + sprintf(s, "IDC_COMBODRIVETYPE[%d]", i); + h = wx_getdlgitem(hdlg, WX_ID(s)); + if (i == new_cdrom_channel) + wx_sendmessage(h, WX_CB_SETCURSEL, 1, 0); + else if (i == new_zip_channel) + wx_sendmessage(h, WX_CB_SETCURSEL, 2, 0); + else + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + sprintf(s, "IDC_EDIT_FN[%d]", i); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + sprintf(s, "IDC_FILE[%d]", i); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + sprintf(s, "IDC_EJECT[%d]", i); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + sprintf(s, "IDC_NEW[%d]", i); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + sprintf(s, "IDC_EDIT_SPT[%d]", i); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + sprintf(s, "IDC_EDIT_HPC[%d]", i); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + sprintf(s, "IDC_EDIT_CYL[%d]", i); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + sprintf(s, "IDC_TEXT_SIZE[%d]", i); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + for (j = 1; j < 6; ++j) + { + sprintf(s, "IDC_HDD_LABEL[%d]", i*10+j); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !b); + } + } +} + +static volatile int create_drive_pos; +static int create_drive_raw(void* data) +{ + int c; + uint8_t buf[512]; + FILE* f = (FILE*)data; + memset(buf, 0, 512); + for (c = 0; c < (hd_new_cyl * hd_new_hpc * hd_new_spt); c++) + { + create_drive_pos = c; + fwrite(buf, 512, 1, f); + } + + fclose(f); + + return 1; +} + +static void vhd_progress_callback(uint32_t current_sector, uint32_t total_sectors) +{ + create_drive_pos = (int)current_sector; +} + +/* If the disk geometry requested in the PCem GUI is not compatible with the internal VHD geometry, + * we adjust it to the next-largest size that is compatible. On average, this will be a difference + * of about 21 MB, and should only be necessary for VHDs larger than 31.5 GB, so should never be more + * than a tenth of a percent change in size. + */ +static void adjust_pcem_geometry_for_vhd(MVHDGeom *vhd_geometry) +{ + if (hd_new_cyl <= 65535) + return; + + int desired_sectors = hd_new_cyl * hd_new_hpc * hd_new_spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; + + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors += (85680 - remainder); + + hd_new_cyl = desired_sectors / (16 * 63); + hd_new_hpc = 16; + hd_new_spt = 63; + + vhd_geometry->cyl = desired_sectors / (16 * 255); + vhd_geometry->heads = 16; + vhd_geometry->spt = 255; +} + +static void adjust_vhd_geometry_for_pcem() +{ + if (hd_new_spt <= 63) + return; + + int desired_sectors = hd_new_cyl * hd_new_hpc * hd_new_spt; + if (desired_sectors > 267321600) + desired_sectors = 267321600; + + int remainder = desired_sectors % 85680; /* 8560 is the LCM of 1008 (63*16) and 4080 (255*16) */ + if (remainder > 0) + desired_sectors -= remainder; + + hd_new_cyl = desired_sectors / (16 * 63); + hd_new_hpc = 16; + hd_new_spt = 63; +} + +static int create_drive_vhd_fixed(void *data) +{ + MVHDGeom geometry = { .cyl = hd_new_cyl, .heads = hd_new_hpc, .spt = hd_new_spt }; + adjust_pcem_geometry_for_vhd(&geometry); + + int vhd_error = 0; + MVHDMeta *vhd = mvhd_create_fixed(hd_new_name, geometry, &vhd_error, vhd_progress_callback); + if (vhd == NULL) + { + return 0; + } + else + { + mvhd_close(vhd); + return 1; + } +} + +static int create_drive_vhd_dynamic(int blocksize) +{ + MVHDGeom geometry = { .cyl = hd_new_cyl, .heads = hd_new_hpc, .spt = hd_new_spt }; + adjust_pcem_geometry_for_vhd(&geometry); + int vhd_error = 0; + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = hd_new_name; + options.size_in_bytes = 0; + options.geometry = geometry; + options.type = MVHD_TYPE_DYNAMIC; + + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + if (vhd == NULL) + { + return 0; + } + else + { + mvhd_close(vhd); + return 1; + } +} + +static int create_drive_vhd_diff(char* parent_filename, int blocksize) +{ + int vhd_error = 0; + MVHDCreationOptions options; + options.block_size_in_sectors = blocksize; + options.path = hd_new_name; + options.parent_path = parent_filename; + options.type = MVHD_TYPE_DIFF; + + MVHDMeta *vhd = mvhd_create_ex(options, &vhd_error); + if (vhd == NULL) + { + return 0; + } + else + { + MVHDGeom vhd_geom = mvhd_get_geometry(vhd); + + if (vhd_geom.spt > 63) + { + hd_new_cyl = mvhd_calc_size_sectors(&vhd_geom) / (16 * 63); + hd_new_hpc = 16; + hd_new_spt = 63; + } + else + { + hd_new_cyl = vhd_geom.cyl; + hd_new_hpc = vhd_geom.heads; + hd_new_spt = vhd_geom.spt; + } + + mvhd_close(vhd); + return 1; + } +} + +static int hdnew_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + char s[260]; + void* h; + int c; + PcemHDC hd[7]; + FILE *f; + int hd_type, hd_format, hd_blocksize; + int size; + + switch (message) + { + case WX_INITDIALOG: + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + sprintf(s, "%i", 63); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + sprintf(s, "%i", 16); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + sprintf(s, "%i", 511); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDITC")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)""); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4")); + sprintf(s, "%i", (((511*16*63)*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + +// hd_type = 0; + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Custom type"); + for (c = 1; c <= 46; c++) + { + sprintf(s, "Type %02i : cylinders=%i, heads=%i, size=%iMB", c, hd_types[c-1].cylinders, hd_types[c-1].heads, (hd_types[c-1].cylinders * hd_types[c-1].heads * 17 * 512) / (1024 * 1024)); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + } + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDFORMAT")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Raw (.img)"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Fixed-size VHD (.vhd)"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Dynamic-size VHD (.vhd)"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Differencing VHD (.vhd)"); + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZE")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Large blocks (2 MB)"); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Small blocks (512 KB)"); + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + wx_sendmessage(h, WX_WM_SHOW, 0, (LONG_PARAM)0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZELABEL")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)" "); + + return TRUE; + case WX_COMMAND: + if (wParam == wxID_OK) { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDITC")); + wx_sendmessage(h, WX_WM_GETTEXT, 511, (LONG_PARAM)hd_new_name); + if (!hd_new_name[0]) + { + wx_messagebox(hdlg,"Please enter a valid filename","PCem error",WX_MB_OK); + return TRUE; + } + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd_new_spt); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd_new_hpc); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd_new_cyl); + + if (hd_new_spt > 63) + { + wx_messagebox(hdlg, "Drive has too many sectors (maximum is 63)", "PCem error", WX_MB_OK); + return TRUE; + } + if (hd_new_hpc > 16) + { + wx_messagebox(hdlg, "Drive has too many heads (maximum is 16)", "PCem error", WX_MB_OK); + return TRUE; + } + if (hd_new_cyl > MAX_CYLINDERS) + { + char s[256]; + sprintf(s, "Drive has too many cylinders (maximum is %i)", MAX_CYLINDERS); + wx_messagebox(hdlg, s, "PCem error", WX_MB_OK); + return TRUE; + } + + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDFORMAT")); + hd_format = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZE")); + hd_blocksize = (wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0) == 0) ? MVHD_BLOCK_LARGE : MVHD_BLOCK_SMALL; + + if (hd_format == 0) /* Raw .img */ + { + f = fopen64(hd_new_name, "wb"); + if (!f) + { + wx_messagebox(hdlg, "Can't open file for write", "PCem error", WX_MB_OK); + return TRUE; + } + wx_progressdialog(hdlg, "PCem", "Creating drive, please wait...", create_drive_raw, f, hd_new_cyl * hd_new_hpc * hd_new_spt, &create_drive_pos); + } + else if (hd_format == 1) /* Fixed VHD */ + { + if (!wx_progressdialog(hdlg, "PCem", "Creating drive, please wait...", create_drive_vhd_fixed, NULL, hd_new_cyl * hd_new_hpc * hd_new_spt, &create_drive_pos)) + { + wx_messagebox(hdlg, "Can't create VHD", "PCem error", WX_MB_OK); + return TRUE; + } + } + else if (hd_format == 2) /* Dynamic VHD */ + { + if (!create_drive_vhd_dynamic(hd_blocksize)) + { + wx_messagebox(hdlg, "Can't create VHD", "PCem error", WX_MB_OK); + return TRUE; + } + } + else if (hd_format == 3) /* Differencing VHD */ + { + if (!getfilewithcaption(hdlg, "VHD file (*.vhd)|*.vhd|All files (*.*)|*.*", "", "Select the parent VHD")) + { + if (!create_drive_vhd_diff(openfilestring, hd_blocksize)) + { + wx_messagebox(hdlg, "Can't create VHD", "PCem error", WX_MB_OK); + return TRUE; + } + } + wx_messagebox(hdlg, "Differencing VHD image created.\n\n" + "WARNING: Do not open or modify the parent image(s) while this file exists.", "PCem", WX_MB_OK); + } + if (hd_format != 3) + { + wx_messagebox(hdlg, "Drive created, remember to partition and format the new drive.", "PCem", WX_MB_OK); + } + + wx_enddialog(hdlg, 1); + return TRUE; + } else if (wParam == wxID_CANCEL) { + wx_enddialog(hdlg, 0); + return TRUE; + } else if (ID_IS("IDC_CFILE")) { + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDFORMAT")); + hd_format = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (!getsfile(hdlg, + hd_format == 0 ? "Raw Hard disc image (*.img)|*.img|All files (*.*)|*.*" : "VHD file (*.vhd)|*.vhd|All files (*.*)|*.*", + "", + NULL, + hd_format == 0 ? "img" : "vhd")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDITC")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM) openfilestring); + } + return TRUE; + } else if (ID_IS("IDC_EDIT1") || ID_IS("IDC_EDIT2") || ID_IS("IDC_EDIT3")) { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + pclog("EDIT1: %s\n", s); + sscanf(s, "%i", &hd[0].spt); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + pclog("EDIT2: %s\n", s); + sscanf(s, "%i", &hd[0].hpc); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + pclog("EDIT3: %s\n", s); + sscanf(s, "%i", &hd[0].tracks); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4")); + sprintf(s, "%i", (int)(((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + + hd_type = 0; + for (c = 1; c <= 46; c++) + { + pclog("Compare %i,%i %i,%i %i,%i\n", hd[0].spt,17, hd[0].hpc,hd_types[c-1].heads, hd[0].tracks,hd_types[c-1].cylinders); + if (hd[0].spt == 17 && hd[0].hpc == hd_types[c-1].heads && hd[0].tracks == hd_types[c-1].cylinders) + { + hd_type = c; + break; + } + } + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE")); + wx_sendmessage(h, WX_CB_SETCURSEL, hd_type, 0); + + return TRUE; + } + else if (ID_IS("IDC_EDIT4")) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + pclog("EDIT4: %s\n", s); + sscanf(s, "%i", &size); + + hd[0].spt = 63; + hd[0].hpc = 16; + hd[0].tracks = (int)(((int64_t)size * 1024 * 1024) / (16 * 63 * 512)); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + sprintf(s, "%i", 63); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + sprintf(s, "%i", 16); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + sprintf(s, "%i", hd[0].tracks); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + } + else if (ID_IS("IDC_HDTYPE")) { + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE")); + hd_type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (hd_type) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + sprintf(s, "%i", hd_types[hd_type-1].cylinders); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + sprintf(s, "%i", hd_types[hd_type-1].heads); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"17"); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4")); + sprintf(s, "%i", (int)(((uint64_t)hd_types[hd_type-1].cylinders*hd_types[hd_type-1].heads*17*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + } + return TRUE; + } + else if (ID_IS("IDC_HDFORMAT")) { + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDFORMAT")); + hd_format = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + if (hd_format == 3) /* They switched to a dynamic VHD; disable the geometry fields. */ + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"(use parent)"); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"(use parent)"); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"(use parent)"); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"(use parent)"); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE")); + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)0); + } + else /* Restore geometry fields if necessary. */ + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + wx_sendmessage(h, WX_WM_GETTEXT, 0, (LONG_PARAM)s); + if (!strncmp(s, "(use parent)", 12)) + { + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"63"); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"16"); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"511"); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT4")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"251"); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE")); + wx_sendmessage(h, WX_WM_ENABLE, 0, (LONG_PARAM)1); + } + } + + if (hd_format == 2 || hd_format == 3) /* For dynamic and diff VHDs, show the block size dropdown. */ + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZELABEL")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)"Block size:"); + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZE")); + wx_sendmessage(h, WX_WM_SHOW, 0, (LONG_PARAM)1); + } + else /* Hide it otherwise. */ + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZELABEL")); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)" "); + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDBLOCKSIZE")); + wx_sendmessage(h, WX_WM_SHOW, 0, (LONG_PARAM)0); + } + + return TRUE; + } + break; + + } + return FALSE; +} + +static int hdsize_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + char s[260]; + void* h; + PcemHDC hd[2]; + int c; + + switch (message) + { + case WX_INITDIALOG: + h = wx_getdlgitem(hdlg, WX_ID("IDC_HDTYPE")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"Custom type"); + for (c = 1; c <= 46; c++) + { + sprintf(s, "Type %02i : cylinders=%i, heads=%i, size=%iMB", c, hd_types[c-1].cylinders, hd_types[c-1].heads, (hd_types[c-1].cylinders * hd_types[c-1].heads * 17 * 512) / (1024 * 1024)); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + } + wx_sendmessage(h, WX_CB_SETCURSEL, hd_new_type, 0); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + sprintf(s, "%i", hd_new_spt); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + sprintf(s, "%i", hd_new_hpc); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + sprintf(s, "%i", hd_new_cyl); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_TEXT1")); + sprintf(s, "%imb", (int)((((uint64_t)hd_new_spt*(uint64_t)hd_new_hpc*(uint64_t)hd_new_cyl)*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + + return TRUE; + case WX_COMMAND: + if (wParam == wxID_OK) { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd_new_spt); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd_new_hpc); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd_new_cyl); + + if (hd_new_spt > 63) + { + wx_messagebox(hdlg,"Drive has too many sectors (maximum is 63)","PCem error",WX_MB_OK); + return TRUE; + } + if (hd_new_hpc > 16) + { + wx_messagebox(hdlg,"Drive has too many heads (maximum is 16)","PCem error",WX_MB_OK); + return TRUE; + } + if (hd_new_cyl > MAX_CYLINDERS) + { + char s[256]; + sprintf(s, "Drive has too many cylinders (maximum is %i)", MAX_CYLINDERS); + wx_messagebox(hdlg,s,"PCem error",WX_MB_OK); + return TRUE; + } + + wx_enddialog(hdlg,1); + return TRUE; + } else if (wParam == wxID_CANCEL) { + wx_enddialog(hdlg,0); + return TRUE; + } else if (ID_IS("IDC_EDIT1") || ID_IS("IDC_EDIT2") || ID_IS("IDC_EDIT3")) { + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT1")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT2")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = wx_getdlgitem(hdlg, WX_ID("IDC_EDIT3")); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hd[0].tracks); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_TEXT1")); + sprintf(s, "%imb", (int)(((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + return TRUE; + } + + } + return FALSE; +} + +int hdconf_init(void* hdlg) +{ + int c; + + for (c = 0; c < 7; c++) + { + char s[260]; + void *h; + + sprintf(s, "IDC_EDIT_SPT[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + sprintf(s, "%i", hdc[c].spt); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(s, "IDC_EDIT_HPC[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + sprintf(s, "%i", hdc[c].hpc); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(s, "IDC_EDIT_CYL[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + sprintf(s, "%i", hdc[c].tracks); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(s, "IDC_EDIT_FN[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)ide_fn[c]); + + sprintf(s, "IDC_TEXT_SIZE[%i]", c); + h = wx_getdlgitem(hdlg, WX_ID(s)); + sprintf(s, "%imb", (int)(((((uint64_t)hdc[c].tracks*(uint64_t)hdc[c].hpc)*(uint64_t)hdc[c].spt)*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + + } + + return hdconf_update(hdlg); +} + +int hdconf_update(void* hdlg) +{ + char s[260]; + void *h; + + int is_mfm = hdd_controller_selected_is_mfm(hdlg); + + update_hdd_cdrom(hdlg); + + int i; + for (i = 0; i < 7; ++i) + { + sprintf(s, "IDC_HDD_LABEL[%d]", i*10); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !is_mfm); + sprintf(s, "IDC_COMBODRIVETYPE[%d]", i); + h = wx_getdlgitem(hdlg, WX_ID(s)); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID(s)), !is_mfm); + } + + h = wx_getdlgitem(hdlg, WX_ID("IDC_CONFIGUREHDD")); + if (hdd_controller_selected_has_config(hdlg)) + wx_enablewindow(h, TRUE); + else + wx_enablewindow(h, FALSE); + + return TRUE; +} + +static int hd_eject(void *hdlg, int drive) +{ + char s[80]; + + ide_fn[drive][0] = 0; + sprintf(s, "IDC_EDIT_SPT[%i]", drive); + wx_setdlgitemtext(hdlg, WX_ID(s), "0"); + sprintf(s, "IDC_EDIT_HPC[%i]", drive); + wx_setdlgitemtext(hdlg, WX_ID(s), "0"); + sprintf(s, "IDC_EDIT_CYL[%i]", drive); + wx_setdlgitemtext(hdlg, WX_ID(s), "0"); + sprintf(s, "IDC_EDIT_FN[%i]", drive); + wx_setdlgitemtext(hdlg, WX_ID(s), ""); + hd_changed = 1; + + return TRUE; +} + +static int hd_new(void *hdlg, int drive) +{ + if (wx_dialogbox(hdlg, "HdNewDlg", hdnew_dlgproc) == 1) + { + char s[80]; + char id[80]; + void *h; + + sprintf(id, "IDC_EDIT_SPT[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%i", hd_new_spt); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(id, "IDC_EDIT_HPC[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%i", hd_new_hpc); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(id, "IDC_EDIT_CYL[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%i", hd_new_cyl); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(id, "IDC_EDIT_FN[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)hd_new_name); + + sprintf(id, "IDC_TEXT_SIZE[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%imb", (int)(((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + + hd_changed = 1; + } + return TRUE; +} + +static int hd_file(void *hdlg, int drive) +{ + if (!getfile(hdlg, "Hard disc image (*.img;*.vhd)|*.img;*.vhd|All files (*.*)|*.*", "")) + { + off64_t sz; + FILE *f = fopen64(openfilestring, "rb"); + if (!f) + { + wx_messagebox(hdlg,"Can't open file for read","PCem error",WX_MB_OK); + return TRUE; + } + + if (mvhd_file_is_vhd(f)) + { + fclose(f); + int vhdError = 0; + MVHDMeta *vhd = mvhd_open(openfilestring, false, &vhdError); + if (vhd == NULL) + { + wx_messagebox(hdlg,mvhd_strerr(vhdError),"PCem error",WX_MB_OK); + return TRUE; + } + else if (vhdError == MVHD_ERR_TIMESTAMP) + { + const char ts_warning[] = + "WARNING: VHD PARENT/CHILD TIMESTAMPS DO NOT MATCH!\n\n" + "This could indicate that the parent image was modified after this VHD was created.\n\n" + "This could also happen if the VHD files were moved/copied, or the differencing VHD was created with DiskPart.\n\n" + "Do you wish to fix this error after a file copy or DiskPart creation?"; + int wx_res = wx_messagebox(hdlg,ts_warning,"PCem error", WX_MB_NODEFAULT); + if (wx_res == WX_MB_YES) + { + int ts_res = mvhd_diff_update_par_timestamp(vhd, &vhdError); + if (ts_res != 0) + { + wx_messagebox(hdlg,"Can't fix VHD timestamps","PCem error",WX_MB_OK); + mvhd_close(vhd); + return TRUE; + } + } + else + { + mvhd_close(vhd); + return TRUE; + } + + } + MVHDGeom geom = mvhd_get_geometry(vhd); + hd_new_cyl = geom.cyl; + hd_new_hpc = geom.heads; + hd_new_spt = geom.spt; + hd_new_type = 0; + adjust_vhd_geometry_for_pcem(); + mvhd_close(vhd); + } + else + { + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + check_hd_type(hdlg, sz); + } + + if (wx_dialogbox(hdlg, "HdSizeDlg", hdsize_dlgproc) == 1) + { + char s[80]; + char id[80]; + void *h; + + sprintf(id, "IDC_EDIT_SPT[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%i", hd_new_spt); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(id, "IDC_EDIT_HPC[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%i", hd_new_hpc); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(id, "IDC_EDIT_CYL[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%i", hd_new_cyl); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + sprintf(id, "IDC_EDIT_FN[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)openfilestring); + + sprintf(id, "IDC_TEXT_SIZE[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%imb", (int)(((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + + hd_changed = 1; + } + } + return TRUE; +} + +static int hd_edit(void *hdlg, int drive) +{ + char s[80]; + char id[80]; + void *h; + int spt, hpc, tracks; + + sprintf(id, "IDC_EDIT_SPT[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &spt); + sprintf(id, "IDC_EDIT_HPC[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &hpc); + sprintf(id, "IDC_EDIT_CYL[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + wx_sendmessage(h, WX_WM_GETTEXT, 255, (LONG_PARAM)s); + sscanf(s, "%i", &tracks); + + sprintf(id, "IDC_TEXT_SIZE[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + sprintf(s, "%imb", ((((tracks*hpc)*spt)*512)/1024)/1024); + wx_sendmessage(h, WX_WM_SETTEXT, 0, (LONG_PARAM)s); + + return TRUE; +} + +static int hd_combodrivetype(void *hdlg, int drive) +{ + int type; + char id[80]; + void *h; + + sprintf(id, "IDC_COMBODRIVETYPE[%i]", drive); + h = wx_getdlgitem(hdlg, WX_ID(id)); + type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + switch (type) + { + case 0: /*Hard drive*/ + if (new_cdrom_channel == drive) + new_cdrom_channel = -1; + if (new_zip_channel == drive) + new_zip_channel = -1; + break; + case 1: /*CD-ROM*/ + new_cdrom_channel = drive; + if (new_zip_channel == drive) + new_zip_channel = -1; + break; + case 2: /*Zip*/ + new_zip_channel = drive; + if (new_cdrom_channel == drive) + new_cdrom_channel = -1; + break; + } + update_hdd_cdrom(hdlg); + return TRUE; +} + +int hdconf_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + switch (message) + { + case WX_INITDIALOG: + pause = 1; + return hdconf_init(hdlg); + + case WX_COMMAND: + if (ID_IS("IDC_EJECT[0]")) + return hd_eject(hdlg, 0); + else if (ID_IS("IDC_EJECT[1]")) + return hd_eject(hdlg, 1); + else if (ID_IS("IDC_EJECT[2]")) + return hd_eject(hdlg, 2); + else if (ID_IS("IDC_EJECT[3]")) + return hd_eject(hdlg, 3); + else if (ID_IS("IDC_EJECT[4]")) + return hd_eject(hdlg, 4); + else if (ID_IS("IDC_EJECT[5]")) + return hd_eject(hdlg, 5); + else if (ID_IS("IDC_EJECT[6]")) + return hd_eject(hdlg, 6); + else if (ID_IS("IDC_NEW[0]")) + return hd_new(hdlg, 0); + else if (ID_IS("IDC_NEW[1]")) + return hd_new(hdlg, 1); + else if (ID_IS("IDC_NEW[2]")) + return hd_new(hdlg, 2); + else if (ID_IS("IDC_NEW[3]")) + return hd_new(hdlg, 3); + else if (ID_IS("IDC_NEW[4]")) + return hd_new(hdlg, 4); + else if (ID_IS("IDC_NEW[5]")) + return hd_new(hdlg, 5); + else if (ID_IS("IDC_NEW[6]")) + return hd_new(hdlg, 6); + else if (ID_IS("IDC_FILE[0]")) + return hd_file(hdlg, 0); + else if (ID_IS("IDC_FILE[1]")) + return hd_file(hdlg, 1); + else if (ID_IS("IDC_FILE[2]")) + return hd_file(hdlg, 2); + else if (ID_IS("IDC_FILE[3]")) + return hd_file(hdlg, 3); + else if (ID_IS("IDC_FILE[4]")) + return hd_file(hdlg, 4); + else if (ID_IS("IDC_FILE[5]")) + return hd_file(hdlg, 5); + else if (ID_IS("IDC_FILE[6]")) + return hd_file(hdlg, 6); + else if (ID_IS("IDC_EDIT_SPT[0]") || ID_IS("IDC_EDIT_HPC[0]") || ID_IS("IDC_EDIT_CYL[0]")) + return hd_edit(hdlg, 0); + else if (ID_IS("IDC_EDIT_SPT[1]") || ID_IS("IDC_EDIT_HPC[1]") || ID_IS("IDC_EDIT_CYL[1]")) + return hd_edit(hdlg, 1); + else if (ID_IS("IDC_EDIT_SPT[2]") || ID_IS("IDC_EDIT_HPC[2]") || ID_IS("IDC_EDIT_CYL[2]")) + return hd_edit(hdlg, 2); + else if (ID_IS("IDC_EDIT_SPT[3]") || ID_IS("IDC_EDIT_HPC[3]") || ID_IS("IDC_EDIT_CYL[3]")) + return hd_edit(hdlg, 3); + else if (ID_IS("IDC_EDIT_SPT[4]") || ID_IS("IDC_EDIT_HPC[4]") || ID_IS("IDC_EDIT_CYL[4]")) + return hd_edit(hdlg, 4); + else if (ID_IS("IDC_EDIT_SPT[5]") || ID_IS("IDC_EDIT_HPC[5]") || ID_IS("IDC_EDIT_CYL[5]")) + return hd_edit(hdlg, 5); + else if (ID_IS("IDC_EDIT_SPT[6]") || ID_IS("IDC_EDIT_HPC[6]") || ID_IS("IDC_EDIT_CYL[6]")) + return hd_edit(hdlg, 6); + else if (ID_IS("IDC_COMBODRIVETYPE[0]")) + return hd_combodrivetype(hdlg, 0); + else if (ID_IS("IDC_COMBODRIVETYPE[1]")) + return hd_combodrivetype(hdlg, 1); + else if (ID_IS("IDC_COMBODRIVETYPE[2]")) + return hd_combodrivetype(hdlg, 2); + else if (ID_IS("IDC_COMBODRIVETYPE[3]")) + return hd_combodrivetype(hdlg, 3); + else if (ID_IS("IDC_COMBODRIVETYPE[4]")) + return hd_combodrivetype(hdlg, 4); + else if (ID_IS("IDC_COMBODRIVETYPE[5]")) + return hd_combodrivetype(hdlg, 5); + else if (ID_IS("IDC_COMBODRIVETYPE[6]")) + return hd_combodrivetype(hdlg, 6); + } + return FALSE; +} + +int config_dialog_proc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + switch (message) + { + case WX_INITDIALOG: + pause = 1; + return config_dlgproc(hdlg, message, wParam, lParam); + case WX_COMMAND: + { + if (wParam == wxID_OK) + { + config_dlgsave(hdlg); + pause = 0; + wx_enddialog(hdlg, 1); + return TRUE; + } + else if (wParam == wxID_CANCEL) + { + pause = 0; + wx_enddialog(hdlg, 0); + return TRUE; + } + else if (wParam == WX_ID("IDC_NOTEBOOK")) + { + if (lParam == 3) + hdconf_update(hdlg); + } + break; + } + } + config_dlgproc(hdlg, message, wParam, lParam); + hdconf_dlgproc(hdlg, message, wParam, lParam); + return TRUE; +} + + +int config_open(void* hwnd) +{ + return wx_dialogbox(hwnd, "ConfigureDlg", config_dialog_proc); +} diff --git a/src/wx-config_sel.c b/src/wx-config_sel.c new file mode 100644 index 0000000..b21f307 --- /dev/null +++ b/src/wx-config_sel.c @@ -0,0 +1,341 @@ +#include "ibm.h" +#include "config.h" +#include "wx-utils.h" +#include "paths.h" +#include "wx-hostconfig.h" + +static int active_config = -1; + +extern int config_open(void* hwnd); + +static void select_config(void* hdlg, char* name) +{ + char s[512]; + int num, c; + void* h; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + num = wx_sendmessage(h, WX_LB_GETCOUNT, 0, 0); + + for (c = 0; c < num; c++) + { + wx_sendmessage(h, WX_LB_GETTEXT, c, (LONG_PARAM)s); + if (!strcmp(s, name)) + { + wx_sendmessage(h, WX_LB_SETCURSEL, c, 0); + return; + } + } + +} + +static void config_list_update(void* hdlg) +{ + char s[512]; + int num, p; + void* h; + + strcpy(s, configs_path); + put_backslash(s); + strcat(s, "*.cfg"); + pclog("Dir %s\n", s); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + p = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + + wx_dlgdirlist(hdlg, s, WX_ID("IDC_LIST"), 0, 0); + + num = wx_sendmessage(h, WX_LB_GETCOUNT, 0, 0); + + if (num > 0) + { + if (p >= num) + p = num-1; + else if (p < 0) + p = 0; + wx_sendmessage(h, WX_LB_SETCURSEL, p, 0); + } + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID("IDC_RENAME")), num); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID("IDC_DELETE")), num); + wx_enablewindow(wx_getdlgitem(hdlg, WX_ID("IDC_CONFIG")), num); + wx_enablewindow(wx_getdlgitem(hdlg, wxID_OK), num); +} + +static int run(void* hdlg) +{ + char s[512]; + + int ret = wx_dlgdirselectex(hdlg, (LONG_PARAM)s, 512, WX_ID("IDC_LIST")); + + pclog("wx_dlgdirselectex returned %i %s\n", ret, s); + if (s[0]) + { + char cfg[512]; + + active_config = wx_sendmessage(wx_getdlgitem(hdlg, WX_ID("IDC_LIST")), WX_LB_GETCURSEL, 0, 0); + + strcpy(cfg, configs_path); + put_backslash(cfg); + strcat(cfg, s); + strcat(cfg, "cfg"); +// sprintf(cfg, "%s\\configs\\%scfg", config_path, s); + pclog("Config name %s\n", cfg); + + strcpy(config_file_default, cfg); + strcpy(config_name, s); + if (config_name[strlen(config_name)-1] == '.') + config_name[strlen(config_name)-1] = 0; + + wx_enddialog(hdlg, 1); +// pause = 0; + return TRUE; + } + return FALSE; +} + +static int config_selection_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + //void* h; + int done = 0; + + switch (message) + { + case WX_INITDIALOG: + { + // pause = 1; + config_list_update(hdlg); + + if (active_config >= 0) + wx_sendmessage(wx_getdlgitem(hdlg, WX_ID("IDC_LIST")), WX_LB_SETCURSEL, active_config, 0); + + // h = wx_getdlgitem(hdlg, IDC_LIST); + // wx_sendmessage(h, LB_ADDSTRING, 0, (LONG_PARAM)(LPCSTR)"AAA"); + // wx_sendmessage(h, LB_ADDSTRING, 0, (LONG_PARAM)(LPCSTR)"BBB"); + return TRUE; + } + case WX_COMMAND: + { + if (wParam == wxID_OK) + return run(hdlg); + else if (wParam == wxID_CANCEL) + { + wx_enddialog(hdlg, 0); + // pause = 0; + return TRUE; + } + else if (wParam == WX_ID("IDC_NEW")) + { + char name[64]; + name[0] = 0; + + while (!done) + { + if (wx_textentrydialog(hdlg, "Enter name:", "New config", name, 1, 64, (LONG_PARAM)name)) + { + char cfg[512]; + + strcpy(cfg, configs_path); + put_backslash(cfg); + strcat(cfg, name); + strcat(cfg, ".cfg"); + + pclog("Config %s\n", cfg); + + if (!wx_file_exists(cfg)) + { + if (config_open(hdlg)) + { + saveconfig(cfg); + + config_list_update(hdlg); + select_config(hdlg, name); + } + done = 1; + } + else + wx_simple_messagebox("Already exists", "A configuration with that name already exists."); + } + else + done = 1; + } + + return TRUE; + } + else if (wParam == WX_ID("IDC_CONFIG")) + { + char s[512]; + + int ret = wx_dlgdirselectex(hdlg, (LONG_PARAM)s, 512, WX_ID("IDC_LIST")); + + pclog("wx_dlgdirselectex returned %i %s\n", ret, s); + if (s[0]) + { + char cfg[512]; + + strcpy(cfg, configs_path); + put_backslash(cfg); + strcat(cfg, s); + strcat(cfg, "cfg"); + pclog("Config name %s\n", cfg); + + loadconfig(cfg); + config_open(hdlg); + saveconfig(cfg); + } + + return TRUE; + } + else if (wParam == WX_ID("IDC_RENAME")) + { + char name[64]; + char old_name[64]; + void* h; + int c; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + if (c >= 0) + { + wx_sendmessage(h, WX_LB_GETTEXT, c, (LONG_PARAM)old_name); + strcpy(name, old_name); + + while (!done) + { + if (wx_textentrydialog(hdlg, "Enter name:", "New name", name, 1, 64, (LONG_PARAM)name)) + { + char old_path[512]; + char new_path[512]; + + strcpy(old_path, configs_path); + put_backslash(old_path); + strcat(old_path, old_name); + strcat(old_path, ".cfg"); + + strcpy(new_path, configs_path); + put_backslash(new_path); + strcat(new_path, name); + strcat(new_path, ".cfg"); + + pclog("Rename %s to %s\n", old_path, new_path); + + if (!wx_file_exists(new_path)) + { + rename(old_path, new_path); + + config_list_update(hdlg); + done = 1; + } + else + wx_simple_messagebox("Already exists", "A configuration with that name already exists."); + } + else + done = 1; + } + } + + return TRUE; + } + else if (wParam == WX_ID("IDC_COPY")) + { + char name[64]; + char old_name[64]; + void* h; + int c; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + if (c >= 0) + { + wx_sendmessage(h, WX_LB_GETTEXT, c, (LONG_PARAM)old_name); + strcpy(name, old_name); + + while (!done) + { + if (wx_textentrydialog(hdlg, "Enter name:", "New name", name, 1, 64, (LONG_PARAM)name)) + { + char old_path[512]; + char new_path[512]; + + strcpy(old_path, configs_path); + put_backslash(old_path); + strcat(old_path, old_name); + strcat(old_path, ".cfg"); + + strcpy(new_path, configs_path); + put_backslash(new_path); + strcat(new_path, name); + strcat(new_path, ".cfg"); + + pclog("Copy %s to %s\n", old_path, new_path); + + if (!wx_file_exists(new_path)) + { + wx_copy_file(old_path, new_path, 1); + + config_list_update(hdlg); + done = 1; + } + else + wx_simple_messagebox("Already exists", "A configuration with that name already exists."); + } + else + done = 1; + } + } + + return TRUE; + } + else if (wParam == WX_ID("IDC_DELETE")) + { + char name[64]; + void* h; + int c; + h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + if (c >= 0) + { + char s[512]; + wx_sendmessage(h, WX_LB_GETTEXT, c, (LONG_PARAM)name); + sprintf(s, "Do you want to delete \"%s\"?", name); + if (wx_messagebox(NULL, s, "PCem", WX_MB_OKCANCEL) == WX_IDOK) + { + strcpy(s, configs_path); + put_backslash(s); + strcat(s, name); + strcat(s, ".cfg"); + + remove(s); + + config_list_update(hdlg); + } + } + } + else if (wParam == WX_ID("IDC_LIST")) + { + if (lParam == WX_LBN_DBLCLK) + run(hdlg); + } +#ifdef USE_NETWORKING + else if (wParam == WX_ID("IDC_CONFIG_HOST")) + { + hostconfig_open(hdlg); + } +#endif + } + break; + } + return FALSE; +} + +int config_selection_open(void* hwnd, int inited) +{ + int ret; + + has_been_inited = inited; + + ret = wx_dialogbox(hwnd, "ConfigureSelectionDlg", config_selection_dlgproc); + + has_been_inited = 1; + + return ret; +} diff --git a/src/wx-createdisc.cc b/src/wx-createdisc.cc new file mode 100644 index 0000000..f0eb8fc --- /dev/null +++ b/src/wx-createdisc.cc @@ -0,0 +1,147 @@ +#include + +extern "C" void pclog(const char *format, ...); + +#include "wx-createdisc.h" + +#include "wx-utils.h" +#include "wx/wxprec.h" + +#include "wx-dialogbox.h" +#include + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/xrc/xmlres.h" + +#define IDC_CONFIG_BASE 1000 + +static struct +{ + char name[80]; + int nr_sectors; +} disc_formats[] = +{ + {"160 kB", 1*40*8}, + {"180 kB", 1*40*9}, + {"320 kB", 2*40*8}, + {"360 kB", 2*40*9}, + {"720 kB", 2*80*9}, + {"1.2 MB", 2*80*15}, + {"1.44 MB", 2*80*18}, + {"2.88 MB", 2*80*36}, + {"100 MB (Zip)", 2048*96}, + {"", 0} +}; + +static int creatediscimage_dlgproc(void *hdlg, int message, INT_PARAM wParam, + LONG_PARAM lParam) +{ + wxWindow *window = (wxWindow *)hdlg; + int c; + + switch (message) + { + case WX_INITDIALOG: + return TRUE; + + case WX_COMMAND: + switch (wParam) + { + case wxID_OK: + c = 0; + + while (disc_formats[c].nr_sectors) + { + wxWindow *rb_win = window->FindWindow(IDC_CONFIG_BASE + c); + wxRadioButton *rb = wxDynamicCast(rb_win, wxRadioButton); + + if (rb->GetValue()) + break; + c++; + } + + if (disc_formats[c].nr_sectors) + { + char openfilestring[260]; + int ret; + + memset(openfilestring, 0, sizeof(openfilestring)); + ret = wx_filedialog(hdlg, "Save", "", + "Disc image (*.img;*.ima)|*.img;*.ima|All files (*.*)|*.*", + ".img", + 0, openfilestring); + + if (!ret) + { + FILE *f = fopen(openfilestring, "wb"); + if (f) + { + uint8_t sector[512]; + int d; + + memset(sector, 0, 512); + + for (d = 0; d < disc_formats[c].nr_sectors; d++) + fwrite(sector, 512, 1, f); + + fclose(f); + } + } + } + + wx_enddialog(hdlg, 0); + return TRUE; + + case wxID_CANCEL: + wx_enddialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void creatediscimage_open(void *hwnd) +{ + int id = IDC_CONFIG_BASE; + int c = 0; + + PCemDialogBox dialog((wxWindow *)hwnd, creatediscimage_dlgproc); + + dialog.SetTitle("Create Disc Image"); + + wxFlexGridSizer* root = new wxFlexGridSizer(0, 1, 0, 0); + root->SetFlexibleDirection(wxBOTH); + root->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + dialog.SetSizer(root); + + wxFlexGridSizer* sizer = new wxFlexGridSizer(0, 1, 0, 0); + sizer->SetFlexibleDirection(wxBOTH); + sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + root->Add(sizer, 1, wxEXPAND, 5); + + while (disc_formats[c].nr_sectors) + { + wxBoxSizer *radioSizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(radioSizer, 1, wxEXPAND, 5); + wxRadioButton *rb = new wxRadioButton(&dialog, id++, disc_formats[c].name); + radioSizer->Add(rb, 1, wxALL, 5); + + c++; + } + + wxBoxSizer* okCancelSizer = new wxBoxSizer(wxHORIZONTAL); + root->Add(okCancelSizer, 1, wxEXPAND, 5); + + okCancelSizer->Add(0, 0, 1, wxEXPAND, 5); + okCancelSizer->Add(new wxButton(&dialog, wxID_OK), 0, wxALL, 5); + okCancelSizer->Add(new wxButton(&dialog, wxID_CANCEL), 0, wxALL, 5); + + dialog.Fit(); + dialog.OnInit(); + dialog.ShowModal(); + dialog.Destroy(); +} diff --git a/src/wx-createdisc.h b/src/wx-createdisc.h new file mode 100644 index 0000000..dae4c1b --- /dev/null +++ b/src/wx-createdisc.h @@ -0,0 +1,8 @@ +#ifndef SRC_WX_CREATEDISC_H_ +#define SRC_WX_CREATEDISC_H_ + +extern "C" { +void creatediscimage_open(void *hwnd); +} + +#endif /* SRC_WX_CREATEDISC_H_ */ diff --git a/src/wx-deviceconfig.cc b/src/wx-deviceconfig.cc new file mode 100644 index 0000000..310b6eb --- /dev/null +++ b/src/wx-deviceconfig.cc @@ -0,0 +1,292 @@ +#include "wx-deviceconfig.h" + +#include "wx-utils.h" +#include "wx/wxprec.h" + +#include "wx-dialogbox.h" + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/xrc/xmlres.h" + +extern "C" +{ +#include "config.h" +#include "plat-midi.h" +void saveconfig(char*); +void resetpchard(); +int deviceconfig_dlgproc(void* hdlg, int message, INT_PARAM wParam, + LONG_PARAM lParam); +device_t *config_device; +int confirm(); +} +#define IDC_CONFIG_BASE 1000 + +int deviceconfig_dlgproc(void* hdlg, int message, INT_PARAM wParam, + LONG_PARAM lParam) +{ + switch (message) + { + case WX_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; + void* h = 0; + int val_int; + int num; + char s[100]; + + switch (config->type) + { + case CONFIG_BINARY: + h = wx_getdlgitem(hdlg, id); + val_int = config_get_int(CFG_MACHINE, config_device->name, config->name, config->default_int); + + wx_sendmessage(h, WX_BM_SETCHECK, val_int, 0); + + id++; + break; + + case CONFIG_SELECTION: + h = wx_getdlgitem(hdlg, id + 1); + val_int = config_get_int(CFG_MACHINE, config_device->name, config->name, config->default_int); + + c = 0; + while (selection->description[0]) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) selection->description); + if (val_int == selection->value) + wx_sendmessage(h, WX_CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + + case CONFIG_MIDI: + num = midi_get_num_devs(); + if (num > 0) + { + h = wx_getdlgitem(hdlg, id + 1); + val_int = config_get_int(CFG_MACHINE, NULL, config->name, config->default_int); + + for (c = 0; c < num; c++) + { + midi_get_dev_name(c, s); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM) s); + if (val_int == c) + wx_sendmessage(h, WX_CB_SETCURSEL, c, 0); + } + id += 2; + } + break; + } + config++; + } + } + return TRUE; + + case WX_COMMAND: + switch (wParam) + { + case wxID_OK: + { + 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; + void* h = 0; + int val_int; + + switch (config->type) + { + case CONFIG_BINARY: + h = wx_getdlgitem(hdlg, id); + val_int = config_get_int(CFG_MACHINE, config_device->name, config->name, config->default_int); + + if (val_int != wx_sendmessage(h, WX_BM_GETCHECK, 0, 0)) + changed = 1; + + id++; + break; + + case CONFIG_SELECTION: + h = wx_getdlgitem(hdlg, id + 1); + val_int = config_get_int(CFG_MACHINE, config_device->name, config->name, config->default_int); + + c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; + + case CONFIG_MIDI: + if (midi_get_num_devs() > 0) + { + h = wx_getdlgitem(hdlg, id + 1); + val_int = config_get_int(CFG_MACHINE, NULL, config->name, config->default_int); + + c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + if (val_int != c) + changed = 1; + id += 2; + } + break; + } + config++; + } + + if (!changed) + { + wx_enddialog(hdlg, 0); + return TRUE; + } + + if (has_been_inited && !confirm()) + { + wx_enddialog(hdlg, 0); + return TRUE; + } + + id = IDC_CONFIG_BASE; + config = config_device->config; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + void* h = 0; + + switch (config->type) + { + case CONFIG_BINARY: + h = wx_getdlgitem(hdlg, id); + config_set_int(CFG_MACHINE, config_device->name, config->name, wx_sendmessage(h, WX_BM_GETCHECK, 0, 0)); + + id++; + break; + + case CONFIG_SELECTION: + h = wx_getdlgitem(hdlg, id + 1); + c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_int(CFG_MACHINE, config_device->name, config->name, selection->value); + + id += 2; + break; + + case CONFIG_MIDI: + if (midi_get_num_devs() > 0) + { + h = wx_getdlgitem(hdlg, id + 1); + c = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + config_set_int(CFG_MACHINE, NULL, config->name, c); + + id += 2; + } + break; + } + config++; + } + + if (has_been_inited) + { + saveconfig(NULL); + resetpchard(); + } + + wx_enddialog(hdlg, 0); + return TRUE; + } + case wxID_CANCEL: + wx_enddialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void deviceconfig_open(void* hwnd, device_t *device) +{ + char s[257]; + config_device = device; + + PCemDialogBox dialog((wxWindow*) hwnd, deviceconfig_dlgproc); +// dialog.SetWindowStyle(wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + + device_config_t *config = device->config; + + dialog.SetTitle("Device Configuration"); + + wxFlexGridSizer* root = new wxFlexGridSizer(0, 1, 0, 0); + root->SetFlexibleDirection(wxBOTH); + root->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + dialog.SetSizer(root); + + wxFlexGridSizer* sizer = new wxFlexGridSizer(0, 2, 0, 0); + sizer->SetFlexibleDirection(wxBOTH); + sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + sizer->AddGrowableCol(1); + root->Add(sizer, 1, wxEXPAND, 5); + + int id = IDC_CONFIG_BASE; + + while (config->type != -1) + { + switch (config->type) + { + case CONFIG_BINARY: + sizer->Add(0, 0, 1, wxEXPAND, 5); + sizer->Add(new wxCheckBox(&dialog, id++, config->description), 0, wxALL, 5); + break; + + case CONFIG_SELECTION: + case CONFIG_MIDI: + { + if (config->type == CONFIG_MIDI && midi_get_num_devs() == 0) + break; + sprintf(s, "%s:", config->description); + sizer->Add(new wxStaticText(&dialog, id++, s), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(comboSizer, 1, wxEXPAND, 5); + wxComboBox* cb = new wxComboBox(&dialog, id++); + cb->SetEditable(false); + comboSizer->Add(cb, 1, wxALL, 5); + break; + } + } + + config++; + } + + wxBoxSizer* okCancelSizer = new wxBoxSizer(wxHORIZONTAL); + root->Add(okCancelSizer, 1, wxEXPAND, 5); + + okCancelSizer->Add(0, 0, 1, wxEXPAND, 5); + okCancelSizer->Add(new wxButton(&dialog, wxID_OK), 0, wxALL, 5); + okCancelSizer->Add(new wxButton(&dialog, wxID_CANCEL), 0, wxALL, 5); + + dialog.Fit(); + dialog.OnInit(); + dialog.ShowModal(); + dialog.Destroy(); +} diff --git a/src/wx-deviceconfig.h b/src/wx-deviceconfig.h new file mode 100644 index 0000000..5a591df --- /dev/null +++ b/src/wx-deviceconfig.h @@ -0,0 +1,10 @@ +#ifndef SRC_WX_DEVICECONFIG_H_ +#define SRC_WX_DEVICECONFIG_H_ + +extern "C" { +#include +#include "device.h" +void deviceconfig_open(void* hwnd, device_t *device); +} + +#endif /* SRC_WX_DEVICECONFIG_H_ */ diff --git a/src/wx-dialogbox.cc b/src/wx-dialogbox.cc new file mode 100644 index 0000000..50d3c6b --- /dev/null +++ b/src/wx-dialogbox.cc @@ -0,0 +1,84 @@ +#include + +#ifndef WX_PRECOMP +#include +#endif + +#include +#include + +#include "wx-dialogbox.h" +#include "wx-utils.h" + +BEGIN_EVENT_TABLE(PCemDialogBox, wxDialog) END_EVENT_TABLE() + +class CommandValue: public wxObject +{ +public: + CommandValue(int value) { this->value = value; } + int GetValue() { return this->value; } +private: + int value; +}; + +PCemDialogBox::PCemDialogBox(wxWindow* parent, int (*callback)(void* window, int message, INT_PARAM param1, LONG_PARAM param2)) : + wxDialog(parent, -1, "No title") +{ + this->callback = callback; + this->commandActive = false; +} + +PCemDialogBox::PCemDialogBox(wxWindow* parent, const char* name, int (*callback)(void* window, int message, INT_PARAM param1, LONG_PARAM param2)) +{ + wxXmlResource::Get()->LoadDialog(this, parent, name); + this->callback = callback; + this->commandActive = false; +} + +void PCemDialogBox::OnInit() +{ + if (callback) + { + callback(this, WX_INITDIALOG, 0, 0); + Bind(wxEVT_BUTTON, &PCemDialogBox::OnCommand, this); + Bind(wxEVT_RADIOBUTTON, &PCemDialogBox::OnCommand, this); + Bind(wxEVT_TEXT, &PCemDialogBox::OnCommand, this); + Bind(wxEVT_COMBOBOX, &PCemDialogBox::OnCommand, this); + Bind(wxEVT_NOTEBOOK_PAGE_CHANGED, &PCemDialogBox::OnNotebookChanged, this); + Bind(wxEVT_LISTBOX_DCLICK, &PCemDialogBox::OnCommand, this, wxID_ANY, wxID_ANY, new CommandValue(WX_LBN_DBLCLK)); + } + + wxWindow* root = FindWindow(XRCID("ROOT_PANEL")); + if (root) + root->Fit(); + Fit(); +} + +int PCemDialogBox::processEvent(int message, INT_PARAM param1, LONG_PARAM param2) +{ + int result = 0; + /* lock the current command to prevent strange behavior */ + if (!commandActive) + { + commandActive = true; + result = callback(this, message, param1, param2); + commandActive = false; + } + return result; +} + +void PCemDialogBox::OnNotebookChanged(wxCommandEvent& event) +{ + wxBookCtrlEvent* ev = (wxBookCtrlEvent*)&event; + processEvent(WX_COMMAND, ev->GetId(), ev->GetSelection()); +} + +void PCemDialogBox::OnCommand(wxCommandEvent& event) +{ + LONG_PARAM val = 0; + CommandValue* c = (CommandValue*)event.GetEventUserData(); + if (c) + val = c->GetValue(); + processEvent(WX_COMMAND, event.GetId(), val); +} + diff --git a/src/wx-dialogbox.h b/src/wx-dialogbox.h new file mode 100644 index 0000000..af8ed2d --- /dev/null +++ b/src/wx-dialogbox.h @@ -0,0 +1,24 @@ +#ifndef SRC_WX_PCEMDIALOGBOX_H_ +#define SRC_WX_PCEMDIALOGBOX_H_ + +#include "wx/dialog.h" + +#include "wx-utils.h" + +class PCemDialogBox: public wxDialog { +public: + PCemDialogBox(wxWindow* parent, int(*callback)(void* window, int message, INT_PARAM param1, LONG_PARAM param2)); + PCemDialogBox(wxWindow* parent, const char* name, int(*callback)(void* window, int message, INT_PARAM param1, LONG_PARAM param2)); + virtual ~PCemDialogBox() {} + void OnInit(); +private: + void OnNotebookChanged(wxCommandEvent& event); + void OnCommand(wxCommandEvent& event); + int processEvent(int message, INT_PARAM param1, LONG_PARAM param2); + int(*callback)(void* window, int message, INT_PARAM param1, LONG_PARAM param2); + bool commandActive; + + DECLARE_EVENT_TABLE() +}; + +#endif /* SRC_WX_PCEMDIALOGBOX_H_ */ diff --git a/src/wx-display.h b/src/wx-display.h new file mode 100644 index 0000000..09f6315 --- /dev/null +++ b/src/wx-display.h @@ -0,0 +1,38 @@ +#ifndef SRC_WX_DISPLAY_H_ +#define SRC_WX_DISPLAY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +int display_init(); +void display_close(); +void display_start(void* hwnd); +void display_stop(); +void display_resize(int width, int height); + +#ifdef __cplusplus +} +#endif + +extern int mousecapture; + +extern int video_scale_mode; +extern int video_vsync; +extern int video_focus_dim; +extern int video_fullscreen_mode; +extern int video_alternative_update_lock; + +extern int win_doresize; + +extern int window_doreset; +extern int window_dosetresize; +extern int renderer_doreset; +extern int window_dofullscreen; +extern int window_dowindowed; +extern int window_doremember; +extern int window_doinputgrab; +extern int window_doinputrelease; +extern int window_dotogglefullscreen; + +#endif /* SRC_WX_DISPLAY_H_ */ diff --git a/src/wx-glsl.h b/src/wx-glsl.h new file mode 100644 index 0000000..0f8f853 --- /dev/null +++ b/src/wx-glsl.h @@ -0,0 +1,158 @@ +#ifndef SRC_WX_GLSL_H_ +#define SRC_WX_GLSL_H_ + +#define MAX_PREV 7 + +#define MAX_SHADERS 20 +#define MAX_TEXTURES 20 +#define MAX_PARAMETERS 100 + +#define MAX_USER_SHADERS 20 +//#define SDL2_SHADER_DEBUG + +struct shader_scale { + int mode[2]; + float value[2]; +}; + +struct shader_state { + float input_size[2]; + float input_texture_size[2]; + float output_texture_size[2]; + float output_size[2]; + float tex_coords[8]; +}; + +struct shader_vbo { + int vertex_coord; + int tex_coord; + int color; +}; + +struct shader_texture { + int id; + int width; + int height; + int type; + int internal_format; + int format; + int min_filter; + int mag_filter; + int wrap_mode; + void* data; + int mipmap; +}; + +struct shader_lut_texture { + char name[50]; + struct shader_texture texture; +}; + +struct shader_fbo { + int id; + struct shader_texture texture; + int srgb; + int mipmap_input; +}; + +struct shader_prev { + struct shader_fbo fbo; + struct shader_vbo vbo; +}; + +struct shader_input { + int texture; + int input_size; + int texture_size; + int tex_coord; +}; + +struct shader_uniforms { + int mvp_matrix; + int vertex_coord; + int tex_coord; + int color; + + int texture; + int input_size; + int texture_size; + int output_size; + + int frame_count; + int frame_direction; + + struct shader_input orig; + struct shader_input pass[MAX_SHADERS]; + struct shader_input prev_pass[MAX_SHADERS]; + struct shader_input prev[MAX_PREV]; + + int parameters[MAX_PARAMETERS]; + int lut_textures[MAX_TEXTURES]; +}; + +struct shader_program { + int vertex_shader; + int fragment_shader; + int id; +}; + +struct shader_parameter { + char id[64]; + char description[64]; + float default_value; + float value; + float min; + float max; + float step; +}; + +struct shader_pass { + int active; + char alias[64]; + int vertex_array; + int frame_count_mod; + struct shader_program program; + struct shader_uniforms uniforms; + struct shader_fbo fbo; + struct shader_vbo vbo; + struct shader_state state; + struct shader_scale scale; +}; + +struct glsl_shader { + int active; + char name[64]; + + int num_passes; + struct shader_pass passes[MAX_SHADERS]; + + int num_lut_textures; + struct shader_lut_texture lut_textures[MAX_TEXTURES]; + + int num_parameters; + struct shader_parameter parameters[MAX_PARAMETERS]; + + struct shader_pass prev_scene; + struct shader_prev prev[MAX_PREV+1]; + + int last_prev_update; + int has_prev; + + float shader_refresh_rate; + + int input_filter_linear; +}; + +typedef struct glsl_t { + int num_shaders; + struct glsl_shader shaders[MAX_USER_SHADERS]; + struct shader_pass scene; + struct shader_pass final_pass; + struct shader_pass fs_color; +#ifdef SDL2_SHADER_DEBUG + struct shader_pass debug; +#endif + int srgb; +} glsl_t; + +#endif diff --git a/src/wx-glslp-parser.c b/src/wx-glslp-parser.c new file mode 100644 index 0000000..387918a --- /dev/null +++ b/src/wx-glslp-parser.c @@ -0,0 +1,330 @@ +#include "wx-glslp-parser.h" + +#include +#include +#include +#include +#include "wx-utils.h" + +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + +extern char* get_filename(char*); +extern void pclog(const char *format, ...); + +static int endswith(const char* str, const char* ext) +{ + int i; + const char* p; + int elen = strlen(ext); + int slen = strlen(str); + if (slen >= elen) + { + p = &str[slen-elen]; + for (i = 0; i < elen; ++i) + { + if (tolower(p[i]) != tolower(ext[i])) + return 0; + } + return 1; + } + return 0; +} + +static char* load_file(const char* fn) +{ + FILE* f = fopen(fn, "rb"); + if (!f) + return 0; + fseek(f, 0, SEEK_END); + long fsize = ftell(f); + fseek(f, 0, SEEK_SET); + + char* data = malloc(fsize+1); + + fread(data, fsize, 1, f); + fclose(f); + + data[fsize] = 0; + + return data; +} + +static void strip_lines(const char* program, const char* starts_with) +{ + /* strip parameters */ + char* ptr = strstr(program, starts_with); + while (ptr) + { + while (*ptr != '\n' && *ptr != '\0') + *ptr++ = ' '; + ptr = strstr(program, starts_with); + } +} + +static void strip_parameters(const char* program) +{ + /* strip parameters */ + strip_lines(program, "#pragma parameter"); +} + +static void strip_defines(const char* program) +{ + /* strip texture define */ + strip_lines(program, "#define texture"); +} + +static int has_parameter(glslp_t* glsl, char* id) +{ + int i; + for (i = 0; i < glsl->num_parameters; ++i) + if (!strcmp(glsl->parameters[i].id, id)) + return 1; + return 0; +} + +static int get_parameters(glslp_t* glsl) +{ + int i; + struct parameter p; + for (i = 0; i < glsl->num_shaders; ++i) + { + struct shader* shader = &glsl->shaders[i]; + FILE* f = fopen(shader->shader_fn, "rb"); + if (!f) + return 0; + + char line[1024]; + while (fgets(line, sizeof(line)-1, f) && glsl->num_parameters < MAX_PARAMETERS) + { + int num = sscanf(line, "#pragma parameter %63s \"%63[^\"]\" %f %f %f %f", p.id, p.description, &p.default_value, &p.min, &p.max, &p.step); + if (num < 5) + continue; + p.id[63] = 0; + p.description[63] = 0; + + if (num == 5) + p.step = 0.1f * (p.max-p.min); + + p.value = p.default_value; + + if (!has_parameter(glsl, p.id)) + { + memcpy(&glsl->parameters[glsl->num_parameters++], &p, sizeof(struct parameter)); + pclog("Read parameter: %s (%s) %f, %f -> %f (%f)\n", p.id, p.description, p.default_value, p.min, p.max, p.step); + } + } + + fclose(f); + } + + return 1; +} + +static struct parameter* get_parameter(glslp_t* glslp, const char* id) +{ + int i; + for (i = 0; i < glslp->num_parameters; ++i) + { + if (!strcmp(glslp->parameters[i].id, id)) { + return &glslp->parameters[i]; + } + } + return 0; +} + +static glslp_t* glsl_parse(const char* f) +{ + glslp_t* glslp = malloc(sizeof(glslp_t)); + memset(glslp, 0, sizeof(glslp_t)); + glslp->num_shaders = 1; + struct shader* shader = &glslp->shaders[0]; + strcpy(shader->shader_fn, f); + shader->shader_program = load_file(f); + if (!shader->shader_program) + { + wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); + glslp_free(glslp); + return 0; + } + strip_parameters(shader->shader_program); + strip_defines(shader->shader_program); + shader->scale_x = shader->scale_y = 1.0f; + strcpy(shader->scale_type_x, "source"); + strcpy(shader->scale_type_y, "source"); + get_parameters(glslp); + return glslp; +} + +void get_glslp_name(const char* f, char* s, int size) +{ + safe_strncpy(s, get_filename((char*)f), size); +} + +glslp_t* glslp_parse(const char* f) +{ + int i, j, len, sublen; + char s[512], t[512], z[540]; + + memset(s, 0, sizeof(s)); + if (endswith(f, ".glsl")) + return glsl_parse(f); + + void* cfg = wx_config_load(f); + + if (!cfg) + { + wx_simple_messagebox("GLSLP error", "Could not load GLSLP-file %s\n", f); + return 0; + } + + glslp_t* glslp = malloc(sizeof(glslp_t)); + memset(glslp, 0, sizeof(glslp_t)); + + get_glslp_name(f, glslp->name, sizeof(glslp->name)); + + wx_config_get_int(cfg, "shaders", &glslp->num_shaders, 0); + + wx_config_get_bool(cfg, "filter_linear0", &glslp->input_filter_linear, -1); + + for (i = 0; i < glslp->num_shaders; ++i) + { + struct shader* shader = &glslp->shaders[i]; + + + snprintf(s, sizeof(s)-1, "shader%d", i); + if (!wx_config_get_string(cfg, s, t, sizeof(t), 0)) + { + /* shader doesn't exist, lets break here */ + glslp->num_shaders = i; + break; + } + strcpy(s, f); + *get_filename(s) = 0; + snprintf(shader->shader_fn, sizeof(shader->shader_fn)-1, "%s%s", s, t); + shader->shader_program = load_file(shader->shader_fn); + if (!shader->shader_program) + { + wx_simple_messagebox("GLSL error", "Could not load shader %s\n", shader->shader_fn); + glslp_free(glslp); + return 0; + } + strip_parameters(shader->shader_program); + strip_defines(shader->shader_program); + + snprintf(s, sizeof(s)-1, "alias%d", i); + wx_config_get_string(cfg, s, shader->alias, sizeof(shader->alias), 0); + + snprintf(s, sizeof(s)-1, "filter_linear%d", i+1); + wx_config_get_bool(cfg, s, &shader->filter_linear, 0); + + snprintf(s, sizeof(s)-1, "wrap_mode%d", i); + wx_config_get_string(cfg, s, shader->wrap_mode, sizeof(shader->wrap_mode), 0); + + snprintf(s, sizeof(s)-1, "float_framebuffer%d", i); + wx_config_get_bool(cfg, s, &shader->float_framebuffer, 0); + snprintf(s, sizeof(s)-1, "srgb_framebuffer%d", i); + wx_config_get_bool(cfg, s, &shader->srgb_framebuffer, 0); + + snprintf(s, sizeof(s)-1, "mipmap_input%d", i); + wx_config_get_bool(cfg, s, &shader->mipmap_input, 0); + + strcpy(shader->scale_type_x, "source"); + snprintf(s, sizeof(s)-1, "scale_type_x%d", i); + wx_config_get_string(cfg, s, shader->scale_type_x, sizeof(shader->scale_type_x), 0); + strcpy(shader->scale_type_y, "source"); + snprintf(s, sizeof(s)-1, "scale_type_y%d", i); + wx_config_get_string(cfg, s, shader->scale_type_y, sizeof(shader->scale_type_y), 0); + snprintf(s, sizeof(s)-1, "scale_type%d", i); + if (wx_config_has_entry(cfg, s)) + { + wx_config_get_string(cfg, s, shader->scale_type_x, sizeof(shader->scale_type_x), 0); + wx_config_get_string(cfg, s, shader->scale_type_y, sizeof(shader->scale_type_y), 0); + } + + snprintf(s, sizeof(s)-1, "scale_x%d", i); + wx_config_get_float(cfg, s, &shader->scale_x, 1.0f); + snprintf(s, sizeof(s)-1, "scale_y%d", i); + wx_config_get_float(cfg, s, &shader->scale_y, 1.0f); + snprintf(s, sizeof(s)-1, "scale%d", i); + if (wx_config_has_entry(cfg, s)) + { + wx_config_get_float(cfg, s, &shader->scale_x, 1.0f); + wx_config_get_float(cfg, s, &shader->scale_y, 1.0f); + } + + snprintf(s, sizeof(s)-1, "frame_count_mod%d", i); + wx_config_get_int(cfg, s, &shader->frame_count_mod, 0); + } + + /* textures */ + glslp->num_textures = 0; + wx_config_get_string(cfg, "textures", t, sizeof(t), 0); + + len = strlen(t); + j = 0; + sublen = 0; + for (i = 0; i < len; ++i) + { + if (t[i] == ';' || i == len-1) + { + sublen = (i-j) + ((i == len-1) ? 1 : 0) + 1; + safe_strncpy(s, t+j, sublen); + s[511 < sublen ? 511 : sublen] = 0; + + struct texture* tex = &glslp->textures[glslp->num_textures++]; + + strcpy(tex->name, s); + wx_config_get_string(cfg, s, tex->path, sizeof(tex->path), 0); + + snprintf(z, sizeof(z)-1, "%s_linear", s); + wx_config_get_bool(cfg, z, &tex->linear, 0); + + snprintf(z, sizeof(z)-1, "%s_mipmap", s); + wx_config_get_bool(cfg, z, &tex->mipmap, 0); + + snprintf(z, sizeof(z)-1, "%s_wrap_mode", s); + wx_config_get_string(cfg, z, tex->wrap_mode, sizeof(tex->wrap_mode), 0); + + j = i+1; + } + } + + /* parameters */ + get_parameters(glslp); + + wx_config_get_string(cfg, "parameters", t, sizeof(t), 0); + + len = strlen(t); + j = 0; + sublen = 0; + for (i = 0; i < len; ++i) + { + if (t[i] == ';' || i == len-1) + { + sublen = (i-j) + ((i == len-1) ? 1 : 0) + 1; + safe_strncpy(s, t+j, sublen); + s[511 < sublen ? 511 : sublen] = 0; + + struct parameter* p = get_parameter(glslp, s); + + if (p) + wx_config_get_float(cfg, s, &p->default_value, 0); + + j = i+1; + } + } + + wx_config_free(cfg); + + + return glslp; +} + +void glslp_free(glslp_t* p) +{ + int i; + for (i = 0; i < p->num_shaders; ++i) + if (p->shaders[i].shader_program) + free(p->shaders[i].shader_program); + free(p); +} diff --git a/src/wx-glslp-parser.h b/src/wx-glslp-parser.h new file mode 100644 index 0000000..970eb35 --- /dev/null +++ b/src/wx-glslp-parser.h @@ -0,0 +1,56 @@ +#ifndef SRC_WX_GLSLP_PARSER_H_ +#define SRC_WX_GLSLP_PARSER_H_ + +#include "wx-glsl.h" + +struct parameter { + char id[64]; + char description[64]; + float default_value; + float value; + float min; + float max; + float step; +}; + +struct texture { + char path[256]; + char name[50]; + int linear; + int mipmap; + char wrap_mode[50]; +}; + +struct shader { + char shader_fn[1024]; + char* shader_program; + char alias[64]; + int filter_linear; + int float_framebuffer; + int srgb_framebuffer; + int mipmap_input; + int frame_count_mod; + char wrap_mode[50]; + char scale_type_x[9], scale_type_y[9]; + float scale_x, scale_y; +}; + +typedef struct glslp_t { + char name[64]; + int num_shaders; + struct shader shaders[MAX_SHADERS]; + + int num_textures; + struct texture textures[MAX_TEXTURES]; + + int num_parameters; + struct parameter parameters[MAX_PARAMETERS]; + + int input_filter_linear; +} glslp_t; + +void get_glslp_name(const char* f, char* s, int size); +glslp_t* glslp_parse(const char* f); +void glslp_free(glslp_t* p); + +#endif /* SRC_WX_GLSLP_PARSER_H_ */ diff --git a/src/wx-hostconfig.c b/src/wx-hostconfig.c new file mode 100644 index 0000000..9dff296 --- /dev/null +++ b/src/wx-hostconfig.c @@ -0,0 +1,244 @@ +#ifdef _WIN32 +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include +#endif + +#include "wx-utils.h" +#include "wx-sdl2.h" +#include "wx-hostconfig.h" + +#include "ibm.h" +#include "config.h" +#include "nethandler.h" + +#ifdef _WIN32 +static HINSTANCE net_hLib = 0; +static char *net_lib_name = "wpcap.dll"; +static pcap_if_t *alldevs; +static char *dev_name[20]; + +int (*_pcap_findalldevs)(pcap_if_t **, char *); +void (*_pcap_freealldevs)(pcap_if_t *); +pcap_t *(*_pcap_open_live)(const char *, int, int, int, char *); +int (*_pcap_datalink)(pcap_t *); +void (*_pcap_close)(pcap_t *); +#endif + +#define ETH_DEV_NAME_MAX 256 /* maximum device name size */ +#define ETH_DEV_DESC_MAX 256 /* maximum device description size */ +#define ETH_MAX_DEVICE 30 /* maximum ethernet devices */ +#define ETH_PROMISC 1 /* promiscuous mode = true */ +#define ETH_MAX_PACKET 1514 /* maximum ethernet packet size */ +#define PCAP_READ_TIMEOUT -1 + +#ifdef _WIN32 +static int get_network_name(char *dev_name, char *regval) +{ + if (dev_name[strlen( "\\Device\\NPF_" )] == '{') + { + char regkey[2048]; + HKEY reghnd; + + sprintf(regkey, "SYSTEM\\CurrentControlSet\\Control\\Network\\" + "{4D36E972-E325-11CE-BFC1-08002BE10318}\\%s\\Connection", dev_name+ + strlen("\\Device\\NPF_")); + + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, regkey, 0, KEY_QUERY_VALUE, ®hnd) == ERROR_SUCCESS) + { + DWORD reglen = 2048; + DWORD regtype; + + if (RegQueryValueExA(reghnd, "Name", NULL, ®type, (LPBYTE)regval, ®len) == ERROR_SUCCESS) + { + RegCloseKey (reghnd); + + if ((regtype != REG_SZ) || (reglen > 2048)) + return -1; + + /*Name now in regval*/ + return 0; + } + RegCloseKey (reghnd); + } + } + return -1; +} +#endif +int hostconfig_dialog_proc(void *hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + void *h; +#ifdef _WIN32 + pcap_if_t *dev; + char errbuf[PCAP_ERRBUF_SIZE]; +#endif + + switch (message) + { + case WX_INITDIALOG: + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_TYPE")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"SLiRP"); + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE")); + wx_sendmessage(h, WX_CB_SETCURSEL, 0, 0); + wx_enablewindow(h, FALSE); +#ifdef _WIN32 + net_hLib = LoadLibraryA(net_lib_name); + + if (net_hLib) + { + int c = 0; + int match = 0; + + _pcap_findalldevs = (void *)GetProcAddress(net_hLib, "pcap_findalldevs"); + _pcap_freealldevs = (void *)GetProcAddress(net_hLib, "pcap_freealldevs"); + _pcap_open_live = (void *)GetProcAddress(net_hLib, "pcap_open_live"); + _pcap_datalink = (void *)GetProcAddress(net_hLib, "pcap_datalink"); + _pcap_close = (void *)GetProcAddress(net_hLib, "pcap_close"); + + if (_pcap_findalldevs(&alldevs, errbuf) != -1) + { + char *pcap_device = config_get_string(CFG_GLOBAL, NULL, "pcap_device", "nothing"); + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE")); + + for (dev = alldevs; dev; dev = dev->next) + { + pcap_t *conn = _pcap_open_live(dev->name, ETH_MAX_PACKET, ETH_PROMISC, PCAP_READ_TIMEOUT, errbuf); + int datalink = 0; + + if (conn) + { + datalink = _pcap_datalink(conn); + _pcap_close(conn); + } + + if (conn && datalink == DLT_EN10MB) + { + char desc[2048]; + char s[2048]; + + if ((dev->flags & PCAP_IF_LOOPBACK) || (!strcmp("any", dev->name))) + continue; + + if (pcap_device) + { + if (!strcmp(pcap_device, dev->name)) + match = c; + } + + dev_name[c++] = dev->name; + if (get_network_name(dev->name, desc)) + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)dev->name); + else + { + sprintf(s, "%s - %s", dev->name, desc); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + } + } + } + } + if (c) + { + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_TYPE")); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)"PCAP"); + + if (config_get_int(CFG_GLOBAL, NULL, "net_type", NET_SLIRP) == NET_PCAP) + { + wx_sendmessage(h, WX_CB_SETCURSEL, 1, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE")); + wx_sendmessage(h, WX_CB_SETCURSEL, match, 0); + wx_enablewindow(h, TRUE); + } + } + } +#endif + return TRUE; + + case WX_COMMAND: + if (wParam == wxID_OK) + { + int type; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_TYPE")); + type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); +#ifdef _WIN32 + if (type) /*PCAP*/ + { + int dev; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE")); + dev = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + config_set_int(CFG_GLOBAL, NULL, "net_type", NET_PCAP); + config_set_string(CFG_GLOBAL, NULL, "pcap_device", dev_name[dev]); + } + else /*SLiRP*/ + { +#endif + config_set_int(CFG_GLOBAL, NULL, "net_type", NET_SLIRP); + config_set_string(CFG_GLOBAL, NULL, "pcap_device", "nothing"); +#ifdef _WIN32 + } +#endif + saveconfig_global_only(); + + wx_enddialog(hdlg, 1); +#ifdef _WIN32 + if (net_hLib) + { + _pcap_freealldevs(alldevs); + _pcap_findalldevs = NULL; + _pcap_freealldevs = NULL; + _pcap_open_live = NULL; + _pcap_datalink = NULL; + _pcap_close = NULL; + FreeLibrary(net_hLib); + } +#endif + return TRUE; + } + else if (wParam == wxID_CANCEL) + { + wx_enddialog(hdlg, 0); +#ifdef _WIN32 + if (net_hLib) + { + _pcap_freealldevs(alldevs); + _pcap_findalldevs = NULL; + _pcap_freealldevs = NULL; + _pcap_open_live = NULL; + _pcap_datalink = NULL; + _pcap_close = NULL; + FreeLibrary(net_hLib); + } +#endif + return TRUE; + } + else if (ID_IS("IDC_COMBO_NETWORK_TYPE")) + { + int type; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_TYPE")); + type = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + h = wx_getdlgitem(hdlg, WX_ID("IDC_COMBO_NETWORK_DEVICE")); + if (!type) + wx_enablewindow(h, FALSE); + else + wx_enablewindow(h, TRUE); + + return TRUE; + } + break; + } + + return TRUE; +} + +int hostconfig_open(void *hwnd) +{ + return wx_dialogbox(hwnd, "HostConfig", hostconfig_dialog_proc); +} diff --git a/src/wx-hostconfig.h b/src/wx-hostconfig.h new file mode 100644 index 0000000..eeb03cd --- /dev/null +++ b/src/wx-hostconfig.h @@ -0,0 +1 @@ +int hostconfig_open(void *hwnd); diff --git a/src/wx-joystickconfig.cc b/src/wx-joystickconfig.cc new file mode 100644 index 0000000..2c00c65 --- /dev/null +++ b/src/wx-joystickconfig.cc @@ -0,0 +1,358 @@ +#include "wx-joystickconfig.h" + +#include "wx-utils.h" +#include "wx/wxprec.h" + +#include "wx-dialogbox.h" + +#ifndef WX_PRECOMP +#include "wx/wx.h" +#endif + +#include "wx/xrc/xmlres.h" + +extern "C" { +void pclog(const char *format, ...); +#include "config.h" +#include "device.h" +#include "gameport.h" +#include "plat-joystick.h" +} + +#define IDC_CONFIG_BASE 1000 + +static int joystick_nr; +static int joystick_config_type; +#define AXIS_STRINGS_MAX 3 +static char axis_strings[AXIS_STRINGS_MAX][10] = {"X Axis", "Y Axis", "Z Axis"}; + +static void rebuild_axis_button_selections(void *hdlg) +{ + int id = IDC_CONFIG_BASE + 3; + void *h; + int joystick; + int c, d; + + h = wx_getdlgitem(hdlg, IDC_CONFIG_BASE+1); + joystick = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int sel = c; + + h = wx_getdlgitem(hdlg, id); + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)plat_joystick_state[joystick-1].axis[d].name); + if (c < AXIS_STRINGS_MAX) + { + if (!strcasecmp(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); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + } + wx_sendmessage(h, WX_CB_SETCURSEL, sel, 0); + wx_enablewindow(h, TRUE); + } + else + wx_enablewindow(h, FALSE); + + id += 2; + } + + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = wx_getdlgitem(hdlg, id); + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_buttons; d++) + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)plat_joystick_state[joystick-1].button[d].name); + wx_sendmessage(h, WX_CB_SETCURSEL, c, 0); + wx_enablewindow(h, TRUE); + } + else + wx_enablewindow(h, FALSE); + + id += 2; + } + + for (c = 0; c < joystick_get_pov_count(joystick_config_type)*2; c++) + { + int sel = c; + + h = wx_getdlgitem(hdlg, id); + wx_sendmessage(h, WX_CB_RESETCONTENT, 0, 0); + + if (joystick) + { + 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); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)s); + } + for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++) + { + wx_sendmessage(h, WX_CB_ADDSTRING, 0, (LONG_PARAM)plat_joystick_state[joystick-1].axis[d].name); + } + wx_sendmessage(h, WX_CB_SETCURSEL, sel, 0); + wx_enablewindow(h, TRUE); + } + else + wx_enablewindow(h, FALSE); + + id += 2; + } + +} + +static int get_axis(void *hdlg, int id) +{ + void *h = wx_getdlgitem(hdlg, id); + int axis_sel = wx_sendmessage(h, WX_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 int get_pov(void *hdlg, int id) +{ + void *h = wx_getdlgitem(hdlg, id); + int axis_sel = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_povs*2; + + if (axis_sel < nr_povs) + { + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); + } + + return axis_sel - nr_povs; +} + +static int joystickconfig_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + switch (message) + { + case WX_INITDIALOG: + { +// rebuild_axis_button_selections(hdlg); + + void *h = wx_getdlgitem(hdlg, IDC_CONFIG_BASE+1); + int c; + int id = IDC_CONFIG_BASE + 3; + int joystick = joystick_state[joystick_nr].plat_joystick_nr; + + wx_sendmessage(h, WX_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; + int nr_povs = plat_joystick_state[joystick-1].nr_povs; + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int mapping = joystick_state[joystick_nr].axis_mapping[c]; + + h = wx_getdlgitem(hdlg, id); + if (mapping & POV_X) + wx_sendmessage(h, WX_CB_SETCURSEL, nr_axes + (mapping & 3)*2, 0); + else if (mapping & POV_Y) + wx_sendmessage(h, WX_CB_SETCURSEL, nr_axes + (mapping & 3)*2 + 1, 0); + else + wx_sendmessage(h, WX_CB_SETCURSEL, mapping, 0); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = wx_getdlgitem(hdlg, id); + wx_sendmessage(h, WX_CB_SETCURSEL, joystick_state[joystick_nr].button_mapping[c], 0); + id += 2; + } + for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++) + { + int mapping; + + h = wx_getdlgitem(hdlg, id); + mapping = joystick_state[joystick_nr].pov_mapping[c][0]; + if (mapping & POV_X) + wx_sendmessage(h, WX_CB_SETCURSEL, (mapping & 3)*2, 0); + else if (mapping & POV_Y) + wx_sendmessage(h, WX_CB_SETCURSEL, (mapping & 3)*2 + 1, 0); + else + wx_sendmessage(h, WX_CB_SETCURSEL, mapping + nr_povs*2, 0); + id += 2; + h = wx_getdlgitem(hdlg, id); + mapping = joystick_state[joystick_nr].pov_mapping[c][1]; + if (mapping & POV_X) + wx_sendmessage(h, WX_CB_SETCURSEL, (mapping & 3)*2, 0); + else if (mapping & POV_Y) + wx_sendmessage(h, WX_CB_SETCURSEL, (mapping & 3)*2 + 1, 0); + else + wx_sendmessage(h, WX_CB_SETCURSEL, mapping + nr_povs*2, 0); + id += 2; + } + } + } + return TRUE; + + case WX_COMMAND: + switch (wParam) + { + case IDC_CONFIG_BASE+1: +// if (HIWORD(wParam) == CBN_SELCHANGE) + rebuild_axis_button_selections(hdlg); + break; + + case wxID_OK: + { + void *h; + int c; + int id = IDC_CONFIG_BASE + 3; + + h = wx_getdlgitem(hdlg, IDC_CONFIG_BASE+1); + joystick_state[joystick_nr].plat_joystick_nr = wx_sendmessage(h, WX_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 = wx_getdlgitem(hdlg, id); + joystick_state[joystick_nr].button_mapping[c] = wx_sendmessage(h, WX_CB_GETCURSEL, 0, 0); + id += 2; + } + for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++) + { + h = wx_getdlgitem(hdlg, id); + joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(hdlg, id); + id += 2; + h = wx_getdlgitem(hdlg, id); + joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(hdlg, id); + id += 2; + } + } + } + case wxID_CANCEL: + wx_enddialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void joystickconfig_open(void *hwnd, int joy_nr, int type) +{ + char s[257]; + int c; + + PCemDialogBox dialog((wxWindow*) hwnd, joystickconfig_dlgproc); +// dialog.SetWindowStyle(wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + + joystick_nr = joy_nr; + joystick_config_type = type; + + dialog.SetTitle("Joystick Configuration"); + + wxFlexGridSizer* root = new wxFlexGridSizer(0, 1, 0, 0); + root->SetFlexibleDirection(wxBOTH); + root->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + dialog.SetSizer(root); + + wxFlexGridSizer* sizer = new wxFlexGridSizer(0, 2, 0, 0); + sizer->SetFlexibleDirection(wxBOTH); + sizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + sizer->AddGrowableCol(1); + root->Add(sizer, 1, wxEXPAND, 5); + + int id = IDC_CONFIG_BASE; + + + sizer->Add(new wxStaticText(&dialog, id++, "Device:"), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(comboSizer, 1, wxEXPAND, 5); + wxComboBox* cb = new wxComboBox(&dialog, id++); + cb->SetEditable(false); + comboSizer->Add(cb, 1, wxALL, 5); + + cb->Append("None"); + for (c = 0; c < joysticks_present; c++) + cb->Append(plat_joystick_state[c].name); + + for (c = 0; c < joystick_get_axis_count(type); c++) + { + sprintf(s, "Axis %i:", c); + sizer->Add(new wxStaticText(&dialog, id++, s), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(comboSizer, 1, wxEXPAND, 5); + wxComboBox* cb = new wxComboBox(&dialog, id++); + cb->SetEditable(false); + comboSizer->Add(cb, 1, wxALL, 5); + } + + for (c = 0; c < joystick_get_button_count(type); c++) + { + sprintf(s, "Button %i:", c); + sizer->Add(new wxStaticText(&dialog, id++, s), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(comboSizer, 1, wxEXPAND, 5); + wxComboBox* cb = new wxComboBox(&dialog, id++); + cb->SetEditable(false); + comboSizer->Add(cb, 1, wxALL, 5); + } + + for (c = 0; c < joystick_get_pov_count(type)*2; c++) + { + sprintf(s, "POV %i:", c); + sizer->Add(new wxStaticText(&dialog, id++, s), 0, wxALL | wxALIGN_CENTER_VERTICAL, 5); + wxBoxSizer* comboSizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(comboSizer, 1, wxEXPAND, 5); + wxComboBox* cb = new wxComboBox(&dialog, id++); + cb->SetEditable(false); + comboSizer->Add(cb, 1, wxALL, 5); + } + + wxBoxSizer* okCancelSizer = new wxBoxSizer(wxHORIZONTAL); + root->Add(okCancelSizer, 1, wxEXPAND, 5); + + okCancelSizer->Add(0, 0, 1, wxEXPAND, 5); + okCancelSizer->Add(new wxButton(&dialog, wxID_OK), 0, wxALL, 5); + okCancelSizer->Add(new wxButton(&dialog, wxID_CANCEL), 0, wxALL, 5); + + dialog.Fit(); + dialog.OnInit(); + dialog.ShowModal(); + dialog.Destroy(); +} diff --git a/src/wx-joystickconfig.h b/src/wx-joystickconfig.h new file mode 100644 index 0000000..32c9aad --- /dev/null +++ b/src/wx-joystickconfig.h @@ -0,0 +1,15 @@ +#ifndef SRC_WX_DEVICECONFIG_H_ +#define SRC_WX_DEVICECONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +void joystickconfig_open(void *hwnd, int joy_nr, int type); + +#ifdef __cplusplus +} +#endif + +#endif /* SRC_WX_DEVICECONFIG_H_ */ diff --git a/src/wx-main.cc b/src/wx-main.cc new file mode 100644 index 0000000..53a9371 --- /dev/null +++ b/src/wx-main.cc @@ -0,0 +1,18 @@ +#include "wx-app.h" +#include + +extern "C" +{ +int pc_main(int, char**); +} + +int main(int argc, char **argv) +{ + if (!pc_main(argc, argv)) + return -1; + + wxApp::SetInstance(new App()); + wxEntry(argc, argv); + return 0; +} + diff --git a/src/wx-resources.cpp b/src/wx-resources.cpp new file mode 100644 index 0000000..68deac3 --- /dev/null +++ b/src/wx-resources.cpp @@ -0,0 +1,8326 @@ +// +// This file was automatically generated by wxrc, do not edit by hand. +// + +#include + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include +#include +#include +#include + +#if wxCHECK_VERSION(2,8,5) && wxABI_VERSION >= 20805 + #define XRC_ADD_FILE(name, data, size, mime) \ + wxMemoryFSHandler::AddFileWithMimeType(name, data, size, mime) +#else + #define XRC_ADD_FILE(name, data, size, mime) \ + wxMemoryFSHandler::AddFile(name, data, size) +#endif + +static size_t xml_res_size_0 = 430; +static unsigned char xml_res_file_0[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0, +0,31,243,255,97,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0, +65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60, +0,0,1,80,73,68,65,84,120,218,196,147,177,75,195,64,20,198,191,75,2,77,82, +2,66,58,171,32,130,171,130,179,10,34,138,173,155,131,56,248,143,137,184, +9,145,186,168,40,34,104,103,65,119,233,160,117,236,210,160,29,210,187,228, +204,119,70,135,170,181,218,193,7,71,238,184,239,247,229,221,189,123,66, +107,141,81,194,194,136,225,236,238,237,35,77,51,88,150,224,90,151,74,165, +129,64,146,36,252,136,44,211,176,109,11,14,87,89,150,209,68,215,170,235, +120,120,108,13,52,152,156,24,199,241,201,169,22,194,18,52,176,8,247,164, +212,27,181,106,14,63,209,28,66,124,61,184,71,13,181,100,200,58,105,154, +70,59,219,91,144,74,97,102,122,106,184,131,231,102,100,14,162,195,200,81, +74,109,198,207,47,56,59,191,40,118,127,170,138,185,43,172,173,174,128,44, +51,64,210,75,224,249,30,150,151,22,115,94,23,26,209,7,234,55,239,252,239, +151,87,215,134,33,107,12,100,79,194,247,92,40,41,113,115,123,247,113,222, +126,3,190,153,249,185,89,163,37,99,12,148,74,205,196,117,61,116,226,24, +149,74,88,24,124,14,26,80,67,45,25,178,38,3,222,102,185,236,227,190,217, +252,22,126,143,118,187,141,48,12,139,210,231,6,156,216,142,131,32,8,204, +24,54,200,152,50,118,187,221,70,189,126,180,240,219,158,96,166,249,171, +108,48,95,22,127,236,143,173,208,17,255,222,141,175,2,12,0,1,60,177,155, +95,179,104,212,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_1 = 730; +static unsigned char xml_res_file_1[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0, +0,31,243,255,97,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0, +65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60, +0,0,2,124,73,68,65,84,120,218,140,83,77,72,85,65,24,61,115,239,220,247, +158,247,169,207,22,146,253,27,214,162,218,219,198,22,45,42,105,23,180,9, +139,8,162,104,227,182,34,37,242,137,216,162,149,127,139,22,134,36,182,80, +116,19,22,190,130,16,194,140,22,45,130,90,244,71,100,17,6,37,153,250,222, +157,59,157,111,238,141,90,132,116,185,115,103,238,204,57,223,249,190,51, +51,170,161,107,186,35,178,40,86,76,140,40,6,248,174,251,120,108,154,159, +192,247,160,21,58,81,127,109,218,62,91,180,118,246,83,100,255,247,17,172, +112,132,171,141,181,208,212,61,48,252,6,246,242,110,188,90,88,162,134,130, +229,215,198,49,136,135,231,121,238,159,19,216,179,181,206,97,159,159,107, +130,112,37,35,44,27,5,204,12,185,20,71,250,123,49,50,208,139,249,210,20, +158,148,38,81,21,102,113,171,175,7,79,31,76,113,110,50,169,99,102,48,225, +72,57,138,253,207,114,12,221,184,23,101,250,208,222,209,77,85,133,56,54, +46,19,202,162,253,74,55,98,167,102,177,90,49,14,43,28,225,122,138,185,253, +88,139,208,176,255,16,137,49,250,138,29,152,25,191,141,128,14,245,247,116, +226,225,228,29,148,38,70,145,241,225,230,173,53,196,30,118,28,225,106,73, +99,133,246,231,57,202,178,93,42,22,221,110,72,237,23,187,138,46,77,81,151, +224,199,78,158,66,46,0,242,126,194,113,37,72,150,107,252,41,4,10,247,222, +174,160,117,103,72,75,173,51,45,177,242,207,6,138,97,130,41,100,148,227, +8,87,75,149,101,30,132,2,229,175,207,125,199,213,217,111,88,51,169,106, +74,21,140,199,130,179,84,14,41,36,88,225,40,164,37,208,15,84,51,106,217, +120,56,219,164,208,214,188,233,47,101,155,54,133,209,249,207,24,251,96, +145,241,148,227,36,187,144,6,168,146,227,69,96,91,115,61,94,190,255,10, +95,7,78,186,82,137,16,27,227,220,150,181,137,143,139,196,38,1,84,122,50, +81,161,65,57,166,150,97,62,17,243,223,178,113,3,134,111,14,226,252,233, +19,216,198,113,192,5,173,53,162,85,67,140,114,88,225,224,119,9,177,245, +144,15,52,245,121,31,140,69,77,232,97,238,241,44,142,180,30,69,77,78,8, +190,108,139,91,11,57,206,7,158,227,184,0,98,142,246,125,212,133,1,116,133, +7,202,75,22,178,188,44,97,214,197,103,159,113,59,226,115,77,112,213,12, +32,28,199,141,190,188,27,186,113,23,23,162,216,98,169,108,112,166,118,23, +86,120,18,183,239,104,60,222,62,246,8,45,45,7,199,151,233,131,4,168,37, +113,224,254,107,212,242,84,81,25,194,21,31,196,242,205,255,184,185,47,210, +126,223,58,183,123,225,151,0,3,0,201,66,64,174,55,176,170,129,0,0,0,0,73, +69,78,68,174,66,96,130}; + +static size_t xml_res_size_2 = 835; +static unsigned char xml_res_file_2[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0, +0,31,243,255,97,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0, +65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60, +0,0,2,229,73,68,65,84,120,218,100,83,75,76,19,81,20,61,211,118,166,157, +150,22,176,5,1,229,35,82,36,4,99,162,6,18,34,113,39,46,80,227,70,73,220, +201,202,128,184,209,24,119,46,220,104,76,36,4,226,74,55,224,130,141,66, +130,49,16,73,52,98,68,148,40,66,212,128,168,20,249,10,165,244,199,48,191, +231,157,153,242,81,95,114,38,147,247,238,57,247,220,251,238,227,240,207, +106,125,250,185,93,211,217,69,198,224,98,169,61,14,144,236,54,238,225,149, +186,242,198,157,177,140,130,184,45,98,239,248,9,69,99,125,135,131,57,40, +47,244,35,224,230,16,213,128,12,59,16,223,96,24,15,173,96,240,203,2,156, +54,174,182,249,84,69,255,95,2,173,189,99,23,108,28,215,121,186,186,20,170, +192,99,62,1,232,58,224,225,1,55,161,212,107,186,192,106,82,197,163,23,19, +6,177,182,185,174,162,223,16,176,25,2,138,162,117,214,86,29,192,188,198, +99,54,14,184,104,55,91,36,184,128,28,151,69,150,146,26,212,152,142,186, +35,251,33,171,106,223,166,115,71,75,207,135,246,242,226,92,36,236,14,56, +40,107,186,19,200,243,0,94,199,118,173,242,134,142,233,80,18,203,97,25, +254,128,136,163,193,92,220,35,30,29,53,58,84,85,107,40,200,11,128,217,45, +187,89,148,89,36,7,207,70,102,176,16,78,162,40,224,67,85,73,54,92,110,59, +50,152,0,191,223,129,116,33,11,195,95,102,26,76,1,6,221,233,243,216,192, +147,79,183,205,34,15,140,45,226,253,143,136,28,93,158,123,242,43,154,119, +86,222,224,132,218,170,221,88,161,174,166,251,28,224,204,206,233,78,227, +107,211,53,134,108,250,13,8,36,144,178,253,157,172,38,86,23,30,220,189, +116,242,154,28,11,63,94,210,233,58,136,101,144,169,74,208,165,192,43,58, +173,30,48,166,195,158,170,53,186,166,192,151,230,192,62,143,7,82,240,96, +195,253,87,139,170,162,234,245,133,89,110,243,156,46,1,235,4,141,8,177, +68,194,18,224,160,203,73,73,21,164,4,195,236,92,18,62,47,143,234,50,47, +124,75,138,48,17,81,47,23,237,226,113,172,72,52,201,225,13,202,78,22,98, +113,29,6,207,20,136,173,46,117,191,30,157,61,151,197,103,66,82,85,240,162, +29,54,193,142,202,98,30,149,155,206,40,116,126,157,178,235,150,253,159, +211,11,136,134,127,119,167,166,20,5,119,186,6,167,143,151,150,33,63,207, +139,52,114,32,186,104,10,21,32,161,88,150,105,4,204,204,18,145,215,226, +10,38,135,223,226,106,125,77,33,13,82,200,24,164,208,167,55,207,155,6,167, +190,66,16,25,53,135,51,27,181,66,118,35,138,133,53,213,194,50,89,153,26, +121,135,209,161,129,38,131,103,150,96,124,58,91,110,118,128,212,101,89, +105,171,57,84,130,189,249,123,16,103,156,105,217,64,52,201,16,153,159,197, +106,232,27,62,14,189,108,234,48,226,183,31,218,214,242,17,130,55,218,186, +174,251,50,3,103,232,64,112,137,46,200,146,100,4,201,107,225,229,158,91, +77,231,111,83,204,164,209,150,255,94,227,142,85,64,240,27,51,178,99,207, +172,106,211,246,206,231,252,71,128,1,0,112,7,72,225,52,89,175,48,0,0,0, +0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_3 = 758; +static unsigned char xml_res_file_3[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,24,0,0,0,24,8,6,0,0, +0,224,119,61,248,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147, +0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,215,1,66,40,155,120,0,0,0,7,116, +73,77,69,7,225,5,27,16,40,7,129,43,165,16,0,0,2,131,73,68,65,84,72,199, +173,150,75,72,85,81,20,134,191,181,207,193,30,100,20,133,72,138,40,74,88, +148,98,23,172,73,154,26,145,41,105,13,170,91,87,16,130,102,61,104,208,80, +176,73,163,232,49,8,10,132,64,203,50,172,124,21,36,233,176,129,248,200, +66,169,244,38,248,106,16,22,106,131,186,247,156,213,68,73,229,30,189,222, +252,135,251,44,190,181,215,218,255,62,107,11,203,200,215,222,144,226,154, +112,153,8,37,64,42,144,60,247,105,12,24,65,181,213,178,77,83,87,190,127, +212,139,33,145,22,179,223,54,36,89,226,84,129,158,7,44,150,151,139,72,163, +11,215,250,10,252,35,43,38,240,117,62,46,87,165,22,216,196,234,52,163,72, +160,183,208,223,188,112,209,44,134,63,186,172,74,99,12,112,128,120,65,95, +248,58,234,47,69,172,96,110,231,141,75,147,198,32,87,145,19,243,149,8,64, +86,103,93,178,173,102,48,198,157,71,110,87,88,50,123,143,248,39,12,128, +173,230,186,23,252,66,234,30,106,246,29,38,51,126,235,170,218,133,165,213, +0,226,107,111,72,81,43,28,244,114,203,205,189,7,57,180,61,25,87,149,151, +147,195,220,25,238,99,54,28,138,38,137,19,22,55,213,96,57,229,81,88,17, +35,194,201,29,25,60,223,95,74,105,98,90,100,127,47,150,101,99,149,25,69, +139,87,83,251,182,184,245,84,239,58,192,253,156,34,210,54,110,94,54,86, +85,143,25,144,140,88,78,209,183,37,129,39,185,197,92,76,207,38,206,88,94, +183,56,221,128,38,198,106,21,91,12,149,41,187,105,200,45,38,97,221,134, +72,33,73,102,45,60,25,103,44,44,137,136,114,109,129,9,133,157,177,128,29, +85,158,141,127,225,222,215,126,126,69,118,214,132,173,16,36,134,4,3,51, +83,220,248,212,197,192,204,148,247,33,67,208,70,181,13,145,163,209,130, +167,67,127,120,48,242,145,167,227,159,113,85,151,183,182,106,171,109,217, +166,201,113,244,246,74,119,65,129,87,223,70,184,53,212,195,143,208,239, +104,246,18,14,25,109,49,93,249,254,81,65,30,122,69,13,205,254,228,195,244, +119,42,187,223,80,53,248,46,90,56,64,77,127,65,96,76,254,13,152,240,32, +16,191,70,63,187,105,177,157,204,238,188,138,73,3,240,190,232,212,184,170, +57,13,56,107,0,119,81,2,221,121,21,147,139,6,78,111,209,153,215,130,92, +5,220,255,154,5,202,149,158,162,179,45,158,35,51,167,163,254,184,160,117, +49,180,107,26,113,207,245,20,4,90,61,71,38,64,111,161,191,89,109,59,93, +209,187,64,56,170,150,160,181,98,59,153,75,225,158,175,138,121,101,117, +214,37,219,88,101,224,150,160,146,182,240,217,162,16,52,208,22,18,183,185, +191,32,48,230,197,248,11,86,228,238,84,203,121,117,202,0,0,0,0,73,69,78, +68,174,66,96,130}; + +static size_t xml_res_size_4 = 635; +static unsigned char xml_res_file_4[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,24,0,0,0,24,8,6,0,0, +0,224,119,61,248,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147, +0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,215,1,66,40,155,120,0,0,0,7,116, +73,77,69,7,225,5,27,16,39,59,41,220,197,88,0,0,2,8,73,68,65,84,72,199,181, +150,79,107,19,81,20,197,127,247,77,42,74,213,77,161,105,59,67,168,180,139, +172,252,12,110,107,193,68,67,43,65,17,164,184,85,113,225,170,8,250,17,92, +43,8,117,211,148,40,77,82,220,250,17,220,117,33,132,66,39,211,70,234,194, +74,241,79,230,205,117,209,36,152,191,198,208,57,48,139,119,223,155,115, +207,59,92,238,125,194,16,4,133,185,148,138,205,160,178,12,209,60,136,119, +186,163,62,152,61,160,130,53,219,110,62,216,31,196,33,253,130,251,133,41, +87,72,60,19,88,3,28,134,35,18,40,138,149,167,179,249,195,189,127,38,8,54, +167,179,42,178,1,92,228,255,240,29,184,235,174,214,75,127,7,77,167,37,201, +71,42,82,28,131,28,224,18,240,62,216,76,62,236,123,131,166,242,98,119,210, +49,16,1,55,91,55,17,0,191,232,122,98,195,221,110,229,226,92,192,156,159, +110,255,103,79,124,0,156,73,175,173,35,250,249,5,181,63,122,236,178,214, +166,83,249,163,32,1,32,97,248,2,233,181,229,242,213,117,38,23,215,218,235, +175,31,111,1,48,117,237,93,59,118,242,249,21,223,62,173,247,216,229,24, +231,57,240,192,4,133,185,20,194,189,254,53,150,232,92,155,115,167,95,71, +108,98,80,125,222,247,139,174,103,80,155,29,161,20,199,129,35,161,205,24, +21,89,34,38,136,232,117,3,186,24,87,2,69,23,12,48,67,108,16,215,16,47,34, +3,18,196,152,32,48,64,53,54,131,160,106,128,157,216,252,65,43,6,107,182, +1,27,3,127,136,51,81,54,205,97,241,166,191,132,70,103,217,69,191,32,250, +61,244,76,251,172,242,218,203,213,124,105,13,24,67,98,183,217,114,207,162, +217,29,55,28,155,158,207,29,29,180,219,245,193,214,204,82,164,90,62,131, +182,17,161,100,221,219,245,114,199,192,153,93,57,252,32,202,147,102,63, +31,159,92,120,220,34,239,59,50,107,133,228,13,224,109,183,93,35,224,88, +133,59,222,74,189,50,112,100,2,184,171,245,146,65,22,16,94,2,225,40,170, +21,217,104,56,54,221,77,62,240,85,209,130,95,116,61,9,109,70,37,90,22,228, +10,224,181,182,4,170,42,178,163,198,41,121,185,154,63,136,227,15,131,228, +187,196,255,21,120,89,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_5 = 622; +static unsigned char xml_res_file_5[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,24,0,0,0,24,8,6,0,0, +0,224,119,61,248,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147, +0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,215,1,66,40,155,120,0,0,0,7,116, +73,77,69,7,225,5,27,16,40,10,255,154,217,173,0,0,1,251,73,68,65,84,72,199, +181,150,79,107,19,81,20,197,127,247,189,81,20,172,224,78,104,76,83,154, +69,65,92,249,29,4,173,249,163,11,5,91,18,161,184,85,113,225,82,169,31,193, +125,109,154,182,238,146,54,147,20,193,79,224,70,23,74,177,155,198,212,196, +184,20,234,194,66,102,230,186,104,163,113,72,106,26,157,179,155,251,134, +115,238,59,243,230,158,39,28,129,157,84,46,238,88,147,65,153,81,130,4,72, +236,96,69,91,130,105,168,6,53,79,108,37,89,89,106,14,226,144,126,197,230, +245,220,184,103,228,137,8,243,128,229,104,4,8,37,69,30,79,110,20,26,127, +21,248,148,189,155,21,213,21,224,12,199,195,119,163,204,197,221,101,183, +183,104,122,31,118,211,185,7,162,90,26,129,28,96,44,16,214,119,51,249,251, +125,119,112,216,121,41,44,58,2,2,163,220,232,238,68,0,90,55,103,99,158, +239,124,28,177,243,1,118,217,233,184,251,162,237,0,120,190,243,44,76,126, +234,226,52,167,47,95,26,138,237,199,219,15,236,111,109,135,236,242,23,128, +123,178,147,202,197,173,145,122,248,180,156,155,191,195,217,212,149,161, +4,246,170,175,249,182,248,50,92,246,29,235,37,140,99,36,59,196,81,28,5, +214,243,157,140,81,184,74,100,208,107,6,72,70,39,192,148,1,206,71,199,47, +227,134,104,17,24,160,29,161,64,219,0,245,8,63,114,221,160,186,25,25,189, +72,205,120,98,43,128,31,1,191,119,194,120,85,39,89,89,106,54,210,249,2, +7,179,255,247,239,255,230,29,116,58,67,142,138,247,125,130,70,22,99,229, +181,150,3,96,3,125,234,91,185,5,140,117,95,216,223,218,14,207,151,227,96, +79,173,183,240,43,15,46,212,138,95,16,189,253,159,172,10,4,153,75,148,87, +191,254,17,56,137,141,226,43,129,71,64,240,79,228,34,15,39,42,133,234,192, +200,252,156,206,167,3,97,181,215,174,97,109,17,163,179,19,235,197,218,192, +200,4,136,187,203,110,231,164,153,82,120,14,120,195,116,13,186,130,245, +167,195,228,3,111,21,93,28,38,93,6,101,6,97,18,136,117,151,64,235,192,166, +99,125,55,86,94,107,13,226,248,9,156,77,179,166,75,139,17,212,0,0,0,0,73, +69,78,68,174,66,96,130}; + +static size_t xml_res_size_6 = 1144; +static unsigned char xml_res_file_6[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,24,0,0,0,24,8,6,0,0, +0,224,119,61,248,0,0,0,6,98,75,71,68,0,255,0,255,0,255,160,189,167,147, +0,0,0,9,112,72,89,115,0,0,13,215,0,0,13,215,1,66,40,155,120,0,0,0,7,116, +73,77,69,7,225,5,27,16,40,3,134,70,97,9,0,0,4,5,73,68,65,84,72,199,149, +150,125,76,213,85,24,199,63,231,220,223,21,132,139,74,76,96,23,68,4,2,95, +74,36,204,149,185,28,80,54,112,75,237,143,182,107,184,114,174,173,53,179, +172,173,218,154,110,218,250,167,245,178,176,173,63,154,171,41,190,76,231, +31,10,182,53,2,172,54,209,25,34,182,188,18,112,167,128,225,11,239,92,64, +238,203,239,233,15,188,183,251,194,5,122,254,59,231,57,207,247,123,206, +247,60,207,121,142,98,6,43,174,59,149,101,106,223,22,165,216,12,100,3,153, +143,92,61,192,45,68,106,45,134,62,123,101,163,163,59,22,134,154,110,178, +176,254,84,134,69,249,247,131,236,2,44,204,108,38,74,157,49,225,195,107, +37,142,91,179,18,20,55,30,223,42,194,81,192,198,255,179,81,65,85,182,148, +58,206,197,36,40,110,60,246,174,136,250,10,208,161,243,217,9,11,88,155, +156,74,122,92,34,94,49,233,28,27,230,210,64,47,110,159,55,234,52,10,181, +183,185,212,81,21,69,240,104,231,103,66,193,87,36,61,198,222,188,34,138, +23,165,70,109,215,47,66,205,93,23,135,58,91,25,242,78,134,145,8,106,91, +224,36,10,96,117,99,117,166,33,218,25,42,203,54,123,46,31,231,175,197,80, +83,124,109,238,65,122,31,142,97,85,154,60,219,34,210,226,18,0,24,244,78, +242,246,181,6,254,118,15,133,203,229,83,203,91,54,57,254,49,0,12,209,7, +67,193,95,74,93,202,39,5,235,80,192,197,129,94,190,104,111,230,246,248, +104,48,90,43,197,51,201,233,124,148,191,150,204,249,54,190,91,83,202,27, +205,117,116,79,4,215,36,97,145,3,192,155,170,184,238,84,150,88,124,174, +208,108,249,105,253,22,210,226,18,168,185,235,226,128,243,50,18,227,86, +19,13,43,223,23,149,81,96,75,230,226,64,47,239,180,94,8,83,209,167,204, +108,139,125,231,43,175,3,21,161,158,206,177,97,58,198,134,249,214,213,138, +57,67,218,236,206,41,36,101,94,60,233,241,137,44,153,159,196,170,5,41,60, +151,98,231,215,190,59,8,104,173,180,75,11,82,30,25,120,105,224,46,71,186, +156,248,69,102,204,203,62,207,4,133,11,23,7,199,27,82,236,120,76,63,230, +163,56,17,169,208,160,242,34,3,173,90,163,149,154,53,241,143,117,183,113, +99,116,32,56,238,247,60,228,155,142,107,161,53,144,171,65,210,35,3,63,91, +185,158,183,150,61,57,43,129,41,194,193,155,151,241,201,148,144,159,183, +55,51,226,243,132,46,201,48,34,131,54,164,216,41,91,188,4,191,8,245,247, +187,105,115,15,206,72,210,238,30,226,72,151,147,2,91,50,191,220,239,138, +46,188,226,134,227,109,2,249,129,172,56,189,174,34,152,227,109,238,65,118, +252,241,243,172,119,161,149,194,80,26,143,233,143,116,221,212,2,174,192, +104,79,206,154,32,56,64,129,45,25,71,102,193,156,164,154,6,28,1,151,70, +228,124,160,164,19,12,131,11,125,61,193,5,127,141,244,135,17,78,103,86, +173,217,157,83,200,166,212,172,232,147,137,212,106,139,161,207,2,126,1, +246,221,104,226,131,63,127,15,106,153,100,157,199,15,93,55,102,148,230, +211,21,207,178,115,233,74,222,207,123,42,210,237,243,106,169,209,87,54, +58,186,21,234,199,80,207,151,29,87,185,55,57,78,214,252,36,78,62,93,78, +121,90,54,243,116,216,3,203,19,11,82,56,92,244,2,47,166,102,225,49,77,246, +59,155,34,9,14,95,47,169,236,81,255,53,24,159,19,72,10,120,3,111,140,61, +62,17,128,49,159,23,215,248,48,94,211,196,30,111,35,61,126,74,186,135,126, +63,251,156,77,52,60,8,107,106,35,202,240,47,111,126,126,71,111,176,154, +138,234,79,150,43,101,214,132,190,73,9,22,131,93,217,171,120,53,227,113, +18,44,214,168,139,253,173,255,14,85,157,173,220,30,31,9,239,112,194,214, +171,101,219,107,162,27,78,195,137,61,130,124,29,217,112,172,90,83,180,112, +49,185,137,139,176,40,197,189,201,113,90,134,30,208,231,153,152,46,161, +222,107,41,219,126,40,102,203,44,106,56,241,178,66,170,67,229,154,163,141, +160,204,215,174,150,84,214,134,37,66,228,170,150,82,199,57,49,140,92,65, +170,0,223,28,128,77,144,163,202,240,47,143,4,143,249,171,8,216,234,198, +234,76,3,203,22,48,55,35,106,89,232,183,101,170,136,56,239,85,230,185,235, +37,149,61,177,48,254,5,68,165,141,10,108,236,250,76,0,0,0,0,73,69,78,68, +174,66,96,130}; + +static size_t xml_res_size_7 = 1852; +static unsigned char xml_res_file_7[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,6,222,73,68,65,84,120,218,188,87,107,136,85,85,20,254,246,62,231, +222,59,247,206,181,113,108,212,73,51,51,130,140,32,170,31,61,200,136,222, +132,40,169,101,69,66,101,15,122,64,74,15,169,8,42,168,176,172,44,168,164, +232,97,86,72,143,49,205,158,248,39,66,255,20,84,100,165,65,145,164,53,154, +81,206,204,109,230,156,123,206,61,167,111,173,125,212,123,207,204,144,70, +117,240,56,107,159,253,250,246,183,190,181,246,186,6,128,191,230,206,147, +214,90,196,51,145,166,108,202,251,95,62,134,255,12,18,248,239,205,93,250, +249,69,62,191,148,109,26,205,60,241,178,165,72,147,6,251,140,27,164,111, +54,126,132,101,82,252,19,172,169,78,49,198,226,139,215,239,154,41,123,11, +128,54,68,53,212,251,127,193,150,13,43,0,235,195,216,34,71,121,186,179, +103,129,130,117,211,19,206,182,25,154,40,113,109,89,49,109,61,223,190,246, +48,155,12,39,60,228,177,231,222,200,70,34,159,219,4,128,233,190,226,93, +108,217,253,43,112,198,114,76,232,158,130,223,215,95,201,157,139,4,98,80, +34,142,37,235,138,194,26,158,152,23,98,113,79,73,61,245,232,156,58,23,115, +27,196,13,89,60,129,37,177,150,136,19,93,155,182,109,181,27,137,65,20,69, +14,150,50,205,45,228,255,193,218,239,216,246,195,86,108,251,126,43,134, +6,251,224,179,211,231,66,190,245,200,128,65,165,189,202,183,29,150,243, +42,149,118,181,125,206,191,253,157,118,125,11,30,199,179,115,207,113,247, +226,214,55,13,121,77,208,151,183,223,178,40,249,92,211,227,137,210,198, +62,198,132,1,196,245,24,29,29,157,180,44,162,48,230,32,46,88,112,92,199, +113,130,123,207,236,229,73,98,244,15,0,247,204,24,212,239,181,26,176,244, +252,65,158,216,67,163,81,128,103,82,68,65,13,69,63,165,203,82,196,121,219, +75,245,48,150,135,75,243,0,18,175,132,142,113,19,148,144,196,248,40,149, +124,44,90,227,57,170,103,199,56,235,206,183,57,42,24,69,88,109,248,232, +161,121,40,148,44,194,48,32,213,6,30,65,141,102,147,84,100,126,217,15,96, +251,170,153,152,126,246,117,216,241,213,251,24,162,239,15,153,212,133,246, +234,24,245,43,82,30,21,60,58,23,129,231,187,87,158,70,236,222,98,164,227, +12,69,27,6,117,61,33,221,141,32,111,211,144,8,211,40,203,51,112,194,162, +77,216,185,179,23,213,115,47,68,247,225,71,34,218,112,61,150,207,174,81, +168,41,250,6,140,219,136,19,223,184,123,46,252,82,155,115,13,1,205,127, +224,77,237,147,141,60,178,23,214,3,221,200,35,237,245,156,109,116,140,115, +129,65,14,64,56,212,135,111,190,222,172,155,140,59,180,139,19,83,92,187, +218,215,168,93,62,203,138,16,84,185,157,227,186,80,108,171,232,196,122, +48,232,66,169,145,50,98,185,48,223,48,116,39,181,244,119,56,148,179,9,80, +198,73,100,49,28,90,1,68,245,8,237,149,146,106,64,194,164,66,32,43,23,36, +144,97,253,253,156,64,1,74,208,143,169,150,233,235,178,203,3,20,152,2,179, +217,201,184,89,56,20,104,146,241,76,162,126,111,177,51,1,10,144,84,25,48, +251,1,52,152,28,202,229,178,70,65,220,136,53,4,23,174,138,52,209,60,117, +137,231,0,48,216,43,20,167,231,187,137,5,153,26,215,169,9,79,253,111,69, +3,245,186,138,205,216,17,108,97,128,175,117,25,169,149,129,6,41,41,209, +183,41,1,52,24,118,18,134,149,114,73,147,76,193,11,50,0,33,142,191,248, +46,151,33,53,171,242,20,49,251,76,73,147,143,199,183,78,23,24,2,242,188, +132,126,15,135,217,34,72,25,155,101,193,166,48,76,13,218,202,21,110,104, +244,212,2,196,43,180,185,52,234,197,122,202,125,234,55,217,100,81,51,211, +54,209,194,247,125,231,130,48,212,147,202,70,46,34,154,108,97,195,100,9, +48,31,5,182,88,65,91,181,160,0,36,5,167,60,229,138,249,177,250,105,48,44, +162,231,145,219,24,186,137,10,145,228,144,21,232,194,210,47,9,120,210,248, +14,197,88,207,104,151,136,200,219,78,15,34,25,134,108,30,192,79,175,205, +199,49,167,205,70,255,207,155,17,51,17,217,73,157,184,236,133,72,7,172, +188,170,132,35,216,150,139,196,232,230,6,87,190,20,42,8,1,16,113,173,85, +11,61,141,28,137,2,35,241,78,218,131,156,237,244,0,141,4,168,188,155,68, +56,177,107,44,166,76,158,136,33,179,75,145,210,35,120,235,6,95,55,29,12, +24,13,84,251,94,6,164,111,229,2,104,90,117,23,44,179,39,67,81,194,80,124, +173,57,129,27,71,57,219,9,48,213,136,113,215,104,19,3,178,136,228,236,57, +207,13,168,47,123,110,238,192,197,207,244,113,211,20,47,47,44,227,148,171, +239,151,88,109,45,0,76,166,3,186,236,179,151,239,99,179,160,39,133,170, +61,29,102,187,44,232,106,129,97,137,72,65,48,20,229,150,219,91,144,136, +40,147,140,118,244,237,160,226,163,150,240,217,39,68,175,64,208,34,10,15, +53,138,45,74,172,18,92,11,162,97,182,176,103,108,50,92,132,178,110,196, +240,123,126,129,175,64,6,254,12,240,236,165,174,126,169,179,242,232,89, +177,172,37,116,154,105,144,240,154,54,185,11,49,239,250,37,51,246,104,156, +7,113,21,119,204,248,67,71,4,241,24,44,57,99,143,178,222,72,218,29,232, +116,152,11,160,149,74,200,100,115,194,229,247,184,211,238,165,155,127,78, +26,173,246,146,197,252,34,190,92,253,160,14,60,124,124,69,197,40,39,156, +220,85,209,80,145,156,114,68,247,33,168,199,188,150,69,43,34,70,242,146, +230,93,32,16,153,40,73,247,207,25,221,73,174,208,26,13,64,65,197,38,26, +218,232,93,129,237,219,190,215,174,169,211,142,198,57,118,53,102,63,177, +91,195,123,205,45,227,179,91,152,26,200,39,162,236,126,213,251,122,253, +139,79,114,239,88,35,224,111,235,91,17,22,147,209,81,147,15,149,124,132, +95,123,119,224,227,13,31,104,223,133,179,230,192,159,98,80,29,83,85,0,122, +11,90,151,199,82,140,0,64,228,34,7,154,181,248,97,98,25,65,112,163,49,64, +17,126,219,179,76,75,173,93,187,118,177,100,115,151,149,216,102,170,135, +158,155,164,174,48,8,162,84,43,36,185,8,61,164,35,48,160,138,207,92,112, +144,0,132,137,148,115,183,237,216,137,134,117,119,200,143,219,123,145,158, +108,113,206,195,187,181,253,225,109,227,113,222,178,221,252,59,97,248,93, +160,106,38,55,30,67,233,163,87,159,86,65,30,40,0,9,193,35,89,65,53,56,229, +246,83,123,181,0,145,185,113,50,196,248,239,192,187,139,198,105,197,20, +6,33,62,88,220,169,185,197,51,185,235,88,215,18,84,156,124,193,77,15,186, +10,232,32,24,248,110,237,99,220,48,193,233,215,220,183,127,174,172,79,125, +108,237,121,4,211,231,45,129,34,228,133,246,221,186,199,81,72,70,212,0, +180,12,199,64,175,91,228,128,126,246,24,93,84,42,99,125,250,126,105,154, +235,110,75,77,82,125,92,83,88,149,235,153,109,219,180,130,239,126,29,100, +101,120,90,198,198,181,175,224,192,127,35,186,251,117,106,247,88,109,181, +206,205,250,38,118,96,227,186,236,187,180,15,235,212,189,140,53,205,153, +208,212,62,221,244,73,85,138,80,99,14,254,231,230,111,63,237,247,200,72, +125,205,223,181,109,141,238,185,55,195,8,252,105,124,59,71,207,56,255,250, +35,20,73,174,254,209,104,121,7,48,73,163,136,255,247,145,235,245,207,191, +4,24,0,228,101,43,215,5,253,61,104,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_8 = 1017; +static unsigned char xml_res_file_8[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0, +0,31,243,255,97,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0, +65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60, +0,0,3,155,73,68,65,84,120,218,108,83,107,76,28,85,24,61,51,204,192,62,200, +178,180,74,106,85,144,46,143,74,74,85,88,16,180,11,110,155,216,248,10,54, +45,93,72,140,105,13,49,77,68,34,36,45,2,41,181,42,225,33,5,234,143,254, +177,63,76,127,216,198,96,218,106,104,4,45,162,18,90,202,110,154,150,165, +181,117,97,215,2,93,118,102,217,7,236,123,102,118,188,67,72,252,227,73, +78,230,206,157,123,190,239,220,243,101,168,190,254,65,136,162,8,5,130,32, +32,22,143,127,89,110,44,237,96,24,6,118,187,29,222,213,213,31,95,42,41, +105,39,103,70,213,106,245,211,233,26,45,2,235,107,144,68,113,150,162,168, +3,140,34,148,101,121,131,130,32,94,170,124,185,220,242,246,91,111,162,171, +187,219,125,109,100,228,227,18,163,81,78,75,77,181,151,149,150,32,235,137, +39,33,72,34,34,225,8,28,142,249,226,71,203,75,142,141,2,201,100,18,146, +36,125,95,188,123,87,109,117,149,9,63,92,190,140,147,29,237,251,201,167, +191,223,63,114,212,187,179,176,0,52,69,99,226,207,73,132,195,97,132,194, +33,128,162,72,211,36,24,69,156,157,157,13,142,227,106,205,166,61,112,204, +47,160,48,191,0,173,109,29,45,26,141,246,104,52,26,213,234,116,58,220,191, +255,23,180,106,21,92,255,184,208,220,212,104,196,38,24,98,253,138,32,138, +53,150,195,7,49,247,224,33,182,232,245,120,236,118,43,174,142,16,87,107, +241,88,108,163,83,70,70,6,104,154,70,34,145,64,79,223,25,155,36,10,160, +200,59,77,46,80,179,183,186,10,179,246,123,74,24,184,117,107,6,163,99,163, +104,249,164,9,69,69,69,77,49,82,32,22,75,128,37,161,42,182,205,38,147,18, +186,44,41,161,17,69,74,69,229,43,85,235,161,72,110,102,166,30,1,191,15, +103,7,7,222,73,79,99,181,105,108,202,206,170,87,43,96,187,125,7,121,121, +6,50,157,4,52,42,21,114,178,159,65,69,121,25,12,134,92,204,88,109,65,138, +84,217,209,222,209,249,141,70,173,218,27,13,5,199,187,122,122,223,32,123, +79,25,142,159,183,165,179,236,214,241,70,51,22,22,221,120,224,88,128,213, +58,131,156,237,219,176,22,12,34,24,10,91,7,134,134,26,208,223,63,160,100, +177,131,176,84,121,234,186,38,160,59,253,243,133,67,195,243,242,141,128, +44,127,113,221,41,255,58,242,147,124,170,179,83,62,209,210,124,113,243, +156,194,130,158,207,78,130,58,119,166,15,52,153,109,171,184,135,36,42,66, +18,226,223,213,151,61,95,255,65,101,14,206,78,241,88,137,83,240,90,175, +98,244,152,25,211,55,167,197,11,172,241,219,95,238,58,245,44,203,214,42, +33,50,157,241,114,146,100,18,106,57,1,65,20,46,190,190,43,175,78,17,127, +61,229,129,63,46,195,195,251,201,68,224,187,125,99,82,180,101,84,100,181, +154,242,27,168,36,141,223,230,30,94,74,101,216,58,90,5,1,44,233,44,75,194, +240,11,207,110,171,59,177,47,15,195,247,252,240,197,146,88,226,125,240, +56,239,92,155,235,109,48,91,108,169,147,147,235,122,244,143,115,104,219, +111,192,107,249,57,22,81,18,135,233,44,157,6,10,183,166,107,14,14,29,122, +145,116,230,96,95,137,99,209,27,192,162,115,110,140,235,173,111,220,222, +125,253,46,9,89,203,249,56,248,163,18,190,154,240,224,212,187,69,27,26, +154,216,83,44,18,80,56,55,237,71,48,33,227,17,207,97,201,101,31,243,245, +30,62,214,247,105,179,51,73,165,192,253,249,129,143,188,174,217,177,101, +47,135,64,76,198,224,31,62,200,68,147,194,154,234,16,37,127,97,196,207, +155,31,7,35,207,121,86,121,4,60,174,113,190,199,242,97,87,219,113,34,166, +113,83,85,136,45,251,222,243,47,159,174,153,98,118,87,23,7,19,241,220,69, +158,199,154,119,229,119,10,255,193,64,168,223,92,251,9,23,240,255,80,70, +158,185,185,14,252,43,192,0,141,58,185,202,150,159,74,140,0,0,0,0,73,69, +78,68,174,66,96,130}; + +static size_t xml_res_size_9 = 1751; +static unsigned char xml_res_file_9[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,6,121,73,68,65,84,120,218,180,87,91,136,85,85,24,254,215,90,123, +239,115,206,92,116,116,38,157,48,47,35,90,80,129,89,116,33,51,74,165,34, +6,52,20,231,33,240,33,80,8,133,30,213,232,74,15,225,99,161,4,69,15,9,65, +23,203,140,30,122,200,64,208,138,233,98,150,24,42,90,94,162,209,156,25, +103,206,204,156,115,246,109,245,253,107,175,125,206,222,211,25,60,15,181, +14,63,251,236,117,251,191,245,255,223,255,255,107,11,74,154,243,234,190, +15,15,72,229,172,215,90,211,255,217,132,16,20,71,225,161,151,183,15,108, +194,107,40,88,249,139,111,188,127,80,72,167,127,197,138,229,20,51,128,255, +11,3,180,73,0,56,113,226,44,233,56,252,226,181,231,158,126,202,65,119,137, +148,211,191,107,251,102,138,211,137,186,233,218,186,76,111,26,157,241,204, +58,115,107,120,235,199,87,175,164,61,251,62,234,103,221,12,160,24,71,177, +217,96,235,243,111,153,73,137,21,120,168,13,82,32,137,101,5,242,129,116, +138,28,10,217,104,232,41,226,233,65,185,160,192,13,104,170,84,161,192,9, +208,111,182,36,129,245,18,187,122,88,231,106,159,164,134,14,40,241,107, +130,222,124,233,89,252,55,144,139,60,91,104,44,11,35,108,231,57,244,238, +43,91,41,136,24,4,143,63,4,159,29,35,23,255,142,210,195,244,168,56,98,182, +47,64,92,218,128,255,63,144,35,75,84,131,146,145,133,23,40,154,67,20,1, +151,116,239,38,225,118,193,176,130,222,115,183,65,158,161,118,108,18,3, +123,223,234,119,8,231,37,203,53,225,24,179,224,37,8,53,22,40,242,49,169, +234,91,0,162,0,243,181,225,28,34,81,139,71,135,57,55,108,32,60,128,232, +32,165,74,164,221,73,51,92,129,193,98,70,231,97,157,219,142,227,225,212, +174,36,23,90,92,69,198,118,133,130,194,1,67,86,154,176,191,1,32,162,2,102, +177,98,118,65,204,142,133,8,99,72,153,98,229,127,164,120,161,86,88,236, +130,84,108,106,215,116,198,152,18,179,185,148,34,161,48,19,34,164,224,215, +122,43,120,0,0,19,167,209,38,19,102,104,211,233,186,78,26,43,211,152,132, +29,132,52,118,144,117,97,104,248,161,95,113,143,204,14,202,186,48,128,236, +118,172,35,8,67,210,148,1,192,104,124,116,186,142,99,24,157,227,172,81, +172,140,58,202,1,144,38,164,164,129,34,76,167,200,1,80,117,0,217,208,98, +29,126,24,215,45,224,52,0,196,13,11,104,202,88,34,221,89,24,211,11,145, +181,128,74,237,208,240,141,25,132,77,160,88,243,233,101,222,154,198,2,193, +116,14,144,54,157,6,128,206,4,48,9,123,114,97,50,152,152,110,1,134,33,44, +0,101,215,240,160,163,12,8,33,99,195,5,193,134,180,137,130,35,205,184,32, +11,192,112,0,157,94,157,3,169,21,68,114,100,145,170,204,0,16,202,192,83, +134,1,42,217,201,77,66,68,184,46,107,66,56,34,178,48,207,197,22,30,3,136, +56,10,0,32,106,226,130,192,184,64,82,190,20,228,207,204,135,84,34,57,172, +50,220,119,17,142,78,194,129,9,68,64,0,193,160,30,27,36,25,118,80,36,125, +58,89,189,151,62,27,177,233,18,227,253,91,101,46,10,26,0,208,233,57,174, +209,217,160,128,74,34,192,18,141,149,59,214,56,19,52,73,99,250,34,77,196, +62,226,251,42,209,105,28,176,4,97,43,208,53,76,98,166,87,40,18,149,36,115, +177,5,0,160,8,235,248,198,5,212,0,192,113,95,139,216,5,170,73,38,183,236, +2,16,108,69,151,180,177,36,222,135,1,176,140,83,58,141,217,142,37,162,57, +85,178,206,112,72,155,116,107,128,123,94,146,136,226,188,5,40,33,161,231, +228,84,55,78,95,33,95,143,154,76,38,172,27,132,45,51,156,37,117,179,18, +37,40,71,104,157,141,2,63,110,146,9,131,216,48,148,67,152,73,156,112,16, +190,138,203,224,96,100,84,165,7,227,108,41,204,12,196,143,212,117,77,138, +247,141,44,119,209,39,177,111,253,126,17,89,147,115,30,168,54,18,81,61, +10,66,84,138,246,146,162,118,213,48,99,140,234,23,83,213,76,18,230,252, +105,127,186,99,144,171,221,179,38,237,56,120,160,149,15,64,62,69,126,148, +73,68,194,228,235,127,39,34,252,34,132,70,215,108,55,151,54,239,184,111, +45,117,247,44,166,8,12,94,57,188,140,244,96,99,236,133,7,214,210,169,238, +37,80,162,192,183,113,227,227,180,173,25,216,76,65,97,22,69,97,141,182, +109,185,147,244,19,141,177,67,131,14,85,107,97,179,76,24,26,23,100,155, +82,21,212,147,49,227,231,80,130,7,246,204,92,13,71,49,54,162,174,35,16, +81,148,162,169,252,186,145,9,84,197,8,0,2,170,141,84,97,67,84,194,72,112, +109,50,42,253,160,41,0,248,12,87,142,225,234,53,36,49,166,172,130,85,118, +163,118,187,73,4,201,128,46,169,17,132,85,68,10,99,187,162,157,228,98,12, +201,142,100,132,190,43,35,230,25,163,244,69,7,62,78,158,32,139,31,248,116, +249,175,97,240,38,6,121,5,220,92,164,161,225,241,60,9,57,205,242,235,79, +191,13,67,254,206,148,3,244,219,234,196,110,210,66,215,125,41,116,18,7, +41,5,132,185,69,105,147,57,181,176,25,84,219,117,118,140,245,40,176,188, +88,240,234,21,215,228,149,169,242,216,177,159,191,251,118,149,142,227,230, +87,66,109,57,155,62,51,253,211,203,183,176,239,162,73,89,79,223,4,64,84, +38,198,143,217,252,72,157,144,69,144,158,122,84,204,220,228,150,29,187, +215,47,233,91,190,177,216,57,167,55,59,80,45,143,14,253,241,251,217,79, +246,239,125,253,16,205,124,71,77,91,152,164,75,186,40,172,210,146,185,73, +54,191,244,26,208,107,250,7,22,61,242,228,198,193,9,228,139,123,238,186, +149,206,195,175,217,76,179,244,230,110,58,126,226,12,181,57,146,142,124, +249,233,253,135,63,255,224,2,205,124,193,231,126,230,102,197,177,104,202, +86,102,106,133,85,143,109,24,210,133,34,114,121,76,157,179,58,104,221,130, +121,117,38,179,111,175,150,167,200,3,193,52,204,251,224,186,245,223,0,64, +59,134,106,55,250,84,112,90,252,164,104,11,16,82,203,22,206,167,242,100, +133,206,158,187,76,103,166,125,65,49,136,121,61,93,52,167,179,131,126,253, +229,148,178,119,250,255,12,128,27,162,94,247,205,159,43,145,75,105,116, +124,146,42,190,159,227,96,9,245,191,103,118,7,133,65,64,199,185,182,39, +183,131,27,54,213,34,0,175,60,62,250,253,148,156,53,224,224,138,117,91, +223,2,186,125,233,45,180,184,119,46,164,155,22,245,246,96,163,152,78,158, +62,79,95,31,253,145,14,31,220,191,233,234,159,23,206,89,63,223,232,107, +173,165,198,21,125,62,71,203,166,109,59,119,116,245,244,174,115,92,183, +59,107,2,156,124,248,250,181,161,175,14,188,189,103,47,179,27,114,165,21, +23,180,10,64,216,12,220,5,185,9,50,219,130,202,94,121,89,217,24,132,51, +217,117,136,79,45,124,230,182,10,32,235,178,162,85,238,52,137,237,154,53, +123,212,234,134,255,8,48,0,163,88,200,134,33,243,7,106,0,0,0,0,73,69,78, +68,174,66,96,130}; + +static size_t xml_res_size_10 = 1855; +static unsigned char xml_res_file_10[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,6,225,73,68,65,84,120,218,196,87,123,80,84,85,24,255,238,115,31, +160,41,169,37,175,196,16,28,21,75,108,20,21,195,200,124,128,111,39,49,205, +7,154,38,249,154,177,153,242,143,254,232,53,163,142,53,227,24,67,89,227, +148,96,36,166,228,35,95,164,136,104,68,89,249,2,53,65,65,212,69,151,213, +117,217,221,123,239,62,238,189,125,231,238,93,220,20,84,172,198,157,249, +102,239,185,247,156,243,253,206,247,251,94,135,82,85,21,30,231,143,250, +151,235,185,241,175,229,92,197,255,110,12,195,216,119,108,206,125,10,159, +125,237,217,128,121,84,224,47,101,78,143,75,30,146,110,27,147,145,17,54, +120,200,16,56,117,226,132,41,50,246,217,163,245,53,213,117,237,217,136, +126,4,229,244,152,169,243,102,71,197,198,93,202,156,56,17,142,149,151,131, +44,203,160,42,10,72,130,139,107,239,158,108,59,149,51,25,211,22,108,141, +239,149,48,165,95,82,18,148,150,148,128,71,146,208,30,1,38,21,69,161,117, +0,242,255,1,128,203,156,182,240,242,144,212,212,238,70,163,17,126,173,172, +4,142,227,128,161,67,15,220,170,67,115,230,101,165,215,17,221,53,33,119, +228,192,187,125,132,126,40,190,51,178,226,38,207,90,234,205,156,48,161, +59,58,27,212,92,184,160,41,55,153,205,96,68,1,140,36,181,109,143,230,132, +245,233,131,128,162,227,17,136,131,140,219,3,128,30,61,37,123,86,247,152, +30,26,223,54,155,13,44,22,11,24,77,38,77,120,131,1,12,104,141,214,66,153, +75,91,222,17,21,90,77,11,126,200,198,161,71,248,44,125,56,248,164,75,230, +197,7,246,135,90,254,126,0,152,177,175,190,81,212,43,177,247,166,87,70, +143,134,134,250,122,112,58,157,96,34,202,81,169,1,149,27,117,105,13,128, +98,57,101,80,221,183,126,164,76,157,114,205,57,123,215,224,171,27,194,231, +25,51,129,225,134,153,230,22,78,15,234,38,72,216,171,27,83,118,240,148, +63,147,5,63,92,176,135,195,59,71,147,192,196,248,33,101,232,80,136,138, +142,134,250,186,58,77,9,81,126,143,34,244,126,85,231,159,82,149,22,36,114, +77,153,40,214,148,173,226,82,23,149,114,201,89,5,166,236,162,74,241,235, +172,98,127,245,190,121,108,223,140,111,113,202,118,20,145,0,48,113,224, +207,236,154,93,136,123,200,48,152,146,97,122,172,3,76,172,31,68,193,5,215, +209,228,132,111,138,106,157,97,2,140,8,165,146,35,41,154,207,240,243,183, +15,98,195,58,239,146,47,28,30,231,217,255,81,37,221,241,233,101,76,124, +218,122,252,182,217,123,104,109,37,219,103,172,100,156,181,105,154,84,48, +167,128,152,1,73,196,133,126,23,216,74,94,7,225,240,108,104,178,218,192, +106,181,130,219,237,214,156,140,240,77,184,110,77,200,55,208,40,64,16,1, +91,80,190,109,75,235,193,239,109,98,18,210,143,227,248,150,103,239,251, +251,65,246,93,53,205,223,182,2,199,130,234,188,94,68,133,117,33,190,193, +209,45,206,171,72,96,140,136,2,99,231,72,220,212,172,153,59,200,247,125, +5,231,168,119,232,144,53,163,56,44,94,33,111,204,12,213,43,156,49,231,236, +219,138,239,156,202,141,243,95,80,230,8,2,64,149,175,157,222,75,241,230, +52,114,248,128,19,170,148,6,192,208,169,27,208,157,187,1,75,51,192,178, +40,204,253,133,132,36,153,27,36,199,239,247,41,244,146,35,249,166,37,7, +139,113,104,247,253,178,113,37,112,198,151,53,165,13,191,87,32,143,102, +114,96,185,182,188,90,95,194,135,36,34,9,29,212,136,70,81,192,106,191,9, +102,222,139,156,62,184,82,146,12,16,23,254,76,208,2,172,146,155,182,18, +150,149,145,122,32,249,79,21,159,229,211,150,6,104,249,45,191,150,75,201, +14,56,104,93,133,61,152,99,2,0,52,7,147,192,121,173,6,194,13,42,88,155, +250,67,56,239,3,154,82,31,168,92,65,199,239,25,219,67,99,146,97,208,115, +255,89,105,165,144,20,233,11,121,150,239,74,197,56,87,149,128,229,205,192, +24,85,112,139,2,80,202,195,1,144,101,37,16,33,58,15,244,194,61,239,129, +226,111,210,162,33,125,69,116,112,46,159,254,118,76,107,249,250,14,5,178, +0,124,199,206,232,22,42,112,200,63,143,9,147,0,104,43,252,130,33,40,51, +74,232,145,121,229,203,204,143,69,0,146,120,84,182,247,168,13,170,228,60, +74,62,209,145,73,195,112,129,155,60,27,38,173,29,216,138,5,68,224,194,35, +0,12,50,2,96,129,193,47,12,57,24,2,104,51,7,144,116,41,203,45,3,154,97, +201,196,219,252,196,181,73,108,204,128,82,124,17,45,230,141,233,75,190, +210,79,68,173,80,155,27,183,107,96,58,69,167,130,79,172,214,64,6,236,134, +193,64,232,195,40,0,228,62,101,224,64,116,66,63,8,238,102,184,120,185,1, +129,43,109,128,64,11,224,218,96,42,166,104,154,152,67,84,89,158,198,184, +23,189,63,111,152,68,162,193,48,249,211,254,120,162,24,113,211,204,85,90, +204,133,117,153,163,216,106,191,34,129,163,1,240,3,237,108,218,82,212,129, +65,223,248,203,30,6,133,71,45,152,9,125,48,224,249,254,144,152,152,8,87, +26,27,193,227,241,220,3,130,168,165,21,165,197,136,138,94,90,124,219,151, +87,163,199,141,35,96,12,25,31,68,48,49,201,37,138,237,210,58,28,55,27,167, +174,75,70,48,145,82,81,206,102,226,164,4,128,55,106,94,197,136,119,167, +196,14,243,248,20,181,131,65,165,202,119,148,157,35,91,58,237,19,231,98, +54,156,241,92,114,50,88,111,218,64,148,60,247,148,92,18,5,90,58,38,121, +144,162,41,29,151,147,236,107,90,180,103,53,38,156,28,85,116,148,75,133, +243,243,136,66,58,170,127,177,114,253,220,135,250,28,15,1,64,28,163,126, +77,113,67,147,94,161,20,205,40,72,111,197,161,157,107,154,111,223,60,109, +183,219,87,15,31,49,2,4,73,4,151,219,125,143,35,234,15,161,134,241,50,253, +198,119,64,229,111,42,214,154,92,105,203,194,13,248,206,129,89,241,123, +240,121,234,164,173,111,21,232,0,20,86,143,79,146,24,28,33,0,20,253,185, +185,234,143,99,197,183,154,26,235,93,46,215,38,4,97,232,18,241,36,56,176, +44,7,21,170,161,32,66,126,114,213,110,159,80,181,187,143,62,188,109,94, +252,83,9,58,101,111,236,11,94,208,245,73,161,97,24,76,14,161,189,156,172, +163,244,91,26,46,122,177,229,30,41,184,93,249,169,47,166,197,69,98,137, +118,186,92,90,41,134,182,27,50,140,70,104,36,84,98,19,114,0,25,138,68,229, +41,56,182,145,131,233,135,124,168,182,220,175,111,230,185,120,254,100,137, +76,241,145,72,123,66,207,248,120,80,176,124,211,20,173,85,197,234,51,103, +64,112,53,127,119,237,114,237,69,125,115,114,0,15,177,164,108,57,125,196, +123,232,147,124,93,249,205,208,190,240,97,239,5,178,110,50,233,114,237, +217,227,152,252,110,55,55,187,83,123,37,36,2,139,189,2,41,76,213,85,85, +8,192,17,10,160,37,63,169,206,27,162,110,77,199,221,77,105,123,186,98,178, +240,22,249,255,179,226,224,55,141,87,46,157,20,4,97,203,200,81,163,32,60, +44,12,83,9,77,170,35,211,198,58,223,127,121,53,11,52,49,120,29,67,137,205, +204,90,184,147,166,153,78,152,35,156,187,10,243,72,214,179,180,231,94,240, +168,119,67,178,142,71,233,138,18,137,18,166,155,183,94,247,112,245,255, +6,208,210,125,235,202,57,221,204,238,246,94,78,31,251,239,111,1,6,0,48, +107,244,198,77,151,19,83,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_11 = 869; +static unsigned char xml_res_file_11[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,3,7,73,68,65,84,120,218,236,151,223,75,20,81,20,199,207,157,157, +31,251,83,77,122,176,151,232,7,130,73,245,188,161,137,17,26,5,82,244,22, +81,36,98,136,32,21,253,29,81,17,136,36,98,37,209,147,82,8,69,74,36,166, +228,115,5,9,210,22,61,7,169,59,174,59,59,59,247,118,206,29,119,221,93,117, +118,87,150,246,101,239,114,119,118,239,143,115,62,243,189,231,156,217,101, +66,8,168,102,83,160,202,173,6,80,3,168,58,0,243,152,211,39,94,190,178,228, +34,198,246,101,60,147,226,55,174,95,51,240,146,42,71,1,125,252,249,132, +213,218,218,10,182,237,64,58,205,129,115,81,86,167,61,180,151,108,144,45, +178,89,170,2,250,232,216,184,21,141,70,225,203,215,111,16,14,133,209,160, +3,249,74,236,165,136,200,187,115,69,241,129,185,97,194,233,83,39,97,105, +105,9,250,251,122,119,40,81,104,73,31,25,29,179,58,59,58,224,251,242,178, +28,104,111,59,3,235,235,235,176,182,22,135,100,50,9,137,205,77,79,217,131, +129,0,248,253,126,168,175,143,64,93,93,29,44,44,126,150,227,39,90,90,96, +110,126,30,6,250,251,242,32,114,1,244,225,145,167,86,119,119,23,172,172, +252,216,154,18,104,204,128,3,13,13,16,137,68,64,215,53,48,12,195,19,192, +178,44,72,165,108,136,199,227,240,119,117,21,161,173,172,173,230,230,227, +48,51,51,11,131,3,183,179,16,25,0,253,241,147,97,235,202,229,30,136,253, +252,85,16,72,180,85,184,178,150,250,220,192,163,162,227,146,175,2,141,143, +29,61,2,175,223,76,195,157,161,65,9,65,211,234,131,135,143,166,122,111, +221,236,177,237,116,246,28,119,59,94,81,78,106,177,189,103,53,77,133,241, +103,47,166,239,223,187,123,85,197,145,128,207,167,246,152,102,2,222,190, +123,47,23,8,193,161,210,79,73,169,8,83,228,157,92,186,120,1,200,39,249, +38,0,131,115,142,105,147,150,193,67,110,187,206,159,147,0,172,88,165,40, +169,24,184,202,17,192,236,135,143,210,28,249,34,159,228,155,0,20,250,98, +227,32,5,24,71,199,220,225,48,247,105,1,211,72,169,132,127,233,172,243, +108,59,6,177,14,10,130,216,219,0,10,1,64,70,1,85,85,229,6,51,177,1,145, +112,8,1,88,69,36,160,194,68,54,53,77,43,84,0,178,0,60,237,200,5,36,125, +10,83,39,16,8,238,187,4,239,86,146,201,166,134,55,72,54,201,87,1,0,82,98, +224,81,158,19,177,237,56,16,10,21,1,16,185,149,156,123,10,69,0,100,211, +48,52,169,40,249,34,159,249,10,224,32,41,64,45,22,139,121,58,151,249,45, +84,80,28,183,40,113,159,5,130,165,101,189,240,130,104,108,108,116,215,75, +128,130,35,16,130,242,211,53,216,212,116,168,72,158,51,116,238,207,27,227, +190,164,39,64,166,168,185,87,150,15,64,116,20,128,225,112,208,77,191,98, +71,47,92,5,124,220,5,118,20,82,0,55,177,226,0,164,172,12,118,177,125,4, +194,52,227,139,147,147,83,109,52,88,74,253,97,59,62,137,156,247,162,85, +90,66,36,18,27,139,238,173,0,68,176,31,198,126,48,163,200,127,104,84,243, +255,96,255,205,182,156,6,176,251,43,144,244,229,212,167,36,246,205,106, +255,36,196,176,169,253,53,171,1,84,185,253,19,96,0,249,4,138,17,171,4,193, +66,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_12 = 1507; +static unsigned char xml_res_file_12[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,5,133,73,68,65,84,120,218,164,87,91,104,28,101,20,62,51,187,155, +236,230,158,77,210,52,218,180,138,109,76,177,105,161,96,125,17,159,4,81, +4,193,7,171,40,98,193,82,237,139,216,168,120,125,200,67,40,105,107,131, +68,107,193,104,180,10,26,168,20,193,90,16,108,169,109,173,13,84,107,45, +33,109,18,91,55,27,211,53,183,221,77,246,58,55,207,247,207,76,50,89,102, +147,221,56,112,216,221,249,207,249,206,247,159,219,255,175,100,24,6,229, +62,146,36,145,203,35,189,127,244,216,3,165,126,255,235,146,236,121,148, +117,2,146,44,145,71,146,73,51,116,50,116,131,24,43,101,232,218,169,76,58, +125,176,253,165,231,47,177,141,225,6,228,244,41,21,66,96,111,251,91,53, +247,181,109,63,87,81,89,177,101,199,214,86,90,215,212,72,21,229,1,177,118, +184,183,159,246,189,184,83,124,159,79,164,40,60,17,161,129,171,67,52,63, +55,127,45,22,155,121,242,237,87,246,140,228,18,89,226,19,63,114,197,201, +165,227,96,207,198,15,191,56,110,92,25,188,110,184,61,29,221,189,174,239, +161,15,187,247,246,119,111,2,78,46,1,91,188,180,252,83,18,92,179,118,248, +161,29,219,168,173,117,35,233,186,198,98,26,202,178,76,30,143,135,210,169, +148,80,212,52,172,233,34,122,50,167,102,219,230,22,146,57,61,103,7,140, +27,188,236,103,201,184,57,144,151,113,238,233,250,168,175,179,101,195,157, +236,252,30,82,21,133,20,69,93,112,100,176,224,73,167,77,92,252,198,123, +172,67,15,250,176,131,253,161,163,199,142,2,175,88,2,126,191,191,172,125, +75,203,221,12,166,145,170,233,98,247,16,100,84,146,76,211,76,38,99,213, +141,44,34,109,235,64,31,68,182,114,228,124,190,210,23,120,49,80,12,1,249, +221,206,195,79,4,252,165,84,89,81,70,170,234,216,57,87,60,50,122,241,247, +63,169,251,211,126,186,183,117,19,29,249,242,4,253,122,229,154,72,52,214, +237,72,168,170,70,85,149,101,116,71,99,29,189,217,113,224,241,220,90,192, +147,175,6,60,89,69,169,107,8,86,17,183,156,233,220,42,78,228,216,195,180, +135,111,142,209,238,167,30,35,188,70,206,63,248,252,56,221,223,182,121, +161,70,236,98,67,157,0,167,58,88,255,44,191,58,145,91,11,249,8,120,171, +107,131,143,84,85,148,51,101,137,52,46,62,195,65,0,223,51,156,251,88,60, +206,107,58,121,217,137,146,85,68,183,153,17,176,116,17,74,214,175,175,173, +166,146,82,255,195,252,179,180,80,2,62,159,215,183,189,154,195,39,138,139, +35,96,56,102,4,156,128,64,34,153,100,2,220,74,28,146,108,54,43,66,111,138, +163,149,217,182,134,211,104,152,157,80,82,104,10,124,178,215,215,212,24, +172,225,208,235,166,115,199,124,16,17,200,100,41,197,131,71,51,108,2,138, +217,219,86,10,36,147,45,218,131,68,221,154,246,114,193,53,32,1,216,231, +21,253,238,156,94,72,9,162,128,29,39,82,73,107,38,72,156,130,172,136,185, +196,250,50,153,4,160,43,51,57,172,75,134,235,84,206,59,138,215,236,239, +249,44,18,137,76,81,137,223,79,229,1,63,5,202,203,24,204,35,114,106,14, +33,123,51,38,33,56,84,181,197,90,65,42,146,201,148,72,149,194,51,161,161, +190,150,218,247,60,215,200,75,255,58,125,230,157,132,94,175,143,246,237, +222,73,149,85,85,86,251,229,18,181,59,106,177,224,12,59,83,18,45,137,64, +60,22,167,254,31,206,186,251,201,71,0,173,151,97,230,82,34,41,118,108,228, +9,225,114,15,34,3,242,89,85,17,159,69,17,128,67,49,86,185,216,188,37,190, +85,19,80,185,56,53,71,106,10,39,192,165,43,177,13,162,32,123,61,171,38, +192,3,141,69,37,210,221,237,243,141,98,35,149,74,93,191,61,61,43,170,29, +206,23,123,188,112,129,29,236,103,227,115,148,100,60,183,11,74,62,2,90, +54,155,30,139,70,19,230,208,201,20,79,194,158,21,152,35,192,1,30,112,11, +37,160,78,69,38,206,128,57,170,153,163,177,170,8,192,14,246,192,1,30,112, +11,37,144,253,233,212,119,39,39,103,162,100,48,130,162,42,34,151,246,73, +183,242,238,117,161,15,59,216,3,7,120,192,45,152,192,173,191,134,167,230, +19,233,76,44,54,47,58,154,239,120,124,38,232,43,166,66,172,179,94,98,62, +33,128,96,15,28,224,21,67,0,77,155,137,206,76,158,28,143,76,139,218,193, +113,28,103,18,56,227,209,33,112,146,43,120,143,117,232,225,148,68,201,193, +30,56,214,41,168,23,115,35,202,12,92,56,243,73,104,124,82,40,73,214,92, +136,207,205,81,42,157,182,28,88,103,63,214,144,115,126,143,117,232,65,159, +143,0,130,61,112,86,115,39,76,95,60,119,122,48,26,139,142,142,132,38,112, +176,91,163,214,88,112,52,203,247,129,40,11,62,109,98,226,68,132,38,235, +143,132,254,33,216,3,7,120,197,18,64,197,206,253,248,253,183,175,14,141, +134,173,203,167,177,144,231,124,162,91,161,215,56,21,67,163,227,4,123,224, +184,117,192,74,4,176,225,196,111,3,23,174,134,67,55,191,186,244,199,13, +51,180,142,123,159,91,245,99,29,55,168,243,151,7,9,118,176,7,78,190,127, +73,242,10,211,20,247,172,153,222,158,174,174,112,56,252,243,47,151,135, +204,123,30,31,78,246,17,108,159,132,230,93,209,60,180,160,7,125,216,193, +222,194,41,234,62,176,228,114,194,82,205,178,126,215,203,175,189,209,188, +254,174,103,54,52,55,210,186,181,245,84,230,47,17,249,6,149,100,58,75,225, +219,83,244,247,88,132,198,66,183,190,238,251,248,208,1,182,9,161,19,115, +39,96,209,255,13,173,67,171,138,165,169,54,88,223,252,244,174,189,239,212, +212,212,61,40,138,109,225,252,151,120,228,78,159,255,166,239,72,231,236, +204,20,198,46,87,46,197,221,114,191,26,2,118,36,240,231,162,134,165,193, +34,228,205,41,90,56,156,100,137,98,130,187,205,254,255,67,192,25,141,128, +117,197,150,115,135,151,229,88,93,14,192,233,243,63,1,6,0,218,58,168,206, +121,36,62,30,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_13 = 1208; +static unsigned char xml_res_file_13[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,4,90,73,68,65,84,120,218,236,87,221,79,91,101,24,255,189,231,156, +74,217,44,140,169,43,180,27,236,131,133,176,121,163,55,38,91,102,116,134, +152,32,6,73,92,87,194,159,48,37,153,100,119,198,37,222,44,220,44,126,45, +49,222,120,101,128,118,174,96,182,185,155,9,8,154,232,197,62,162,110,67, +41,107,41,165,173,48,144,22,232,105,207,151,207,123,122,90,97,155,91,219, +128,222,236,109,159,246,61,231,188,239,121,126,207,215,121,126,135,25,134, +129,255,115,72,252,135,49,86,210,158,225,173,248,46,205,112,68,23,114,39, +4,178,225,105,134,177,151,147,56,74,135,106,201,0,138,93,219,221,115,202, +175,216,42,222,106,184,210,11,81,82,160,91,184,69,18,67,183,31,105,63,216, +165,72,242,234,224,215,190,190,99,197,2,97,60,4,69,120,64,58,217,115,106, +200,225,112,180,206,37,83,232,18,5,188,184,227,57,232,96,230,71,164,237, +63,207,70,241,81,98,30,162,166,64,205,102,47,7,46,156,111,47,6,68,177,30, +168,148,36,169,181,165,229,53,248,47,12,226,203,180,140,47,238,134,161, +104,26,52,18,93,37,61,244,111,35,72,146,100,131,166,40,173,124,15,73,234, +113,55,22,138,117,255,84,48,120,154,4,111,190,209,138,189,59,93,216,66, +86,87,104,42,236,186,134,74,154,215,108,221,130,237,53,53,60,24,72,36,226, +167,139,53,174,216,16,112,107,118,119,159,236,185,94,231,116,86,184,92, +181,168,174,222,134,84,42,133,229,212,10,82,203,73,196,227,9,204,205,205, +65,150,229,140,223,215,255,2,173,15,145,164,55,42,4,25,146,123,225,187, +83,189,132,248,131,240,244,52,185,89,133,102,232,208,117,18,30,10,235,63, +30,139,245,242,181,214,30,108,84,8,116,30,207,161,193,64,31,85,92,230,240, +161,67,168,117,187,32,8,2,68,81,52,133,207,185,210,177,177,209,62,43,246, +250,70,2,200,123,97,33,56,21,60,19,10,133,176,111,79,3,10,225,179,36,26, +141,158,225,107,138,181,190,84,0,166,23,46,125,51,52,112,253,218,13,84, +85,85,153,86,115,183,43,217,44,150,22,230,241,253,232,240,64,41,214,151, +10,32,239,133,164,32,242,109,235,19,215,74,228,100,41,214,151,3,128,91, +166,62,88,53,44,15,71,45,197,250,114,0,108,248,120,2,224,9,128,178,1,220, +95,8,198,127,239,1,182,6,5,169,47,147,218,253,91,55,148,188,157,93,231, +233,124,251,186,162,166,181,230,147,79,209,224,114,215,241,206,7,85,81, +232,88,65,106,105,17,142,234,26,232,180,198,176,92,196,44,11,73,199,80, +127,223,87,111,63,140,160,60,12,128,232,57,222,233,103,130,208,81,187,171, +30,142,237,207,64,167,102,195,168,243,9,217,12,116,122,236,118,30,247,96, +102,102,134,250,126,174,5,243,86,60,59,59,139,253,77,77,208,232,94,170, +40,129,145,8,116,239,229,133,123,136,71,166,137,178,233,1,223,128,73,213, +180,71,1,16,61,30,175,159,78,116,236,218,187,15,142,29,117,104,30,56,7, +231,79,183,144,36,179,174,157,253,24,44,189,202,41,23,188,4,34,153,92,194, +242,202,42,210,43,50,110,254,114,147,204,21,144,37,197,31,14,95,197,213, +111,47,99,254,165,3,184,227,61,129,212,159,49,68,166,130,220,21,1,159,175, +127,29,136,181,0,72,121,167,169,188,177,113,63,182,57,157,120,101,248,44, +118,255,62,9,226,90,24,191,1,76,156,251,28,130,156,134,97,81,177,124,15, +96,2,131,192,132,28,0,73,194,251,23,47,33,22,187,2,137,226,23,106,106,196, +200,171,239,225,47,242,214,228,228,31,22,136,127,60,145,7,32,29,243,120, +3,52,109,59,112,240,121,56,107,157,80,105,179,70,214,104,162,45,167,192, +208,32,42,25,48,174,152,199,217,200,231,62,203,127,97,16,24,221,12,129, +13,6,223,71,151,69,93,37,162,170,66,34,124,9,10,213,173,223,126,229,233, +113,145,88,83,7,207,137,60,35,170,164,214,218,214,253,238,59,184,51,49, +177,190,180,152,90,72,122,60,37,113,14,252,200,172,54,172,182,100,48,45, +55,163,155,48,91,78,77,67,189,27,175,183,28,197,39,159,126,214,150,39,173, +121,0,118,158,187,161,112,24,35,35,163,57,183,150,246,178,242,216,97,152, +94,51,96,183,219,97,213,137,125,45,0,198,99,24,137,68,224,118,239,220,212, +39,31,215,97,230,139,69,40,10,164,84,16,68,186,24,69,83,115,51,47,153,77, +81,78,165,141,137,219,183,77,93,247,179,98,67,150,211,63,44,46,226,240, +143,227,227,216,172,23,86,30,86,78,227,184,174,66,138,89,85,224,160,121, +61,201,179,37,190,47,150,51,120,86,207,147,76,243,28,40,148,161,149,149, +246,7,200,222,198,15,110,185,108,189,180,168,127,11,48,0,131,178,248,28, +75,223,85,170,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_14 = 2048; +static unsigned char xml_res_file_14[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,3,34,105,84,88,116,88,77,76,58,99,111,109,46,97,100,111,98,101,46, +120,109,112,0,0,0,0,0,60,63,120,112,97,99,107,101,116,32,98,101,103,105, +110,61,34,239,187,191,34,32,105,100,61,34,87,53,77,48,77,112,67,101,104, +105,72,122,114,101,83,122,78,84,99,122,107,99,57,100,34,63,62,32,60,120, +58,120,109,112,109,101,116,97,32,120,109,108,110,115,58,120,61,34,97,100, +111,98,101,58,110,115,58,109,101,116,97,47,34,32,120,58,120,109,112,116, +107,61,34,65,100,111,98,101,32,88,77,80,32,67,111,114,101,32,53,46,48,45, +99,48,54,49,32,54,52,46,49,52,48,57,52,57,44,32,50,48,49,48,47,49,50,47, +48,55,45,49,48,58,53,55,58,48,49,32,32,32,32,32,32,32,32,34,62,32,60,114, +100,102,58,82,68,70,32,120,109,108,110,115,58,114,100,102,61,34,104,116, +116,112,58,47,47,119,119,119,46,119,51,46,111,114,103,47,49,57,57,57,47, +48,50,47,50,50,45,114,100,102,45,115,121,110,116,97,120,45,110,115,35,34, +62,32,60,114,100,102,58,68,101,115,99,114,105,112,116,105,111,110,32,114, +100,102,58,97,98,111,117,116,61,34,34,32,120,109,108,110,115,58,120,109, +112,61,34,104,116,116,112,58,47,47,110,115,46,97,100,111,98,101,46,99,111, +109,47,120,97,112,47,49,46,48,47,34,32,120,109,108,110,115,58,120,109,112, +77,77,61,34,104,116,116,112,58,47,47,110,115,46,97,100,111,98,101,46,99, +111,109,47,120,97,112,47,49,46,48,47,109,109,47,34,32,120,109,108,110,115, +58,115,116,82,101,102,61,34,104,116,116,112,58,47,47,110,115,46,97,100, +111,98,101,46,99,111,109,47,120,97,112,47,49,46,48,47,115,84,121,112,101, +47,82,101,115,111,117,114,99,101,82,101,102,35,34,32,120,109,112,58,67, +114,101,97,116,111,114,84,111,111,108,61,34,65,100,111,98,101,32,80,104, +111,116,111,115,104,111,112,32,67,83,53,46,49,32,87,105,110,100,111,119, +115,34,32,120,109,112,77,77,58,73,110,115,116,97,110,99,101,73,68,61,34, +120,109,112,46,105,105,100,58,56,70,69,52,69,48,56,66,65,55,53,65,49,49, +69,49,56,57,68,48,69,57,50,68,57,53,67,56,68,70,68,68,34,32,120,109,112, +77,77,58,68,111,99,117,109,101,110,116,73,68,61,34,120,109,112,46,100,105, +100,58,56,70,69,52,69,48,56,67,65,55,53,65,49,49,69,49,56,57,68,48,69,57, +50,68,57,53,67,56,68,70,68,68,34,62,32,60,120,109,112,77,77,58,68,101,114, +105,118,101,100,70,114,111,109,32,115,116,82,101,102,58,105,110,115,116, +97,110,99,101,73,68,61,34,120,109,112,46,105,105,100,58,56,70,69,52,69, +48,56,57,65,55,53,65,49,49,69,49,56,57,68,48,69,57,50,68,57,53,67,56,68, +70,68,68,34,32,115,116,82,101,102,58,100,111,99,117,109,101,110,116,73, +68,61,34,120,109,112,46,100,105,100,58,56,70,69,52,69,48,56,65,65,55,53, +65,49,49,69,49,56,57,68,48,69,57,50,68,57,53,67,56,68,70,68,68,34,47,62, +32,60,47,114,100,102,58,68,101,115,99,114,105,112,116,105,111,110,62,32, +60,47,114,100,102,58,82,68,70,62,32,60,47,120,58,120,109,112,109,101,116, +97,62,32,60,63,120,112,97,99,107,101,116,32,101,110,100,61,34,114,34,63, +62,49,208,174,166,0,0,4,116,73,68,65,84,120,218,172,87,65,108,27,69,20, +253,51,187,235,221,117,226,54,174,104,84,33,176,4,103,206,128,196,141,208, +64,201,5,9,20,169,39,80,5,130,43,129,128,144,10,45,18,231,114,225,64,165, +74,229,128,138,72,56,112,129,150,166,81,185,84,2,206,185,35,153,168,66, +78,219,52,9,36,177,189,187,195,127,127,215,246,218,236,218,187,81,71,26, +77,118,50,243,230,205,123,127,254,140,149,49,134,148,82,148,20,123,101, +101,229,71,173,245,2,250,31,101,193,26,81,20,253,180,184,184,248,26,127, +6,253,5,71,198,249,90,169,133,185,23,95,162,200,68,143,148,128,86,154,214, +215,215,22,176,6,215,189,60,2,94,196,59,159,169,31,167,223,126,255,67,88, +167,212,57,82,129,146,168,207,63,247,44,69,177,170,222,56,2,188,90,44,189, +101,217,196,86,72,61,42,9,44,204,178,75,77,122,146,53,6,197,206,112,139, +39,70,100,219,54,57,142,67,149,74,69,90,16,193,6,210,177,209,35,54,218, +135,110,44,218,237,118,169,211,233,72,107,196,210,255,111,196,206,98,30, +69,134,9,88,228,251,30,125,121,233,18,123,183,206,138,88,20,134,17,213, +235,53,106,109,237,208,236,201,227,244,224,65,172,228,137,19,131,190,237, +237,61,30,171,121,108,72,115,115,115,244,254,210,146,44,14,204,204,216, +200,234,12,13,44,112,200,117,61,186,125,251,87,170,213,106,52,53,53,205, +106,248,116,227,231,11,60,194,145,214,169,120,82,211,125,24,131,177,152, +131,185,192,0,86,152,115,168,50,21,160,40,100,5,52,75,111,49,64,69,118, +47,214,48,223,99,51,247,136,133,144,214,152,88,210,161,62,138,227,6,227, +49,23,24,192,2,102,97,2,32,107,107,155,44,84,203,150,30,120,107,219,138, +54,54,64,202,150,86,128,185,12,247,197,49,128,184,192,92,96,0,43,47,171, +100,19,96,191,52,131,107,246,82,89,0,196,174,44,242,92,69,231,206,125,69, +199,106,158,180,190,87,145,241,233,62,207,141,3,22,129,175,44,35,24,192, +50,57,49,96,231,29,33,200,46,85,33,24,125,249,59,14,246,73,25,50,86,0,65, +184,191,127,208,199,161,50,10,8,1,222,5,42,118,224,87,171,137,175,197,11, +142,225,97,187,221,199,41,65,32,246,91,115,30,208,204,28,242,251,158,127, +36,2,15,213,142,96,0,43,206,25,166,132,2,72,40,73,60,184,158,39,50,2,36, +118,193,228,221,56,241,28,254,63,44,192,92,149,96,21,86,0,216,90,43,89, +16,187,152,159,63,77,183,56,17,185,174,43,89,177,209,104,80,222,77,9,130, +205,102,83,178,95,155,229,199,92,96,0,11,152,89,211,178,79,1,118,194,19, +130,48,160,143,62,94,166,79,63,59,207,183,153,162,151,231,95,21,59,198, +17,8,187,33,221,90,251,69,46,30,144,0,25,96,153,28,21,236,60,32,75,91,178, +80,208,9,68,202,106,213,231,108,22,74,64,102,157,5,213,207,162,113,194, +57,60,56,164,48,8,101,32,176,84,25,2,240,12,249,124,176,83,147,4,86,234, +194,201,189,253,82,193,204,113,203,226,199,27,42,74,0,32,114,13,91,86,159, +128,72,200,237,153,87,230,233,230,218,90,238,185,70,224,97,12,198,42,36, +160,100,81,57,85,90,103,90,55,38,15,88,67,19,32,231,242,242,7,82,39,149, +128,199,106,220,115,122,248,218,46,149,136,112,137,12,51,86,3,69,114,0, +123,255,71,196,35,117,143,190,27,10,17,232,37,28,36,160,178,15,33,149,146, +60,243,238,207,72,102,163,4,204,238,238,238,157,213,213,213,23,6,207,168, +236,124,15,48,60,90,208,6,236,61,44,50,99,30,178,24,7,236,209,3,164,70, +158,229,53,174,13,174,143,141,179,167,231,210,210,135,159,92,191,122,245, +10,109,223,223,58,195,223,221,73,161,193,245,30,215,230,184,71,233,65,50, +160,149,249,128,27,46,117,219,157,38,183,58,67,116,127,235,79,254,222,158, +244,70,69,122,72,214,200,181,32,72,216,237,21,241,252,159,238,52,237,180, +241,202,150,197,91,71,250,193,50,98,65,209,98,221,253,250,212,247,117,207, +126,29,222,118,77,180,57,253,230,230,211,5,108,200,37,80,185,248,249,23, +237,137,239,124,118,165,29,218,52,235,252,77,239,62,241,3,85,223,250,75, +250,247,191,121,146,46,111,190,65,173,238,41,114,173,128,20,77,254,89,119, +241,194,121,151,155,78,207,130,169,107,215,190,157,252,67,3,6,118,52,61, +243,120,68,239,189,163,83,199,79,211,205,27,215,105,227,46,191,29,42,17, +21,212,115,10,4,122,10,212,249,227,41,4,86,65,229,156,214,149,198,119,218, +88,51,114,71,168,240,225,236,219,205,179,37,44,64,204,72,224,246,45,72, +24,57,5,1,112,37,158,76,142,45,37,65,187,5,55,10,206,7,209,127,211,10,148, +141,29,39,33,92,73,190,59,9,96,233,32,252,79,128,1,0,168,254,212,85,21, +212,140,221,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_15 = 634; +static unsigned char xml_res_file_15[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0, +0,31,243,255,97,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0, +65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60, +0,0,2,28,73,68,65,84,120,218,140,146,205,107,19,65,24,135,159,217,221,144, +108,194,162,104,244,80,177,181,136,32,130,7,169,90,240,82,197,34,86,91, +47,90,68,122,240,31,240,32,166,135,10,122,18,145,106,251,23,136,246,224, +65,76,27,15,106,81,36,82,5,123,144,106,148,94,10,173,45,181,133,32,10,37, +181,77,52,217,143,113,38,9,82,37,196,188,48,187,204,204,251,252,222,175, +17,119,239,141,224,251,1,134,33,80,38,195,225,48,245,172,88,44,234,159, +8,2,137,105,26,88,122,23,4,129,22,145,61,221,167,89,252,178,84,87,96,87, +75,51,79,159,141,75,33,12,161,5,12,13,151,92,87,158,233,233,86,240,178, +22,71,136,218,75,223,105,31,237,171,25,205,90,190,239,39,47,246,93,192, +245,60,246,238,217,77,67,166,196,52,243,48,57,154,180,60,207,235,93,93, +91,231,249,139,151,213,91,249,63,186,252,237,58,121,2,205,234,12,40,150, +138,216,81,155,206,99,71,21,47,171,62,226,31,76,84,191,130,244,196,107, +93,2,129,95,41,1,183,228,18,181,35,120,234,112,42,243,241,79,189,149,108, +53,98,98,138,48,66,134,56,220,214,198,166,216,118,112,67,200,64,160,74, +240,209,34,145,136,77,110,109,149,120,124,107,85,160,18,87,245,154,144, +112,72,103,175,146,89,121,194,253,113,117,106,64,71,248,60,120,93,149,12, +116,55,99,177,40,179,179,159,55,192,58,186,158,115,148,169,31,215,200,57, +105,78,29,129,246,29,9,222,101,135,153,158,123,68,200,254,134,165,97,211, +178,112,28,167,188,254,110,182,138,142,195,131,76,154,227,205,176,94,128, +253,91,134,120,53,55,204,62,181,127,155,155,192,202,231,243,111,82,169, +199,29,82,202,26,253,86,181,7,14,102,11,28,106,234,231,96,211,157,242,249, +229,118,201,135,236,0,147,159,6,203,157,210,195,223,92,111,112,125,35,188, +63,208,10,5,23,174,119,74,110,164,5,209,16,76,47,128,117,243,214,237,249, +90,209,193,80,209,109,102,90,47,81,248,202,216,124,152,115,59,227,48,185, +56,128,165,220,23,178,240,115,133,148,85,247,205,72,83,141,14,198,18,36, +122,135,16,249,95,156,157,89,30,212,15,177,12,143,246,115,69,208,184,169, +182,177,109,195,254,187,90,75,162,118,250,141,219,111,1,6,0,80,239,219, +105,146,138,192,9,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_16 = 632; +static unsigned char xml_res_file_16[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0, +0,31,243,255,97,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0, +65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60, +0,0,2,26,73,68,65,84,120,218,164,83,61,111,19,65,16,125,179,187,103,7,131, +81,8,4,10,155,68,20,72,161,224,67,73,68,75,19,104,41,40,144,16,162,129, +34,5,13,255,0,209,210,128,132,172,132,134,6,148,54,13,66,164,65,66,162, +76,224,226,2,100,36,7,35,36,155,96,130,125,150,239,156,203,221,46,179,119, +206,23,208,32,143,116,186,189,157,153,247,102,222,204,145,49,6,131,152, +192,128,166,202,243,51,139,58,10,175,26,29,39,23,36,36,72,170,50,145,56, +199,95,251,163,169,127,67,132,109,159,178,201,231,103,159,1,91,81,26,36, +37,86,158,220,56,203,32,134,232,15,0,78,34,33,32,84,230,19,19,157,73,0, +140,214,156,188,137,176,242,16,198,16,156,194,53,76,206,62,231,230,250, +201,22,100,27,200,190,148,130,91,186,53,33,73,76,241,253,178,74,28,166, +203,142,3,236,151,136,214,95,241,197,203,36,150,24,196,196,26,65,199,239, +151,110,144,41,92,231,120,131,142,31,94,204,31,204,90,0,118,197,62,132, +51,196,71,105,139,220,97,214,172,75,229,157,139,160,213,177,44,236,225, +137,209,125,8,169,144,115,156,18,235,246,32,5,160,77,75,135,160,29,32,233, +59,165,67,109,165,130,209,177,17,28,191,89,2,18,145,77,250,88,191,147,129, +59,119,251,152,178,101,34,242,240,249,173,139,238,47,111,87,47,214,99,124, +234,52,142,20,142,98,171,250,136,171,214,73,233,22,64,230,138,8,197,4,154, +237,112,73,89,102,191,190,198,202,2,211,247,22,184,157,184,175,150,68,252, +181,4,109,120,85,40,147,150,159,0,107,6,24,71,235,227,42,190,172,247,94, +40,158,55,58,245,26,14,23,121,42,221,42,116,115,137,67,69,10,34,179,124, +218,187,107,172,3,49,211,208,33,252,172,186,184,243,248,195,98,210,66,187, +241,13,197,233,75,220,74,29,148,205,115,170,216,29,225,62,99,0,103,4,126, +99,13,223,27,205,215,171,243,51,158,178,65,193,70,11,185,83,39,129,94,139, +7,49,140,191,54,112,175,101,135,177,177,252,30,181,31,189,133,19,163,76, +230,206,93,246,120,96,121,29,197,176,75,101,118,54,230,223,102,139,50,36, +218,147,119,223,140,149,159,94,241,108,228,133,68,177,255,51,187,247,110, +186,91,3,254,206,191,5,24,0,171,203,191,162,234,194,67,169,0,0,0,0,73,69, +78,68,174,66,96,130}; + +static size_t xml_res_size_17 = 685; +static unsigned char xml_res_file_17[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,16,0,0,0,16,8,6,0,0, +0,31,243,255,97,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101,0, +65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101,60, +0,0,2,79,73,68,65,84,120,218,100,83,61,108,82,81,20,254,30,63,15,144,194, +98,52,154,70,156,28,108,73,140,198,166,49,52,142,226,166,198,196,132,142, +154,176,72,88,93,89,93,136,65,106,28,180,12,38,52,150,69,55,113,174,49, +93,52,8,117,176,46,98,26,45,196,193,247,158,240,248,125,158,239,218,71, +16,110,114,184,156,243,125,231,231,158,115,158,134,153,83,40,20,54,70,163, +209,93,199,113,130,174,77,211,52,219,235,245,110,102,179,217,251,211,92, +225,64,115,149,98,177,120,173,223,239,87,19,107,107,136,199,227,56,22,10, +77,136,157,110,23,141,70,3,239,118,118,160,235,122,50,147,201,188,253,47, +0,157,37,75,53,181,190,14,201,132,111,205,38,186,93,27,154,199,3,103,60, +70,40,20,196,217,88,12,82,25,182,202,101,58,170,32,12,224,97,0,102,78,165, +82,176,237,30,190,236,127,21,226,24,225,112,24,229,242,150,186,169,211, +78,156,60,242,221,234,60,124,115,34,145,128,215,167,227,176,221,150,108, +33,44,44,132,241,236,249,38,86,46,175,168,155,58,237,196,201,35,159,126, +42,192,112,56,188,183,180,188,140,118,171,141,160,174,99,65,50,110,60,121, +138,171,210,139,131,131,239,234,166,78,59,113,242,200,167,159,10,32,18, +32,56,26,15,17,12,6,241,168,240,24,215,147,73,116,165,220,197,197,51,234, +166,78,59,113,242,200,167,31,127,124,238,91,216,60,202,169,147,39,240,166, +90,157,157,174,178,187,156,233,51,9,224,247,251,21,152,78,167,17,8,4,224, +241,112,64,20,7,99,105,162,221,235,73,19,109,197,155,13,208,55,76,83,103, +121,124,207,203,237,10,76,211,152,171,32,18,137,226,246,173,155,240,249, +124,16,190,26,158,10,96,154,230,171,207,123,123,119,46,92,188,4,91,22,198, +248,109,226,199,225,207,185,0,167,199,242,76,201,206,105,212,62,126,0,253, +92,44,150,207,231,157,86,171,237,116,58,93,199,178,254,56,178,68,142,204, +124,34,212,45,203,82,56,121,228,211,207,93,164,102,189,94,207,84,42,219, +176,44,19,126,221,175,54,110,48,24,76,132,186,95,70,72,156,60,242,233,55, +105,98,169,84,122,193,187,215,235,21,87,87,175,96,105,233,188,188,57,242, +111,215,53,141,229,162,86,251,132,221,221,247,202,217,229,227,168,205,238, +137,138,156,203,229,114,15,162,209,232,13,249,175,79,97,125,195,48,94,11, +246,80,254,239,139,24,115,95,227,212,137,137,28,63,90,50,247,72,11,241, +203,45,123,250,115,254,43,192,0,120,74,65,201,19,184,212,222,0,0,0,0,73, +69,78,68,174,66,96,130}; + +static size_t xml_res_size_18 = 1971; +static unsigned char xml_res_file_18[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,7,85,73,68,65,84,120,218,156,87,123,76,149,231,25,255,125,215,115, +225,28,64,4,228,182,34,76,81,196,203,172,174,42,118,118,217,186,46,198, +75,170,105,154,213,206,118,107,27,99,155,45,157,201,178,196,54,248,135, +108,251,103,174,29,75,237,76,219,117,235,26,187,49,131,98,129,182,75,183, +214,86,165,245,194,102,13,181,5,122,40,194,17,116,28,176,128,192,185,125, +223,183,231,249,46,120,14,112,16,247,145,31,129,247,253,158,247,249,61, +247,247,19,48,203,103,245,238,154,116,247,220,226,39,116,81,122,84,135, +184,220,48,0,131,126,248,17,248,71,0,68,232,23,69,93,123,45,60,112,249, +149,243,135,158,30,158,205,185,194,173,246,215,237,249,83,169,232,203,174, +119,169,234,210,205,171,138,176,186,52,7,107,22,100,67,149,146,69,163,154, +129,51,95,132,112,46,208,143,166,127,7,17,137,70,91,245,27,161,251,63,122, +254,199,157,128,205,244,54,9,72,119,87,189,249,162,162,170,187,126,182, +169,2,91,87,22,65,163,197,174,235,26,122,71,52,140,68,245,164,151,253,170, +136,2,191,132,249,115,36,72,244,255,241,150,32,106,222,254,20,177,104,244, +165,83,213,91,159,162,37,237,118,8,40,149,251,154,46,175,89,144,155,95, +253,131,85,68,95,192,133,171,97,116,14,198,77,87,11,211,8,26,14,232,87, +105,150,130,111,228,187,160,107,58,246,213,182,224,124,160,191,239,244, +254,77,197,180,29,155,13,1,101,109,85,67,215,147,247,85,20,236,188,187, +4,29,131,26,254,211,23,6,157,5,145,149,11,169,89,59,4,116,130,36,2,43,243, +221,88,144,37,225,213,19,29,120,245,189,246,222,143,170,55,207,159,76,66, +158,106,121,99,247,174,123,151,228,61,68,202,155,123,162,232,30,138,129, +195,173,72,183,78,24,199,36,135,72,75,111,24,253,163,10,118,222,179,144, +188,97,20,136,66,99,247,233,253,155,239,72,36,33,37,198,188,114,111,221, +161,187,22,21,110,216,179,165,2,231,130,81,92,25,137,67,38,237,18,153,46, +10,156,233,22,68,81,36,88,153,47,36,172,79,236,155,239,88,24,142,232,184, +17,53,176,113,69,46,46,94,254,202,167,86,108,44,232,57,249,247,38,39,49, +29,2,194,138,157,213,139,50,10,74,254,88,243,216,122,74,50,157,226,29,131, +76,110,148,28,183,219,144,104,65,165,13,153,124,108,133,195,176,114,66, +152,10,209,6,147,112,209,251,247,86,228,161,190,229,202,157,25,69,139,254, +118,237,226,251,3,172,88,116,92,159,86,188,188,110,215,119,151,144,164, +136,246,129,40,41,191,105,185,3,137,44,87,101,9,245,31,180,226,153,63,52, +193,163,42,20,26,217,92,79,124,47,89,70,48,207,106,163,51,21,122,255,209, +111,151,193,87,188,162,142,117,78,16,40,90,187,53,219,227,113,151,111,164, +58,255,226,122,204,180,136,99,206,137,148,8,210,109,90,223,210,22,196,129, +199,215,225,231,47,52,192,235,146,104,77,48,247,38,191,239,192,201,159, +0,121,117,243,234,249,80,20,165,156,117,58,4,164,194,202,7,30,251,206,178, +66,68,168,82,7,198,226,166,219,197,20,144,236,82,24,167,184,86,255,112, +13,246,252,158,73,200,212,152,68,83,89,74,57,66,136,206,22,232,143,202, +242,60,20,145,78,88,252,72,214,237,223,113,103,105,46,41,215,233,197,169, +174,79,114,41,39,26,9,69,168,243,237,107,108,67,213,142,187,240,116,77, +3,60,46,133,14,74,29,14,62,147,101,89,199,202,146,28,72,30,255,14,214,205, +4,220,134,172,150,175,40,201,54,147,69,100,43,110,1,139,0,117,63,143,138, +154,247,187,176,247,161,181,248,233,243,111,194,227,182,194,33,73,41,100, +37,43,33,151,21,103,193,144,92,229,172,155,9,200,6,21,173,199,37,32,70, +29,68,18,82,91,239,128,159,24,21,81,26,17,240,121,93,120,165,57,136,170, +71,214,227,201,3,199,77,79,40,196,32,149,247,98,212,208,56,121,89,39,235, +22,97,85,146,217,189,132,25,98,159,8,126,194,26,149,163,170,130,134,20, +89,174,226,216,197,126,252,226,225,111,97,215,111,234,205,68,181,194,56, +73,214,44,120,3,126,159,236,76,39,65,78,236,163,188,200,117,158,170,227, +113,99,145,205,41,104,152,150,184,20,213,60,152,141,81,40,213,227,134,37, +233,148,158,110,76,109,213,146,33,36,205,70,57,113,83,38,23,104,130,145, +154,64,130,7,162,134,8,23,185,91,176,101,215,150,100,226,185,55,62,196, +95,246,110,163,10,137,155,171,162,48,149,128,64,139,253,67,209,9,29,38, +1,110,159,163,17,182,72,52,243,32,53,1,203,173,124,146,70,14,85,21,197, +148,93,146,151,134,131,181,39,240,250,51,219,17,166,49,205,30,113,114,101, +50,1,55,233,24,141,68,38,246,69,203,159,227,29,29,125,67,180,41,220,178, +2,36,187,119,198,13,217,140,127,113,118,26,94,175,59,129,55,170,182,211, +165,68,131,78,212,4,242,98,42,89,15,233,248,164,147,186,48,233,100,221, +124,92,60,28,234,110,56,219,214,11,159,34,204,162,10,44,2,154,40,99,94, +166,23,117,245,39,240,215,125,219,233,6,100,64,215,173,235,89,74,89,98, +145,70,13,248,92,123,31,198,67,151,27,88,55,19,8,7,254,241,242,225,230, +182,171,228,82,80,87,155,217,11,236,51,141,124,28,19,41,243,143,253,19, +71,246,147,242,184,62,163,229,14,124,42,119,80,141,166,226,0,2,239,188, +124,152,117,243,145,209,225,158,207,174,133,66,3,157,255,186,208,135,12, +234,237,220,205,36,187,110,147,192,217,65,86,110,88,118,7,142,29,105,194, +209,106,182,156,252,200,151,21,8,211,203,216,144,233,204,12,106,59,71,78, +118,64,143,142,117,14,145,78,214,45,57,213,161,141,13,93,26,76,95,188,227, +251,171,74,204,18,138,115,50,78,26,175,206,179,102,73,1,54,173,91,72,146, +84,53,186,117,55,156,110,28,39,194,71,134,69,40,65,15,28,61,143,206,183, +14,62,114,163,47,16,32,177,113,231,62,160,211,194,152,191,172,178,228,171, +152,186,248,158,101,243,204,154,214,141,233,73,240,58,223,7,38,174,229, +51,41,55,19,79,196,156,52,1,207,254,185,25,215,122,2,199,219,142,255,238, +53,18,187,206,169,52,65,128,255,233,61,219,120,33,190,240,190,7,243,231, +102,122,203,10,253,20,107,209,44,169,41,183,30,187,80,173,239,129,25,64, +158,116,211,156,206,240,10,120,177,241,18,90,62,15,14,124,124,224,225,31, +145,104,31,199,127,242,149,140,175,205,122,240,100,237,219,61,89,235,239, +47,204,201,244,46,46,242,155,106,204,54,61,11,55,39,221,156,72,185,135, +102,93,186,23,56,216,208,138,119,207,118,132,154,127,189,109,11,29,211, +67,24,182,141,78,34,192,254,140,242,156,185,114,170,246,157,96,214,250, +109,253,195,113,207,55,23,205,35,43,18,239,131,184,121,239,155,110,228, +82,104,92,212,174,211,168,154,198,194,26,126,121,248,28,206,180,118,15, +146,242,173,252,89,65,24,228,242,155,238,82,234,132,34,194,68,130,167,106, +155,198,178,151,231,159,234,24,41,203,76,247,160,226,107,62,107,204,38, +213,181,5,201,158,17,76,212,227,50,231,13,142,53,119,226,183,71,91,208, +213,254,121,211,153,231,118,238,182,149,135,38,95,203,83,126,152,16,230, +16,242,114,151,110,88,90,186,233,39,191,202,205,205,153,191,174,60,31,149, +84,1,165,121,126,202,234,155,51,133,15,225,86,254,201,151,131,248,248,82, +47,78,127,214,139,241,145,161,174,64,211,11,207,254,183,245,195,86,218, +190,106,39,93,236,182,62,205,8,20,65,204,37,228,120,231,22,206,251,250, +198,221,91,188,249,101,223,19,221,190,18,221,48,166,204,9,35,114,227,203, +209,190,246,119,3,111,29,106,24,27,184,194,117,222,79,224,219,239,216,237, +126,154,37,238,43,54,145,52,66,58,33,131,224,73,184,81,39,134,111,156,48, +100,39,217,168,173,56,246,255,126,156,78,231,17,149,7,154,61,69,167,251, +60,140,219,229,21,77,101,241,228,231,127,2,12,0,35,187,154,106,194,98,206, +112,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_19 = 2315; +static unsigned char xml_res_file_19[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,8,173,73,68,65,84,120,218,172,87,11,80,84,231,21,62,123,239,238, +178,32,225,189,8,136,32,136,202,242,168,10,212,166,81,177,106,173,113,212, +234,198,71,104,199,65,109,106,58,153,105,19,141,161,42,248,76,192,33,22, +147,49,38,169,157,56,101,242,176,81,81,48,157,198,180,77,194,99,81,164, +160,147,162,242,94,65,129,125,47,187,236,238,221,247,171,231,191,185,155, +172,136,200,180,189,51,103,118,247,222,255,254,223,119,94,223,249,151,7, +83,188,182,109,223,17,153,152,144,120,66,36,18,21,39,36,36,136,146,103, +36,193,180,105,211,128,166,105,144,223,187,7,61,61,189,178,147,127,120, +115,37,46,245,29,125,189,98,47,69,81,187,189,94,111,146,88,44,6,141,70, +3,60,30,62,240,122,107,237,14,199,1,92,215,143,235,252,100,95,222,20,176, +233,3,101,135,254,40,16,8,118,73,55,110,128,249,185,57,192,163,40,80,40, +149,208,218,250,47,252,84,65,95,95,95,227,123,167,79,237,192,181,134,242, +227,111,246,37,37,36,38,44,91,190,20,196,113,113,224,247,251,17,156,7,78, +167,19,250,251,239,193,215,245,13,160,80,12,103,158,121,255,189,62,66,130, +255,36,240,125,7,202,106,242,243,242,16,123,61,11,108,101,172,80,223,216, +4,178,230,102,232,234,236,172,100,24,203,112,179,172,169,5,215,186,223, +168,168,236,155,55,119,110,66,97,225,18,232,184,125,23,174,95,111,5,140, +4,107,241,211,227,33,55,59,11,146,147,147,224,131,179,127,238,193,245,34, +52,231,100,4,232,253,165,7,107,242,11,242,164,155,164,27,97,116,212,0,6, +163,17,26,16,188,183,183,87,255,86,213,137,45,184,70,135,102,70,99,246, +150,236,127,126,70,98,18,130,47,70,130,50,240,122,60,128,81,3,179,217,76, +60,134,174,238,46,104,168,175,103,131,78,211,20,217,63,108,50,2,36,236, +232,121,62,130,111,128,7,67,35,96,181,89,161,169,73,6,114,185,92,129,224, +91,113,205,16,9,57,154,11,77,24,17,17,113,148,132,189,227,118,39,11,78, +81,52,91,31,38,147,9,94,63,122,100,13,137,80,208,254,198,192,23,106,98, +240,195,53,63,44,40,144,110,122,110,3,220,127,48,132,155,140,1,133,121, +140,141,141,1,198,98,249,134,3,215,160,217,208,60,104,33,152,235,233,241, +113,98,80,171,213,108,206,41,138,7,124,62,159,45,62,188,6,209,238,4,25, +249,109,37,15,198,71,128,127,240,240,177,218,252,188,133,235,73,206,7,6, +239,99,8,25,112,185,156,224,241,122,97,235,230,77,64,83,212,186,136,200, +72,168,58,81,41,13,122,79,64,138,205,108,177,0,65,36,4,136,247,66,161,32, +216,99,237,68,161,30,31,129,80,30,143,226,192,7,17,220,132,213,235,0,167, +195,9,122,253,40,22,222,117,216,244,156,148,108,190,142,172,13,126,145, +16,224,211,124,182,173,190,5,231,179,53,240,164,70,163,198,21,93,117,126, +222,2,80,170,212,48,54,102,6,187,195,5,14,135,3,236,132,4,182,145,70,171, +131,175,234,27,89,48,174,138,191,187,188,30,151,106,112,112,0,226,177,239, +5,2,62,146,64,227,211,224,247,249,38,37,64,232,241,203,143,87,94,17,139, +227,215,166,166,204,132,140,217,233,108,222,195,195,195,17,216,9,46,52, +7,18,33,105,64,97,129,129,129,65,192,100,131,82,161,168,59,116,168,140, +116,130,23,45,118,247,158,189,117,69,69,69,75,163,163,163,161,95,46,103, +243,47,10,9,1,53,138,80,123,123,59,219,138,44,32,91,31,20,84,30,47,15,33, +5,204,231,194,190,246,197,95,239,100,23,212,55,52,193,32,134,159,20,79, +234,172,52,4,118,129,199,237,98,159,13,13,13,131,72,36,100,211,48,102,208, +73,159,162,125,231,119,151,30,218,246,70,233,129,51,171,214,174,95,58,111, +110,6,252,27,251,159,68,8,21,147,37,145,158,158,14,89,18,9,251,91,32,160, +65,165,84,195,229,186,186,1,174,13,89,2,66,139,197,212,84,115,169,118,153, +4,23,134,134,138,216,192,88,44,12,246,123,31,232,116,26,246,55,217,52,50, +34,2,22,204,159,15,183,218,219,32,43,39,27,62,14,95,182,57,230,200,231, +82,207,28,160,243,127,144,5,109,29,157,96,183,219,208,236,172,247,49,81, +81,236,123,108,129,162,30,116,247,244,64,119,119,55,234,193,215,123,131, +83,240,20,90,218,222,146,125,167,51,231,73,10,103,207,73,7,55,122,45,151, +15,64,111,79,119,125,91,91,235,37,1,95,192,195,40,248,211,82,102,110,217, +184,97,195,242,168,184,233,240,234,55,110,216,179,118,37,180,169,24,104, +31,82,65,138,91,5,175,102,248,96,72,163,135,230,235,45,138,200,200,200, +24,172,148,208,105,97,97,232,140,133,5,195,162,110,249,224,79,103,246,225, +215,7,92,27,187,120,92,43,70,161,165,32,137,183,103,207,206,40,76,78,78, +134,142,142,14,56,84,182,255,105,188,175,231,68,132,148,116,204,214,205, +155,143,245,46,218,181,230,183,207,46,131,187,58,59,168,25,7,184,253,20, +220,188,55,8,235,104,57,248,238,54,106,207,156,61,251,75,174,54,40,28,92, +225,168,13,86,78,47,76,28,112,64,192,252,52,153,94,68,18,201,141,27,45, +215,91,37,89,57,185,24,174,153,140,197,212,114,237,90,115,53,222,87,5,228, +54,116,69,113,140,117,197,75,85,37,107,22,195,109,173,29,84,22,59,184,125, +126,240,160,69,132,71,129,108,216,0,141,111,151,252,12,215,222,71,83,18, +242,12,195,40,57,13,208,112,210,109,10,86,197,224,38,37,100,162,209,146, +208,34,56,241,32,138,71,226,199,139,121,233,221,217,233,217,121,253,21, +235,127,12,87,229,70,80,90,28,44,176,27,253,116,251,121,160,192,57,17,230, +53,193,38,253,151,159,237,59,124,164,8,223,113,4,97,248,31,59,112,130,181, +132,11,11,195,129,147,48,217,201,253,152,223,188,147,134,224,242,242,245, +207,176,224,42,198,142,224,192,130,123,16,92,137,224,94,253,0,124,181,45, +27,36,146,121,153,179,226,197,153,127,175,111,168,157,12,120,162,8,76,40, +84,177,251,206,23,47,202,156,91,253,242,242,133,240,197,56,112,47,130,171, +113,78,120,12,15,224,84,158,0,104,158,15,126,148,191,0,118,254,181,15,218, +245,62,48,153,205,87,116,199,214,109,225,242,15,83,145,226,135,158,197, +148,156,219,190,124,126,78,117,217,179,11,225,106,191,129,205,121,48,184, +206,108,132,97,173,18,36,183,170,255,105,208,169,65,128,2,179,241,195,118, +24,163,34,224,47,219,151,194,178,121,105,27,227,14,214,93,28,23,233,199, +166,224,33,240,232,215,206,21,175,88,56,191,122,247,138,108,184,112,215, +192,86,187,215,255,61,184,222,108,0,165,122,4,140,31,150,21,221,110,254, +242,106,152,80,48,235,111,130,236,52,65,124,26,252,126,85,14,252,67,110, +129,95,44,72,6,181,213,43,209,73,86,229,218,100,23,46,77,148,146,137,82, +192,143,46,171,187,248,98,97,129,116,109,110,50,92,236,28,69,112,231,4, +224,195,96,188,80,249,188,237,78,211,77,174,224,18,231,190,115,227,230, +39,59,158,134,183,26,181,96,69,45,153,21,21,6,91,179,99,224,84,67,39,52, +118,245,215,233,203,165,1,233,126,108,4,232,232,210,218,154,61,171,23,75, +127,154,153,8,23,187,70,65,243,56,240,79,43,182,216,238,54,183,225,59,234, +64,167,240,114,86,20,92,233,181,166,122,169,112,32,135,30,135,219,3,35, +22,15,252,106,81,42,104,48,18,218,9,34,65,63,228,121,105,237,37,2,94,152, +17,15,53,232,185,198,58,49,184,179,171,165,194,84,255,201,231,28,184,147, +211,18,191,173,165,246,70,104,238,146,108,15,95,152,26,34,138,100,227,107, +119,77,78,34,64,128,22,151,213,158,221,245,147,69,69,43,209,243,71,193, +177,47,25,11,40,84,15,192,217,121,237,184,254,211,242,143,56,129,114,4, +121,67,72,184,153,27,159,181,134,228,44,145,184,105,97,170,48,244,201,36, +2,4,166,197,174,121,225,98,233,234,5,88,112,193,224,126,214,115,6,15,36, +35,202,1,112,220,145,85,232,207,31,255,152,3,183,143,43,170,239,20,117, +50,18,47,32,9,173,205,39,209,103,175,206,179,54,157,175,9,180,161,104,142, +56,10,31,224,206,152,243,111,91,237,123,240,251,35,253,224,54,168,101,8, +126,142,147,88,43,7,56,254,242,6,20,84,117,114,231,30,70,209,35,211,106, +135,193,138,194,107,69,37,24,54,57,224,114,183,17,74,86,101,225,31,2,1, +123,170,10,16,160,212,22,27,80,56,150,8,56,177,96,112,207,168,74,166,170, +218,254,10,151,243,199,129,79,74,194,134,36,108,72,66,201,184,224,149,218, +91,192,99,140,77,100,192,5,82,16,198,43,248,249,150,172,153,113,81,26,59, +31,156,184,133,25,143,225,67,138,123,168,114,170,102,213,201,29,123,112, +205,48,55,148,188,83,248,55,229,127,36,29,252,144,84,81,88,52,178,26,130, +17,121,167,76,83,85,252,50,62,31,13,232,0,38,10,50,18,202,46,215,242,68, +97,41,120,162,102,143,78,94,237,240,23,170,83,187,14,114,67,201,56,69,112, +152,96,192,165,36,190,246,209,105,161,56,249,25,151,110,164,69,85,85,252, +59,110,207,177,0,1,50,235,99,209,102,112,147,144,226,70,166,145,43,184, +177,201,244,124,138,36,2,83,214,204,213,17,235,80,176,18,10,184,115,154, +144,83,72,31,215,102,246,255,194,243,71,212,149,59,198,11,56,199,236,255, +131,67,255,223,235,63,2,12,0,116,106,129,252,126,87,16,179,0,0,0,0,73,69, +78,68,174,66,96,130}; + +static size_t xml_res_size_20 = 1468; +static unsigned char xml_res_file_20[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,5,94,73,68,65,84,120,218,212,87,77,104,92,85,20,62,231,222,247,230, +39,127,77,155,212,68,44,149,86,208,218,85,68,65,65,220,9,110,2,34,6,2,186, +21,187,48,232,50,139,18,127,87,217,41,214,133,226,74,16,41,84,170,224,194, +133,186,178,162,168,52,85,169,26,109,193,159,226,79,27,90,51,201,76,242, +230,189,119,253,206,185,247,205,76,166,147,52,162,37,248,224,204,251,185, +239,221,239,156,239,124,231,220,59,236,156,163,157,60,12,237,240,193,225, +28,61,247,202,241,19,38,138,30,116,249,245,101,132,13,83,158,166,239,62, +243,196,244,20,110,83,113,32,154,123,233,205,147,142,205,228,29,19,135, +40,119,57,145,187,126,225,26,54,180,176,240,29,48,242,247,94,120,234,209, +135,34,60,174,146,177,147,71,103,166,41,15,148,240,38,223,255,91,191,138, +239,31,184,111,130,230,143,29,159,20,108,113,160,146,103,57,101,184,152, +121,246,85,170,196,134,44,247,128,10,98,237,212,172,11,63,174,219,193,94, +207,112,228,8,173,153,57,122,113,238,8,229,185,132,75,21,113,0,112,142, +224,3,13,247,87,232,157,218,221,84,142,193,129,101,16,35,156,89,114,198, +80,100,97,17,195,44,197,150,245,58,70,62,45,44,130,148,229,147,8,207,99, +204,134,33,10,83,224,218,81,76,254,58,135,247,249,226,251,148,102,174,136, +132,35,245,12,55,73,211,81,181,98,169,212,32,42,151,128,43,245,97,165,78, +156,90,28,57,239,128,117,100,173,128,193,228,185,56,192,222,9,1,43,64,35, +61,195,16,156,140,177,0,58,67,165,178,5,86,170,152,170,254,130,87,121,88, +142,99,253,202,96,98,70,196,234,5,0,12,102,80,19,86,48,110,49,38,145,131, +28,98,128,139,178,25,160,108,124,93,27,46,204,225,30,99,112,66,127,49,40, +24,130,229,58,29,144,155,117,60,44,149,34,76,98,240,162,211,73,41,56,97, +108,48,56,193,197,181,101,29,182,198,159,11,64,248,227,133,44,215,10,44, +247,185,8,0,44,24,197,16,44,71,157,14,64,16,45,6,36,6,165,221,207,42,128, +12,206,57,242,76,88,92,155,160,15,31,57,249,200,55,68,45,179,56,189,182, +228,169,247,202,100,42,1,163,9,44,242,34,244,14,228,36,41,200,212,59,215, +226,176,35,250,200,159,213,25,101,129,149,169,34,122,205,185,9,162,147, +156,147,215,130,13,226,115,89,81,49,76,101,209,64,210,67,3,235,73,19,222, +217,206,80,20,68,41,215,124,123,39,172,86,131,156,89,77,128,27,41,0,49, +95,228,252,89,202,216,186,66,191,190,10,134,74,70,115,83,46,197,26,236, +85,26,80,6,36,5,28,90,17,120,21,138,141,41,64,1,8,180,4,228,214,209,64, +147,38,204,5,38,29,107,16,218,198,241,192,73,77,139,165,169,94,187,44,67, +251,117,180,150,228,52,119,168,16,33,117,59,0,13,148,35,47,27,113,66,51, +224,105,206,97,171,25,0,145,58,103,125,122,216,122,150,164,18,100,54,41, +51,161,186,221,78,157,6,161,41,197,181,180,186,102,102,168,2,12,193,162, +78,6,242,162,10,10,6,216,151,151,36,80,162,204,82,159,204,34,255,146,120, +14,34,245,45,206,169,144,185,104,149,204,109,11,1,105,185,34,60,17,250, +58,38,204,54,166,128,60,3,34,66,237,79,254,67,233,88,210,170,184,115,194, +194,138,50,85,0,15,174,121,149,231,121,251,61,57,57,166,86,96,34,244,36, +201,90,77,218,139,16,222,11,3,67,240,78,216,200,240,69,232,148,202,228, +198,198,206,109,135,148,127,14,81,183,149,222,122,215,21,203,8,147,202, +3,239,9,203,43,107,169,50,214,102,32,148,161,197,218,84,111,226,69,163, +65,105,36,82,255,26,145,36,51,24,171,232,108,27,12,185,133,215,228,82,167, +103,74,77,16,33,171,57,29,35,4,9,210,98,52,162,90,87,39,244,26,200,200, +196,85,90,56,50,164,77,132,91,171,154,243,202,114,235,87,47,121,189,246, +54,220,113,207,30,130,165,51,176,95,13,191,189,144,64,204,181,141,14,112, +96,241,204,143,75,180,176,120,105,147,149,223,181,151,98,215,181,159,234, +186,87,9,245,220,85,248,238,89,145,213,206,191,164,14,184,122,109,249,212, +233,207,62,185,183,200,139,219,12,92,150,83,88,95,165,76,171,245,181,98, +14,29,235,239,171,80,125,109,29,26,108,139,175,219,9,110,109,203,12,53, +86,150,79,21,138,25,132,237,135,141,182,68,217,227,232,27,24,172,206,206, +191,254,118,29,253,234,206,137,91,233,252,111,75,27,198,15,222,56,66,11, +103,22,169,140,94,53,63,251,216,195,245,149,90,99,139,205,145,20,182,80, +253,51,7,208,170,236,78,182,216,141,149,158,126,249,173,95,108,127,63,101, +16,215,61,119,29,166,189,131,125,173,148,72,180,23,107,117,250,244,139, +179,218,53,179,149,149,228,249,39,31,185,5,67,201,22,187,179,53,88,35,10, +222,212,130,109,118,236,78,154,77,186,125,223,24,213,86,27,244,195,185, +95,105,177,235,255,132,148,230,13,163,195,180,123,112,128,190,254,234,44, +146,76,43,176,43,215,218,39,70,219,220,79,198,105,51,205,15,140,237,145, +69,129,46,47,175,82,35,73,54,48,80,45,149,104,116,215,0,165,112,244,52, +222,21,214,182,51,177,221,166,3,165,218,242,229,207,235,102,104,58,130, +138,111,59,112,19,29,62,184,143,110,30,223,3,27,161,253,227,163,152,40, +167,111,190,63,79,31,125,252,37,125,120,242,141,169,63,47,252,116,46,208, +188,173,63,38,215,58,202,176,49,17,235,212,227,179,51,195,163,227,247,71, +113,60,210,73,1,34,95,186,114,233,247,15,78,188,54,127,76,196,5,251,3,182, +254,95,57,192,129,210,97,216,94,216,174,224,84,103,39,16,176,191,96,23, +67,238,147,237,252,149,224,127,248,223,194,134,106,41,247,208,79,26,156, +16,218,51,250,191,28,188,211,127,207,255,22,96,0,113,192,97,41,118,79,50, +219,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_21 = 2051; +static unsigned char xml_res_file_21[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,7,165,73,68,65,84,120,218,156,87,125,108,85,103,25,255,189,231,227, +158,123,123,251,129,165,45,216,58,235,112,165,104,132,208,144,97,34,211, +12,199,88,2,24,166,76,103,166,243,47,157,157,78,99,252,136,35,200,76,101, +113,97,14,51,201,22,182,37,115,38,186,153,45,51,196,101,76,145,5,134,5, +66,183,21,16,18,217,40,116,163,31,72,75,139,180,183,189,31,231,158,15,127, +207,123,206,45,183,176,10,235,73,159,158,243,190,247,61,239,243,123,127, +207,239,121,222,247,40,204,238,178,58,158,124,241,101,195,180,214,135,97, +120,221,47,41,165,16,248,222,95,127,249,253,187,239,98,211,211,125,179, +113,254,208,246,23,118,134,202,92,183,100,73,11,130,48,0,174,7,3,61,25, +202,192,241,227,61,80,161,255,234,175,126,120,207,151,75,32,62,236,85,181, +249,137,23,67,159,75,207,185,126,56,89,240,174,219,100,188,188,39,239,203, +60,122,53,179,0,144,12,124,31,110,209,199,190,99,189,248,16,17,96,8,128, +149,75,23,64,222,151,121,104,153,217,0,80,18,119,113,44,19,126,177,109, +65,212,27,78,253,155,241,218,123,236,61,248,65,200,176,133,83,225,183,102, +37,65,121,223,48,144,176,44,108,123,249,128,22,87,105,198,176,4,164,140, +26,121,10,232,120,121,235,13,116,142,105,191,89,211,84,109,81,213,193,181, +57,149,21,60,242,212,75,250,217,160,115,21,243,43,119,59,149,66,162,234, +35,116,24,160,148,33,97,137,25,21,70,253,229,138,22,219,252,187,231,119, +22,253,96,93,219,226,5,215,165,234,16,229,116,171,169,84,82,134,194,209, +35,39,81,147,78,162,117,225,141,240,253,203,32,228,146,182,23,78,239,19, +0,41,24,230,186,77,15,220,13,145,134,49,203,194,16,198,118,199,45,109,216, +242,219,63,226,123,95,91,133,162,23,148,209,173,176,231,200,41,4,94,120, +21,128,164,32,227,80,252,160,227,25,36,19,6,204,56,152,83,225,68,89,187, +44,132,83,109,78,46,145,43,250,33,182,109,188,79,139,97,235,75,157,154, +238,210,123,18,182,101,45,141,154,225,43,1,168,144,3,11,69,160,182,42,133, +191,140,180,33,149,80,112,28,19,182,99,83,104,10,137,132,5,155,168,18,52, +155,109,155,52,137,113,24,108,26,49,211,167,129,244,217,61,4,225,67,17, +141,101,88,8,149,196,59,90,156,138,181,229,249,87,3,128,12,43,184,30,210, +41,113,200,152,36,13,56,52,155,179,59,244,100,90,145,99,13,192,136,1,208, +177,101,134,176,57,151,101,68,43,76,37,109,20,10,30,29,152,88,126,211,39, +53,3,174,114,225,154,17,237,158,235,106,13,148,107,44,202,2,14,204,187, +62,233,183,161,108,19,166,99,192,146,123,194,100,91,0,208,76,3,6,65,24, +4,192,63,138,62,212,119,131,119,165,57,134,126,95,22,98,4,9,60,81,152,7, +145,192,183,43,70,176,246,201,109,116,234,99,103,123,59,139,16,62,128,1, +118,20,138,46,146,164,156,169,168,29,26,182,69,51,35,147,182,24,25,32,14, +173,17,185,147,100,88,2,68,138,139,167,144,36,3,121,2,8,248,251,200,33, +106,66,184,191,221,196,249,87,30,137,116,115,255,253,4,21,76,223,88,74, +50,202,83,4,78,34,193,85,27,218,169,178,204,8,12,159,45,75,194,97,68,33, +48,37,246,12,7,29,123,158,199,204,97,152,18,146,62,33,42,28,135,11,41,178, +218,229,177,249,214,33,29,111,183,152,65,215,238,65,2,8,96,20,178,188,251, +31,192,128,136,208,45,234,21,24,6,29,27,178,98,83,135,193,74,68,119,143, +78,71,93,32,199,52,26,203,121,90,84,97,145,241,38,136,128,171,206,231,129, +205,139,146,96,152,17,6,228,38,84,58,169,109,134,195,116,165,252,250,4, +102,144,41,92,85,136,52,162,60,197,227,48,134,6,185,213,113,167,89,100, +32,235,43,12,184,138,0,12,93,104,36,224,182,163,68,206,58,221,196,79,192, +127,62,199,85,166,230,224,244,249,127,226,52,30,196,67,127,235,67,57,219, +139,26,150,98,121,243,79,208,210,180,129,176,172,43,53,0,198,142,12,144, +75,17,154,69,6,24,89,12,23,200,140,178,160,36,44,4,35,236,136,152,66,229, +151,10,60,65,113,172,73,214,204,36,222,62,119,31,222,189,180,11,107,62, +255,85,44,110,254,49,69,89,161,199,229,220,44,78,156,61,128,87,187,239, +197,80,110,55,157,110,184,50,11,124,166,79,81,51,32,69,165,64,170,38,115, +76,78,198,94,113,181,161,172,158,78,124,10,19,92,169,222,47,152,227,236, +212,21,142,249,131,134,226,122,156,207,239,197,198,13,219,209,63,246,38, +254,209,179,9,67,19,147,122,250,121,149,105,124,102,254,157,216,116,215, +118,108,127,237,103,204,156,225,41,0,70,137,129,44,227,104,147,129,12,87, +61,144,241,144,41,42,76,80,217,25,207,64,198,143,173,24,183,99,155,96,60, +39,61,178,230,238,67,163,243,58,218,215,252,26,157,103,31,69,87,255,159, +112,49,55,137,29,235,67,109,242,220,213,255,60,14,244,61,138,7,214,60,12, +55,253,6,110,254,14,22,11,122,171,180,91,21,40,40,187,198,65,231,183,210, +48,74,149,61,20,170,179,151,171,125,88,218,197,227,237,151,33,177,140,20, +182,254,253,97,180,54,127,29,71,207,253,1,163,217,1,93,152,92,53,253,32, +34,125,242,219,177,115,207,97,237,178,123,241,194,165,103,59,248,83,167, +21,159,48,168,169,16,199,123,47,226,95,167,71,167,85,249,255,119,226,49, +24,2,75,85,227,112,239,97,220,122,115,27,246,191,255,14,43,29,163,196,232, +184,101,2,148,103,51,136,106,71,127,230,223,88,121,227,42,10,29,43,100, +35,20,0,225,196,196,248,193,163,93,135,86,132,165,189,122,106,35,138,78, +47,21,73,7,147,217,124,124,226,0,210,21,73,100,243,5,50,69,241,161,26,102, +10,24,206,119,235,154,255,155,213,87,35,222,241,165,203,125,15,190,174, +40,196,183,74,91,184,84,126,228,127,191,245,231,223,229,189,174,236,128, +162,62,119,219,186,214,213,95,249,230,182,156,175,156,101,75,23,162,247, +63,163,83,147,44,248,232,92,116,31,59,133,234,36,247,253,79,124,10,39,187, +129,9,183,79,211,124,173,75,88,144,177,49,0,173,129,28,173,143,54,92,118, +76,79,174,186,243,27,123,84,170,2,14,249,172,172,74,227,182,198,250,169, +115,224,133,76,22,78,202,129,71,13,156,236,233,213,125,151,242,231,185, +139,178,24,237,83,186,4,231,41,208,199,239,136,86,254,163,221,44,211,86, +180,131,202,152,177,252,32,226,83,156,94,177,156,205,51,177,149,174,90, +151,37,245,211,31,155,135,241,201,28,122,206,12,224,84,153,24,228,12,216, +80,55,7,213,233,52,222,57,209,143,133,13,43,48,122,241,32,230,215,71,43, +20,13,24,101,108,84,208,105,133,29,239,31,204,220,225,11,220,39,178,56, +34,1,157,233,80,106,121,172,116,77,245,53,104,110,170,199,232,216,164,174, +241,165,44,112,108,27,115,107,210,80,92,234,9,175,7,222,224,74,156,153, +56,136,198,6,6,213,142,138,164,83,54,25,247,56,72,9,17,231,178,115,158, +121,15,24,236,198,227,162,79,115,6,0,78,117,109,253,133,75,185,112,117, +37,227,188,248,166,38,44,108,110,68,243,252,90,90,29,170,28,11,167,201, +202,222,67,221,120,243,141,93,27,119,62,179,227,177,186,69,168,25,47,48, +27,155,232,200,138,118,204,253,125,29,232,28,232,0,183,24,13,76,72,57,252, +54,211,177,15,175,188,245,28,158,102,243,191,51,125,154,81,215,104,156, +219,208,216,178,230,158,246,95,84,206,153,187,34,58,45,71,20,72,8,38,198, +70,14,190,246,231,167,183,140,14,157,123,95,132,44,97,251,194,79,177,165, +238,6,172,109,109,97,245,155,23,1,209,167,32,6,121,104,8,120,183,135,206, +251,177,107,255,99,216,200,238,179,18,246,153,0,8,88,97,177,150,70,98,153, +107,211,191,33,68,55,227,177,112,47,198,109,249,212,106,106,185,29,183, +124,252,179,104,79,84,99,73,217,193,25,238,56,142,247,117,225,169,158,61, +56,192,158,65,218,24,116,97,191,198,135,104,204,134,115,197,129,89,82,190, +16,103,80,233,3,83,194,153,142,65,75,74,87,198,125,250,68,78,155,160,141, +196,128,39,227,190,89,125,29,95,227,27,24,118,12,58,81,54,191,112,225,198, +128,139,229,223,112,255,19,96,0,111,126,151,122,57,77,224,198,0,0,0,0,73, +69,78,68,174,66,96,130}; + +static size_t xml_res_size_22 = 2007; +static unsigned char xml_res_file_22[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,7,121,73,68,65,84,120,218,172,87,13,108,85,103,25,126,190,239,156, +115,127,90,74,41,163,180,182,118,115,117,64,21,232,214,176,117,70,22,163, +27,209,17,152,110,254,85,97,63,49,76,129,110,26,166,38,58,38,234,28,209, +204,13,19,204,36,203,100,66,54,49,25,3,231,72,97,108,83,144,159,110,176, +78,91,58,129,149,50,170,164,98,88,215,206,246,246,254,157,191,207,231,59, +247,220,114,239,150,74,169,158,244,237,119,207,189,231,156,231,125,159, +231,125,191,247,61,2,147,59,204,7,127,245,204,14,105,152,159,83,74,77,248, +38,33,4,124,207,125,254,71,247,180,124,145,167,110,240,221,100,192,127, +248,203,223,61,167,132,177,180,177,113,22,124,229,3,19,241,129,72,82,72, +116,119,247,66,40,175,237,39,223,90,118,91,222,137,75,61,202,214,61,246, +140,242,24,122,218,246,84,50,235,78,216,244,245,250,62,125,191,126,78,16, +205,36,28,136,249,158,7,219,241,176,191,235,12,46,65,1,74,0,124,234,154, +122,232,251,245,115,104,137,201,56,32,180,238,26,88,63,240,198,166,250, +220,183,106,236,223,184,199,190,174,62,120,190,162,108,106,76,126,115,82, +41,168,239,151,18,17,211,196,134,29,135,131,228,202,63,81,229,29,41,160, +70,127,242,9,220,60,167,142,224,40,250,205,44,202,106,147,89,237,95,156, +83,29,193,207,30,223,30,124,150,4,23,33,191,122,181,226,113,68,202,42,8, +232,35,95,33,42,207,140,80,185,239,11,51,90,219,186,141,219,158,115,60, +127,105,211,252,250,9,101,181,66,33,221,98,172,148,132,20,232,252,235,73, +148,151,198,48,103,246,149,240,188,11,78,232,195,37,184,11,85,148,55,218, +129,56,164,177,244,129,123,91,160,83,67,78,114,99,80,161,125,230,134,38, +60,244,139,167,209,250,229,69,112,92,63,160,91,137,128,42,188,212,245,22, +60,189,23,200,98,9,98,218,83,94,138,111,62,248,4,98,17,9,35,20,115,76,78, +20,156,23,72,56,118,78,14,180,114,142,167,176,225,254,111,4,201,240,240, +246,67,1,221,250,87,159,160,14,35,107,57,105,99,112,215,105,216,149,162, +200,1,161,120,97,214,1,166,151,197,177,243,157,38,196,35,2,209,168,1,43, +106,49,209,4,34,17,19,22,189,138,208,44,158,91,124,152,54,94,6,139,70,159, +137,41,81,250,143,151,233,132,7,65,111,76,105,50,242,156,222,158,65,240, +19,89,148,92,61,23,163,201,36,86,188,113,12,27,67,7,2,198,245,101,89,219, +69,105,92,3,82,147,152,68,60,78,139,10,148,240,115,52,112,40,52,43,52,237, +72,132,14,240,122,22,3,132,161,120,159,133,108,150,42,43,3,205,87,125,24, +215,210,154,174,170,67,109,170,15,123,171,123,145,30,73,33,53,154,194,112, +85,29,58,214,108,57,79,232,72,174,10,200,64,198,246,72,191,5,97,25,48,162, +18,166,94,35,6,207,41,137,73,51,36,36,65,37,181,228,31,147,94,5,171,228, +42,130,58,67,112,191,14,68,168,8,54,218,85,176,249,221,151,122,118,226, +218,230,102,148,79,159,138,205,79,109,193,205,114,17,50,233,12,34,118,86, +35,151,202,124,89,101,29,27,49,82,206,82,36,160,9,105,105,51,194,149,22, +201,173,134,118,44,112,206,12,156,212,38,233,160,144,6,98,100,64,7,226, +9,19,231,142,0,63,255,253,92,68,167,76,195,148,242,105,232,61,117,26,85, +21,51,240,236,200,31,80,221,223,131,235,55,173,250,88,193,62,160,144,97, +18,68,35,17,62,88,6,192,194,52,114,206,104,16,2,88,100,34,200,1,67,107, +207,124,96,216,174,235,178,114,40,71,36,39,102,60,26,69,146,91,116,146, +140,60,126,238,35,104,104,253,2,26,106,106,241,216,182,131,48,156,81,156, +60,126,130,82,1,91,230,6,109,96,128,150,52,115,10,48,9,109,39,136,64,50, +18,41,53,221,185,232,204,72,110,117,9,58,104,3,105,87,97,56,237,6,137,166, +28,234,77,39,124,210,158,201,10,220,223,80,130,17,219,192,138,129,251,208, +216,122,7,80,253,53,224,149,31,227,94,119,59,214,252,125,29,88,36,248,206, +218,245,216,180,117,135,134,29,165,217,102,174,172,52,3,46,35,161,3,212, +58,208,157,102,146,129,148,39,208,111,11,58,32,131,141,70,11,110,49,25, +225,122,65,185,233,26,247,249,47,235,243,250,248,52,204,120,114,30,22,172, +190,157,224,43,8,254,16,112,170,77,103,40,174,62,191,25,149,173,251,144, +78,167,243,205,168,160,10,232,89,70,51,64,46,117,162,153,100,128,41,134, +183,179,62,6,8,238,235,4,164,230,134,150,136,121,160,229,17,134,17,56,164, +181,119,140,40,82,178,20,205,127,92,146,3,255,192,215,129,87,53,248,174, +160,229,111,58,82,131,219,158,124,11,118,54,9,155,201,151,219,31,10,123, +129,239,177,124,156,128,1,189,169,232,104,146,105,22,167,78,46,70,171,116, +244,4,244,116,205,145,145,160,95,72,62,132,181,238,144,129,97,21,195,129, +115,245,152,189,242,46,70,174,193,215,135,224,14,193,171,209,178,245,77, +188,120,224,13,152,194,99,222,120,69,219,243,24,3,41,234,104,145,129,4, +163,238,79,184,72,240,201,163,174,64,194,149,72,120,161,57,225,121,96,6, +134,61,11,67,254,20,236,239,187,8,248,190,46,220,188,112,62,244,134,231, +49,88,37,138,123,65,208,173,178,76,40,171,60,138,67,119,150,66,230,119, +118,69,173,84,234,194,110,175,242,93,92,192,147,22,183,215,82,12,255,244, +114,204,94,125,231,123,192,73,251,209,106,124,133,224,123,254,212,137,37, +159,104,194,158,63,191,198,156,50,130,6,245,190,118,204,9,131,57,165,208, +125,102,8,199,78,15,22,237,242,239,159,120,152,144,48,144,33,237,139,95, +93,130,235,90,239,10,53,15,193,165,135,39,94,171,193,242,45,199,177,123, +127,23,110,249,100,19,215,163,184,229,198,235,241,194,193,215,137,83,220, +33,181,3,106,116,116,164,189,243,232,43,11,85,190,87,143,53,162,220,244, +82,18,99,125,167,50,65,207,247,9,46,153,237,171,254,189,22,77,247,104,240, +187,139,192,55,191,94,139,211,205,143,224,197,67,212,156,174,238,61,208, +17,236,162,123,184,234,161,212,11,230,132,98,9,50,191,121,248,123,43,185, +206,40,24,80,196,199,111,90,58,231,211,159,191,125,67,218,19,209,5,215, +204,198,153,127,13,6,229,228,200,24,62,219,209,130,198,85,203,73,123,49, +248,175,59,106,80,118,119,27,154,157,4,213,179,115,114,9,81,48,122,171, +160,89,189,151,129,52,237,44,237,237,130,49,61,182,232,214,229,47,139,120, +9,162,164,108,74,89,41,110,170,153,201,182,106,97,176,251,121,76,93,244, +85,160,238,219,192,1,90,239,110,130,171,32,242,169,43,218,96,216,9,102, +181,29,200,90,56,172,92,120,47,240,195,223,46,56,160,103,243,68,104,249, +99,186,237,56,248,232,7,171,48,146,76,163,247,76,63,78,41,210,39,163,104, +28,232,192,135,110,125,4,110,223,94,136,108,6,6,35,223,218,121,5,166,173, +220,205,237,118,132,251,130,23,204,139,227,142,115,122,126,44,248,125,188, +161,212,212,245,90,91,89,142,43,106,43,49,52,156,98,103,19,48,250,247,227, +186,6,222,210,223,6,57,244,38,78,244,189,139,99,39,234,112,184,238,251, +176,94,160,67,190,131,139,205,233,122,243,202,36,19,237,249,76,31,207,1, +247,111,127,105,255,46,231,164,71,23,204,111,64,211,188,89,168,152,81,137, +205,207,254,0,199,205,56,214,44,62,136,157,187,142,160,39,178,16,135,207, +86,173,109,223,180,172,3,19,123,63,66,200,248,59,58,247,254,219,171,89, +156,86,115,217,204,154,89,139,151,173,122,160,172,98,230,13,229,94,63,186, +59,123,112,229,212,119,81,85,63,15,61,233,203,219,247,62,189,97,253,224, +249,127,246,241,218,17,61,248,92,194,248,152,9,115,207,29,207,1,45,82,84, +231,2,109,38,237,178,251,86,223,241,212,192,217,99,219,126,187,187,251, +37,221,197,66,80,157,184,67,225,3,213,100,134,217,139,189,156,154,33,27, +21,180,242,96,127,205,1,107,7,178,249,40,240,63,28,19,125,59,182,66,70, +188,16,216,199,255,233,248,143,0,3,0,149,57,130,56,76,237,54,38,0,0,0,0, +73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_23 = 1967; +static unsigned char xml_res_file_23[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,7,81,73,68,65,84,120,218,180,87,125,108,93,101,25,255,189,239,57, +231,158,115,123,215,142,174,235,166,67,35,84,199,24,100,72,157,153,102, +69,19,101,200,199,10,138,81,23,62,226,248,131,232,192,143,63,140,134,232, +152,134,65,130,136,35,209,108,134,96,52,33,58,194,103,22,65,182,105,153, +115,27,69,6,186,205,106,169,118,99,13,100,31,108,107,217,218,219,246,222, +123,190,94,127,207,57,231,94,110,187,22,70,19,79,250,244,124,190,239,243, +123,126,207,239,121,223,231,42,204,236,176,239,217,244,196,211,218,178, +191,104,140,57,231,65,74,41,196,81,248,135,159,124,107,213,87,120,27,38, +207,102,226,252,199,191,124,108,139,81,86,231,101,151,45,68,108,98,224, +92,48,208,147,86,26,61,61,7,161,76,244,199,245,223,189,249,198,42,136,247, +123,52,174,219,248,132,137,24,122,201,143,204,88,37,60,103,147,239,101, +156,140,151,121,146,104,102,0,192,139,163,8,126,16,97,231,129,195,120,31, +25,96,10,128,207,93,222,6,25,47,243,208,138,51,1,160,36,239,226,88,38,252, +124,123,91,250,212,212,254,77,123,252,229,192,0,162,216,48,109,166,150, +126,123,70,18,148,241,90,35,103,219,216,240,244,139,137,184,170,51,154, +42,144,58,106,228,42,166,227,101,139,62,76,231,152,240,206,158,160,106, +155,170,142,223,155,83,137,224,254,135,159,76,174,53,157,171,140,95,57, +59,249,60,114,141,205,116,24,163,90,33,166,202,140,50,233,243,122,69,139, +173,251,197,230,45,65,20,119,182,47,105,59,39,85,27,212,211,173,106,165, +164,180,194,254,125,125,152,93,240,176,232,162,11,17,69,239,128,144,67, +238,67,51,241,153,0,200,67,91,157,107,191,189,10,34,13,61,195,133,193,100, +118,245,21,237,184,247,161,223,225,206,175,173,64,16,198,117,116,43,116, +237,235,71,28,154,179,0,120,130,140,159,226,59,247,60,2,47,167,97,101,201, +172,165,19,117,247,117,41,172,221,115,114,201,92,16,25,108,248,225,55,18, +49,60,240,228,158,132,238,234,56,73,219,210,133,11,18,134,39,3,80,134,31, +86,2,96,78,99,30,207,12,182,35,159,83,112,93,11,142,235,80,104,10,185,156, +13,135,168,114,52,135,247,14,105,18,227,103,112,104,196,76,159,26,133,55, +186,8,34,130,34,26,91,219,48,74,242,157,6,167,50,109,133,209,217,0,32,159, +85,252,16,133,188,56,100,78,60,13,151,230,112,118,151,158,44,59,117,156, +0,208,25,0,58,182,45,3,135,115,217,58,141,48,239,57,168,84,66,58,176,176, +236,99,31,77,24,240,149,15,223,74,105,15,125,63,209,64,189,198,210,42,224, +135,101,63,34,253,14,148,99,193,114,53,108,57,231,44,222,11,0,154,165,161, +9,66,19,0,255,40,122,147,156,53,207,42,225,24,201,120,9,68,199,57,108,172, +204,135,72,224,246,134,65,172,220,180,129,78,35,108,89,179,134,139,16,166, +96,128,15,42,129,15,143,148,179,20,19,135,218,177,105,86,106,114,47,70, +6,136,35,209,136,156,73,50,108,1,34,139,75,168,224,145,129,50,1,196,124, +63,248,18,53,33,220,95,101,225,173,103,239,79,117,115,199,29,4,21,79,220, +88,170,50,42,83,4,110,46,199,168,117,226,84,217,86,10,134,215,182,45,233, +208,105,10,44,201,61,211,65,199,97,24,178,114,152,166,156,148,143,65,3, +47,202,126,133,121,30,199,218,171,142,241,28,33,240,207,224,229,237,111, +18,64,12,229,151,25,108,52,5,3,34,66,63,72,34,208,154,142,181,68,108,37, +105,176,115,233,57,164,211,33,31,40,177,140,134,75,97,34,42,19,48,223,4, +17,51,234,114,25,88,187,72,0,4,20,98,5,126,56,146,10,78,176,133,41,237, +134,206,35,238,33,6,147,0,200,203,50,197,227,50,135,154,220,38,121,167, +217,100,96,60,82,56,226,43,2,208,201,66,35,9,119,92,37,114,78,202,205,168, +52,133,82,243,13,174,147,4,34,1,69,178,225,196,172,36,237,37,244,135,113, +41,41,65,217,11,234,25,208,169,6,144,32,247,72,161,8,205,38,3,204,44,78, +86,98,156,162,243,88,4,200,242,176,36,69,212,134,164,71,89,86,2,72,68,169, +116,10,206,243,114,73,42,35,58,90,241,233,75,136,47,135,245,93,23,224,215, +175,44,193,103,150,93,76,192,54,129,68,103,3,16,105,86,18,13,56,201,162, +82,137,53,78,149,98,210,205,8,57,113,204,232,13,29,70,4,17,145,149,136, +14,35,233,110,152,174,88,89,100,129,227,56,185,231,230,201,128,204,167, +240,167,238,62,92,189,252,194,68,172,75,230,21,113,219,198,57,100,163,137, +197,96,79,40,195,26,3,227,204,163,67,6,138,140,250,72,49,68,49,80,24,165, +178,139,161,70,49,202,44,200,238,105,163,161,133,177,208,38,216,89,8,208, +204,168,230,160,208,48,31,81,88,224,164,77,184,161,99,49,118,252,237,76, +66,255,170,142,31,96,241,7,78,227,217,222,219,88,190,5,178,149,155,164, +1,89,136,40,40,103,182,139,61,95,151,9,178,149,221,72,209,142,191,179,218, +155,234,46,78,218,201,138,99,21,240,171,157,215,99,215,127,95,32,237,192, +186,231,146,229,0,134,243,47,95,127,107,242,105,178,0,234,2,174,251,196, +87,241,252,254,167,240,251,87,110,130,101,110,159,8,64,201,42,197,25,122, +14,191,141,127,30,26,154,176,202,79,215,241,40,82,111,171,38,108,239,123, +1,143,223,185,9,167,131,231,249,185,93,107,51,77,109,235,142,89,161,45, +232,61,254,20,174,255,228,45,216,214,179,25,253,56,51,1,128,25,29,29,233, +222,191,247,165,14,83,221,171,107,27,81,218,189,52,120,46,198,198,203,89, +199,1,82,237,161,84,14,57,184,9,138,141,85,49,56,141,61,253,91,147,215, +106,170,173,91,61,7,97,189,247,228,102,172,92,186,26,78,238,81,156,185, +23,191,233,90,135,27,5,64,249,183,15,220,245,77,158,231,214,53,40,106,249, +149,157,139,190,240,229,91,55,148,34,229,46,189,252,34,28,62,62,84,155, +180,237,131,45,216,119,224,16,154,189,185,248,215,32,48,26,29,227,230,48, +125,31,88,235,150,104,7,135,30,199,167,22,95,138,151,251,122,59,165,21, +16,135,37,218,155,180,147,117,1,120,43,190,116,75,151,202,55,192,229,98, +50,171,177,128,43,23,180,214,250,192,83,197,113,184,121,15,33,171,64,142, +146,57,202,253,99,250,30,223,100,171,175,150,77,203,170,96,239,161,94,84, +70,176,83,26,40,59,235,205,139,153,85,143,57,126,16,224,146,15,205,199, +200,88,9,7,95,63,130,254,58,49,72,15,216,58,247,60,52,55,180,2,39,128,138, +117,20,110,97,10,0,38,21,97,24,164,183,22,189,13,28,1,250,246,125,22,59, +239,219,253,61,62,10,166,107,74,237,144,43,221,249,173,179,241,145,243, +91,49,52,60,198,42,9,106,85,224,58,14,90,102,55,66,7,14,230,235,118,252, +236,209,191,167,59,226,100,255,226,156,225,173,190,41,29,58,240,6,240,218, +222,14,52,15,175,238,6,118,15,10,121,211,1,8,255,253,143,238,239,179,149, +248,249,210,37,23,163,253,210,54,52,53,53,162,138,96,100,164,136,158,215, +6,240,106,207,235,56,177,235,227,63,218,181,109,255,171,211,244,228,206, +53,63,197,54,39,15,244,31,4,118,108,199,238,23,31,236,94,15,116,191,197, +119,195,226,103,186,180,113,8,22,180,204,91,176,240,186,155,215,220,61, +235,188,150,142,180,91,54,217,26,192,69,106,120,168,123,235,99,15,223,55, +116,242,216,0,31,142,72,207,57,197,60,205,43,31,196,127,58,174,0,254,186, +3,67,127,190,27,215,242,217,241,204,121,233,221,0,200,10,233,138,22,104, +243,104,77,147,126,67,132,153,83,17,238,219,82,73,211,48,48,239,134,135, +112,130,26,24,217,122,23,174,225,253,97,218,96,61,216,247,250,113,106,103, +108,184,147,26,102,209,117,165,26,197,187,140,111,166,93,144,205,115,148, +118,74,132,55,233,55,235,255,245,144,69,191,33,187,30,155,236,92,142,255, +9,48,0,241,195,153,86,37,156,12,221,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_24 = 2051; +static unsigned char xml_res_file_24[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,7,165,73,68,65,84,120,218,156,87,107,112,21,103,25,126,190,221,61, +187,231,228,228,2,185,181,73,4,148,66,130,117,200,52,182,214,81,42,14,45, +86,7,80,212,233,216,17,157,78,127,56,26,188,212,209,254,160,25,172,12,242, +163,211,25,227,84,165,78,107,157,90,111,197,214,58,12,140,69,7,28,138,66, +25,29,36,164,212,182,16,174,197,96,106,110,36,57,201,185,236,213,231,221, +221,115,56,73,154,66,115,38,111,118,191,189,124,239,243,62,239,243,190, +223,183,10,243,251,25,219,31,127,238,5,77,55,54,6,65,112,221,47,41,165, +224,123,238,158,109,223,184,247,30,14,221,240,218,124,156,127,255,39,207, +238,14,148,190,161,189,125,57,252,192,7,174,7,3,61,105,74,195,201,147,103, +160,2,239,79,63,120,96,211,231,138,32,222,237,175,234,225,157,207,5,30, +67,207,217,94,48,85,112,175,219,228,121,121,79,222,151,121,194,104,230, +1,32,233,123,30,108,199,195,75,189,231,241,46,50,192,20,0,107,110,89,10, +121,95,230,161,101,230,3,64,73,222,197,177,76,120,103,199,210,232,106,80, +250,55,231,239,96,239,5,120,126,192,180,5,165,244,27,243,146,160,188,175, +105,48,13,3,221,47,28,9,197,85,156,49,40,2,41,163,70,206,124,58,190,189, +109,17,157,99,218,61,99,154,170,13,170,218,191,54,167,18,193,35,79,60,31, +158,107,116,174,98,126,229,152,72,165,96,86,45,164,67,31,197,10,9,138,204, +168,32,186,94,174,104,177,135,127,252,187,221,142,231,111,232,88,185,244, +186,84,29,160,156,110,85,42,37,165,41,156,232,121,3,53,233,36,218,90,223, +7,207,187,10,66,126,50,118,131,233,215,4,64,10,154,190,97,235,55,239,133, +72,67,155,103,99,8,98,251,228,29,29,216,241,163,223,224,235,95,88,11,199, +245,203,232,86,56,208,211,7,223,13,102,1,72,10,50,62,138,111,109,255,57, +146,166,6,61,78,102,41,157,40,27,151,165,176,52,230,228,146,57,199,11,208, +221,245,213,80,12,143,62,127,56,164,187,248,158,164,237,214,229,205,33, +195,51,1,168,128,15,22,28,160,182,42,133,63,14,119,32,101,42,88,150,142, +132,149,160,208,20,76,211,64,130,168,76,90,130,227,4,105,18,227,99,72,208, +136,153,62,53,164,223,60,64,16,30,20,209,24,154,129,64,73,190,163,224,84, +172,45,215,155,13,0,242,88,193,118,145,78,137,67,230,36,169,193,162,37, +56,187,69,79,186,17,57,14,1,104,49,0,58,54,244,0,9,206,101,104,81,132,169, +100,2,133,130,75,7,58,110,95,118,83,200,128,173,108,216,122,68,187,107, +219,161,6,202,53,22,85,1,31,204,219,30,233,79,64,37,116,232,150,6,67,142, +166,206,177,0,160,233,26,52,130,208,8,128,127,20,125,16,30,53,30,85,200, +49,194,247,37,16,205,55,177,179,112,3,68,2,95,169,24,198,250,199,187,233, +212,195,238,206,78,54,33,188,13,3,188,80,112,108,36,73,57,75,49,116,168, +37,12,154,30,153,140,197,200,0,113,132,26,145,35,73,134,33,64,164,185,184, +10,73,50,144,39,0,159,247,135,143,82,19,194,253,39,116,188,181,247,145, +72,55,155,55,19,148,63,125,97,41,202,40,79,17,88,166,201,168,181,208,169, +50,244,8,12,207,13,67,210,161,69,41,208,37,247,76,7,29,187,174,203,202, +97,154,76,41,159,0,21,150,133,60,3,113,130,60,182,174,121,43,204,183,237, +78,224,31,251,251,9,192,135,42,228,24,172,247,54,12,136,8,109,39,140,64, +211,232,88,147,136,245,48,13,134,25,29,93,58,29,177,129,28,203,104,60,231, +134,162,10,28,230,155,32,124,70,157,47,0,91,87,88,200,178,18,10,204,77, +214,244,88,247,34,65,45,202,15,185,23,183,158,95,214,152,138,0,4,81,158, +226,177,152,67,141,220,134,121,167,25,100,32,235,41,244,219,138,0,180,176, +209,72,194,19,150,18,57,135,229,22,40,132,37,104,243,196,172,170,134,253, +239,19,248,216,193,103,176,240,151,223,13,213,31,174,25,252,103,127,104, +13,114,235,190,8,103,241,90,248,12,114,134,6,192,220,145,1,114,41,66,51, +200,0,51,139,193,2,153,81,6,148,164,133,96,132,29,17,83,160,188,98,131, +39,40,13,110,194,132,163,153,104,217,243,11,212,28,123,9,43,63,245,105, +44,232,188,31,122,170,34,138,58,155,197,149,87,123,209,191,179,11,133,83, +199,224,212,119,204,172,2,143,229,227,132,12,72,83,41,248,26,166,114,44, +78,230,94,49,218,64,162,215,117,120,20,38,200,72,184,94,176,198,73,23,163, +97,90,148,137,239,252,245,65,52,142,29,199,242,45,219,80,56,251,58,50,187, +158,130,59,52,16,57,105,104,66,213,135,87,163,253,161,109,56,245,179,199, +208,209,56,80,2,160,21,25,200,50,143,9,50,144,97,212,253,25,23,25,71,97, +146,202,206,184,26,50,94,108,78,60,46,26,155,215,132,151,192,77,255,249, +23,214,14,252,29,173,155,191,141,236,158,93,200,239,223,3,76,102,96,164, +171,67,147,115,185,150,231,189,247,119,62,128,246,129,215,208,125,243,226, +149,210,159,140,226,106,85,160,160,18,53,22,14,223,151,134,86,236,236,129, +80,157,189,218,237,131,226,42,30,47,63,164,223,75,86,96,104,203,211,104, +92,127,15,242,135,254,2,111,240,50,180,100,50,218,44,148,150,41,121,215, +8,239,21,254,182,15,139,214,109,196,7,126,255,219,237,188,113,216,136,119, +24,212,84,128,147,231,71,241,202,217,145,105,93,254,29,119,60,4,224,36, +211,88,125,232,0,106,30,124,8,83,71,254,12,197,86,28,176,227,205,94,82, +85,148,198,115,167,177,176,227,35,72,234,218,42,89,8,5,64,48,57,57,241, +242,137,127,30,93,21,20,215,234,210,66,20,237,94,42,146,22,166,178,249, +120,199,1,164,43,146,200,74,221,17,64,222,172,192,234,4,59,104,255,5,54, +40,133,154,23,123,223,113,213,28,223,120,27,212,165,115,69,120,210,249, +145,127,250,209,45,95,227,177,190,108,131,162,62,122,215,134,182,187,63, +255,229,238,156,167,172,91,111,105,197,249,129,145,210,36,75,155,234,112, +188,183,15,149,41,11,139,86,44,3,254,64,41,141,93,97,3,75,94,115,217,14, +159,225,179,44,31,20,53,144,163,93,162,13,150,37,45,185,246,179,95,58,160, +88,70,22,59,71,101,85,26,119,53,55,148,246,129,67,153,44,44,58,247,72,233, +169,190,11,104,147,53,111,108,20,122,117,13,38,55,221,25,54,167,89,185, +147,29,147,116,86,62,227,143,141,197,26,137,34,150,189,121,38,182,226,175, +214,118,28,220,252,158,27,48,49,149,195,153,115,253,232,43,155,80,246,128, +141,245,11,80,153,174,192,43,167,47,34,127,219,199,49,49,126,25,181,13, +245,240,172,100,212,106,103,75,32,124,143,31,51,24,30,27,199,132,235,245, +32,148,230,28,31,31,46,59,93,75,67,13,150,180,52,96,100,124,138,85,226, +148,170,192,98,206,235,106,210,144,229,238,196,171,167,177,127,225,10,84, +191,209,131,250,166,38,70,105,198,155,142,217,91,114,45,162,29,111,14,12, +97,255,224,216,99,60,181,245,57,0,88,213,181,13,67,99,185,224,238,74,150, +212,202,101,45,104,93,210,140,37,55,214,210,234,81,101,25,56,75,86,14,30, +61,142,99,135,246,117,61,251,204,79,127,184,170,38,85,227,230,242,109,45, +55,54,177,107,74,75,231,130,38,235,10,143,122,184,194,82,168,4,112,252, +245,83,56,51,54,185,183,235,181,139,79,210,207,149,185,62,205,82,180,230, +186,198,230,229,235,54,117,126,175,114,65,221,170,104,183,28,81,32,84,78, +142,15,191,188,111,215,147,59,70,254,247,223,139,34,100,73,219,175,62,184, +124,71,107,109,245,250,101,239,93,140,250,122,106,218,136,9,166,38,134, +135,135,113,246,226,37,156,30,205,188,120,127,79,95,151,16,33,105,159,11, +128,112,101,201,164,180,70,90,245,140,111,8,209,205,68,44,220,209,120,44, +159,90,45,247,45,110,188,227,51,77,181,157,117,134,222,126,117,59,10,140, +184,222,201,189,3,163,79,252,250,210,224,17,14,47,75,69,34,108,236,215, +248,16,141,217,176,102,108,152,101,161,43,196,21,84,252,192,148,116,166, +99,208,82,210,149,241,181,112,71,78,155,164,13,199,128,167,226,107,243, +250,58,190,198,55,48,18,49,104,115,122,47,134,29,3,118,202,219,228,255, +5,24,0,238,123,163,24,29,62,142,101,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_25 = 1382; +static unsigned char xml_res_file_25[] = { +137,80,78,71,13,10,26,10,0,0,0,13,73,72,68,82,0,0,0,32,0,0,0,32,8,6,0,0, +0,115,122,122,244,0,0,0,25,116,69,88,116,83,111,102,116,119,97,114,101, +0,65,100,111,98,101,32,73,109,97,103,101,82,101,97,100,121,113,201,101, +60,0,0,5,8,73,68,65,84,120,218,188,87,221,107,28,85,20,255,221,123,247, +35,219,205,182,214,26,65,76,137,77,95,170,144,244,69,13,66,13,81,40,166, +44,125,16,95,20,130,246,161,224,187,208,7,65,124,240,73,168,138,255,64, +177,196,40,197,135,250,17,107,179,20,2,106,181,95,84,209,68,12,213,52,164, +105,83,76,98,83,106,147,184,51,115,239,245,156,59,119,55,187,178,205,206, +34,102,147,147,201,206,204,189,231,55,191,243,59,31,3,108,238,71,76,95, +248,178,184,58,247,67,244,193,145,126,75,223,51,169,205,114,124,169,244, +225,174,71,118,118,126,42,97,122,69,42,13,37,36,159,207,203,77,112,174, +230,127,42,125,178,187,187,107,122,109,233,183,222,185,179,199,96,162,8, +66,8,190,150,110,198,64,234,163,55,6,63,203,101,100,81,210,2,145,208,163, +177,22,65,16,160,187,103,31,186,30,123,10,225,234,45,220,152,248,14,209, +234,50,64,215,140,53,80,42,126,246,102,0,114,217,148,40,190,117,106,141, +130,69,0,18,34,48,198,98,229,239,0,151,15,237,195,181,159,199,113,119,105, +22,66,146,43,50,107,66,88,77,12,200,100,0,218,68,140,2,109,116,103,43,0, +172,77,227,250,247,35,88,43,27,90,199,110,200,33,61,57,253,194,16,0,229, +55,107,6,64,8,43,192,244,51,96,153,16,0,7,75,41,5,75,139,140,224,144,192, +81,15,27,135,71,235,176,162,1,36,200,2,11,73,241,106,5,0,127,248,126,118, +70,207,28,3,0,124,252,233,124,20,186,61,19,1,16,70,130,239,149,210,38,7, +64,247,17,1,68,55,135,194,186,135,175,0,176,158,129,74,8,26,165,97,230, +224,123,176,207,29,197,73,6,40,53,135,64,17,101,178,101,211,4,192,104,235, +52,81,103,77,68,152,215,36,148,254,93,120,254,175,55,177,34,202,202,161, +85,196,64,82,17,114,172,37,209,101,109,3,6,232,71,135,161,211,213,189,24, +72,7,26,120,161,239,117,60,219,139,161,177,194,57,40,155,165,5,41,218,84, +182,96,202,229,187,211,129,55,205,71,206,2,42,68,170,134,129,116,241,29, +44,134,26,219,220,69,66,187,86,166,35,114,24,236,125,17,37,117,2,191,47, +127,3,59,57,0,153,9,9,178,78,34,1,167,25,237,247,51,46,1,4,57,39,86,72, +83,145,11,193,122,22,228,217,249,241,87,143,225,86,249,115,174,156,180, +144,110,176,247,99,98,254,4,14,244,190,12,153,30,198,121,249,53,212,47, +207,208,198,1,237,110,18,132,192,198,34,52,113,8,216,121,247,67,51,232, +216,58,143,185,104,176,210,11,28,128,12,63,249,157,242,2,190,189,242,197, +122,185,21,163,228,24,152,252,99,24,131,61,135,40,109,142,227,162,28,71, +219,212,0,237,30,197,94,54,0,192,89,160,141,113,79,175,173,112,212,63,120, +223,18,134,75,143,98,160,168,171,12,84,53,176,162,231,41,24,112,38,50,100, +124,36,120,150,54,186,242,231,199,120,98,207,30,68,157,55,221,73,167,114, +217,204,84,141,8,125,45,32,159,249,92,26,38,12,156,78,170,89,192,88,86, +237,13,168,44,170,12,88,83,83,80,82,1,46,77,79,33,51,223,233,106,2,152, +62,97,55,46,68,194,23,34,91,209,129,113,44,108,201,166,17,82,33,242,17, +136,25,224,77,67,117,19,217,60,197,99,11,145,144,163,11,153,216,82,109, +192,236,34,112,161,212,69,244,239,39,2,168,182,43,56,10,155,153,246,121, +111,201,179,37,0,11,183,119,224,192,147,63,82,33,138,234,52,192,0,238,30, +29,62,215,206,8,89,48,148,37,120,229,165,56,202,87,175,3,151,199,186,80, +184,186,31,50,27,120,200,178,169,8,149,18,113,231,179,194,237,73,42,192, +212,181,157,56,125,62,143,190,167,203,117,205,40,56,117,4,253,116,220,238, +163,145,30,124,27,167,153,133,95,167,129,197,241,14,20,166,73,181,25,202, +77,105,155,59,175,134,64,212,133,192,161,162,221,219,243,169,184,25,249, +94,192,127,87,200,102,200,38,201,38,248,127,86,240,204,28,80,58,137,175, +6,150,30,135,205,26,206,206,4,194,91,55,22,153,49,53,169,232,45,79,173, +61,34,17,214,246,2,170,46,184,77,182,224,109,153,4,140,51,163,56,123,241, +125,188,171,169,240,240,119,169,68,107,149,144,158,194,152,250,74,200,150, +73,81,143,160,24,75,121,239,118,28,142,190,134,189,254,255,40,146,177,98, +121,65,226,102,200,133,200,54,232,5,126,92,99,6,114,27,52,35,14,201,44, +223,75,86,208,116,112,180,10,139,22,122,17,105,64,186,218,175,27,0,8,117, +176,225,60,16,120,115,51,33,47,86,20,3,102,76,192,38,29,7,40,182,42,110, +197,218,214,173,114,253,134,24,16,169,132,19,17,231,176,139,63,68,107,12, +112,3,226,25,208,254,11,54,51,16,82,29,200,183,48,146,185,210,235,250,153, +77,60,18,113,8,226,46,136,245,145,204,143,134,38,42,83,88,115,201,0,164, +69,68,111,15,138,179,176,133,247,2,94,23,235,38,150,146,168,130,224,131, +99,160,70,132,153,161,161,161,114,195,141,104,225,216,50,171,122,201,127, +75,30,2,109,37,206,204,20,176,35,23,161,179,16,34,159,50,136,135,99,206, +130,114,117,34,114,3,201,200,200,200,110,158,11,26,17,224,207,103,254,235, +251,217,3,219,114,185,195,197,158,131,15,119,180,247,109,47,96,111,165, +27,10,191,121,222,59,251,223,94,78,253,254,237,100,91,201,168,229,225,14, +87,93,129,205,251,40,255,176,89,15,134,167,154,149,127,4,24,0,227,17,114, +29,252,169,144,138,0,0,0,0,73,69,78,68,174,66,96,130}; + +static size_t xml_res_size_26 = 142917; +static unsigned char xml_res_file_26[] = { +60,63,120,109,108,32,118,101,114,115,105,111,110,61,34,49,46,48,34,32,101, +110,99,111,100,105,110,103,61,34,85,84,70,45,56,34,63,62,10,60,33,45,45, +32,104,116,116,112,58,47,47,100,111,99,115,46,119,120,119,105,100,103,101, +116,115,46,111,114,103,47,116,114,117,110,107,47,111,118,101,114,118,105, +101,119,95,120,114,99,102,111,114,109,97,116,46,104,116,109,108,32,45,45, +62,10,60,114,101,115,111,117,114,99,101,32,120,109,108,110,115,61,34,104, +116,116,112,58,47,47,119,119,119,46,119,120,119,105,100,103,101,116,115, +46,111,114,103,47,119,120,120,114,99,34,32,118,101,114,115,105,111,110, +61,34,50,46,53,46,51,46,48,34,62,10,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,66,105,116,109,97,112,34,32,110,97,109,101, +61,34,66,73,84,77,65,80,95,72,65,82,68,68,73,83,75,34,62,119,120,45,114, +101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,49, +54,120,49,54,95,100,114,105,118,101,46,112,110,103,60,47,111,98,106,101, +99,116,62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,66,105,116,109,97,112,34,32,110,97,109,101,61,34,66,73,84,77,65, +80,95,70,76,79,80,80,89,34,62,119,120,45,114,101,115,111,117,114,99,101, +115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,100,105,115, +107,101,116,116,101,46,112,110,103,60,47,111,98,106,101,99,116,62,10,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,105,116, +109,97,112,34,32,110,97,109,101,61,34,66,73,84,77,65,80,95,67,68,82,79, +77,34,62,119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36, +105,99,111,110,115,95,49,54,120,49,54,95,99,100,46,112,110,103,60,47,111, +98,106,101,99,116,62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,84,111,111,108,66,97,114,34,32,110,97,109,101,61,34,116, +111,111,108,95,98,97,114,34,62,10,32,32,32,32,60,115,116,121,108,101,62, +119,120,84,66,95,70,76,65,84,124,119,120,84,66,95,78,79,68,73,86,73,68, +69,82,60,47,115,116,121,108,101,62,10,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,116,111,111,108,34,32,110,97,109,101,61, +34,84,79,79,76,66,65,82,95,82,85,78,34,62,10,32,32,32,32,32,32,60,98,105, +116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46,99,112, +112,36,105,99,111,110,115,95,50,52,120,50,52,95,112,108,97,121,46,112,110, +103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,60,108,97,98,101, +108,62,82,117,110,60,47,108,97,98,101,108,62,10,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,116,111,111,108,34,32,110,97,109,101,61,34,84,79,79,76,66, +65,82,95,80,65,85,83,69,34,62,10,32,32,32,32,32,32,60,98,105,116,109,97, +112,62,119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105, +99,111,110,115,95,50,52,120,50,52,95,112,97,117,115,101,46,112,110,103, +60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,60,108,97,98,101,108, +62,80,97,117,115,101,60,47,108,97,98,101,108,62,10,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,116,111,111,108,34,32,110,97,109,101,61,34,84,79,79,76, +66,65,82,95,83,84,79,80,34,62,10,32,32,32,32,32,32,60,98,105,116,109,97, +112,62,119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105, +99,111,110,115,95,50,52,120,50,52,95,115,116,111,112,46,112,110,103,60, +47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,60,108,97,98,101,108,62, +83,116,111,112,60,47,108,97,98,101,108,62,10,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,116,111,111,108,34,32,110,97,109,101,61,34,84,79,79,76,66,65, +82,95,82,69,83,69,84,34,62,10,32,32,32,32,32,32,60,98,105,116,109,97,112, +62,119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99, +111,110,115,95,50,52,120,50,52,95,114,101,102,114,101,115,104,46,112,110, +103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,60,108,97,98,101, +108,62,72,97,114,100,32,114,101,115,101,116,60,47,108,97,98,101,108,62, +10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,60,105,100,115,45,114,97,110,103,101,32,110,97,109, +101,61,34,73,68,77,95,83,67,82,69,69,78,83,72,79,84,95,70,79,82,77,65,84, +34,32,115,116,97,114,116,61,34,57,53,48,34,47,62,10,32,32,60,105,100,115, +45,114,97,110,103,101,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,82, +69,83,79,76,85,84,73,79,78,34,32,115,116,97,114,116,61,34,57,57,48,34,47, +62,10,32,32,60,105,100,115,45,114,97,110,103,101,32,110,97,109,101,61,34, +73,68,77,95,86,73,68,95,70,83,34,32,115,116,97,114,116,61,34,49,48,48,48, +34,47,62,10,32,32,60,105,100,115,45,114,97,110,103,101,32,110,97,109,101, +61,34,73,68,77,95,86,73,68,95,70,83,95,77,79,68,69,34,32,115,116,97,114, +116,61,34,49,49,48,48,34,47,62,10,32,32,60,105,100,115,45,114,97,110,103, +101,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,83,67,65,76,69,34,32, +115,116,97,114,116,61,34,49,50,48,48,34,47,62,10,32,32,60,105,100,115,45, +114,97,110,103,101,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,83,67, +65,76,69,95,77,79,68,69,34,32,115,116,97,114,116,61,34,49,51,48,48,34,47, +62,10,32,32,60,105,100,115,45,114,97,110,103,101,32,110,97,109,101,61,34, +73,68,77,95,86,73,68,95,82,69,78,68,69,82,95,68,82,73,86,69,82,34,32,115, +116,97,114,116,61,34,49,52,48,48,34,47,62,10,32,32,60,105,100,115,45,114, +97,110,103,101,32,110,97,109,101,61,34,73,68,77,95,83,78,68,95,66,85,70, +34,32,115,116,97,114,116,61,34,50,48,48,48,34,47,62,10,32,32,60,105,100, +115,45,114,97,110,103,101,32,110,97,109,101,61,34,73,68,77,95,83,78,68, +95,71,65,73,78,34,32,115,116,97,114,116,61,34,50,49,48,48,34,47,62,10,32, +32,60,105,100,115,45,114,97,110,103,101,32,110,97,109,101,61,34,73,68,77, +95,86,73,68,95,71,76,51,95,73,78,80,85,84,95,83,84,82,69,84,67,72,34,32, +115,116,97,114,116,61,34,51,48,48,48,34,47,62,10,32,32,60,105,100,115,45, +114,97,110,103,101,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76, +51,95,73,78,80,85,84,95,83,67,65,76,69,34,32,115,116,97,114,116,61,34,51, +49,48,48,34,47,62,10,32,32,60,105,100,115,45,114,97,110,103,101,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,83,72,65,68,69,82, +95,82,69,70,82,69,83,72,95,82,65,84,69,34,32,115,116,97,114,116,61,34,51, +50,48,48,34,47,62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,77,101,110,117,66,97,114,34,32,110,97,109,101,61,34,115,116, +97,116,117,115,95,109,101,110,117,34,62,10,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,34,62,10,32,32, +32,32,32,32,60,108,97,98,101,108,62,95,79,112,116,105,111,110,115,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97, +109,101,61,34,73,68,77,95,68,73,83,67,95,65,67,84,73,86,73,84,89,34,62, +10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,68,105,115,99,32,97, +99,116,105,118,105,116,121,60,47,108,97,98,101,108,62,10,32,32,32,32,32, +32,32,32,60,99,104,101,99,107,97,98,108,101,62,49,60,47,99,104,101,99,107, +97,98,108,101,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95, +77,65,67,72,73,78,69,95,77,79,85,78,84,95,80,65,84,72,83,34,62,10,32,32, +32,32,32,32,32,32,60,108,97,98,101,108,62,77,111,117,110,116,32,112,97, +116,104,115,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,99, +104,101,99,107,97,98,108,101,62,49,60,47,99,104,101,99,107,97,98,108,101, +62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110, +117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,83,72,79,87,95, +83,84,65,84,85,83,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,83,116,97,116,117,115,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32, +32,32,60,99,104,101,99,107,97,98,108,101,62,49,60,47,99,104,101,99,107, +97,98,108,101,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95, +83,80,69,69,68,95,72,73,83,84,79,82,89,34,62,10,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,83,112,101,101,100,32,104,105,115,116,111,114,121, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,99,104,101,99, +107,97,98,108,101,62,49,60,47,99,104,101,99,107,97,98,108,101,62,10,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,101,112,97,114,97,116, +111,114,34,47,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109, +101,61,34,73,68,77,95,83,72,79,87,95,77,65,67,72,73,78,69,95,79,78,95,83, +84,65,82,84,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83, +104,111,119,32,111,110,32,115,116,97,114,116,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,60,99,104,101,99,107,97,98,108,101,62,49,60, +47,99,104,101,99,107,97,98,108,101,62,10,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101, +110,117,34,62,10,32,32,32,32,32,32,60,108,97,98,101,108,62,95,67,111,110, +102,105,103,117,114,101,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110, +117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,67,79,78,70,73, +71,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,77,97,99,104, +105,110,101,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101, +110,117,34,62,10,32,32,32,32,32,32,60,108,97,98,101,108,62,95,77,105,115, +99,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34, +32,110,97,109,101,61,34,73,68,77,95,82,69,83,69,84,95,67,79,78,70,73,82, +77,65,84,73,79,78,95,68,73,65,76,79,71,83,34,62,10,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,95,82,101,115,101,116,32,99,111,110,102,105, +114,109,97,116,105,111,110,32,100,105,97,108,111,103,115,60,47,108,97,98, +101,108,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,101, +112,97,114,97,116,111,114,34,47,62,10,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109, +34,32,110,97,109,101,61,34,73,68,77,95,65,66,79,85,84,34,62,10,32,32,32, +32,32,32,32,32,60,108,97,98,101,108,62,95,65,98,111,117,116,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,34,32,110,97,109,101,61,34,109,97,105,110,95,109,101, +110,117,34,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,77,101,110,117,34,62,10,32,32,32,32,32,32,60,108,97,98, +101,108,62,95,83,121,115,116,101,109,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,70, +73,76,69,95,72,82,69,83,69,84,34,62,10,32,32,32,32,32,32,32,32,60,108,97, +98,101,108,62,95,72,97,114,100,32,82,101,115,101,116,60,47,108,97,98,101, +108,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77, +101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,70,73, +76,69,95,82,69,83,69,84,95,67,65,68,34,62,10,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,95,67,116,114,108,43,65,108,116,43,68,101,108,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,101,112,97,114,97,116,111,114,34,47,62,10,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73, +116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,70,73,76,69,95,69,88, +73,84,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,83,104, +117,116,100,111,119,110,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,34,62,10,32,32,32,32,32,32,60,108,97,98,101,108,62,95, +68,105,115,99,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116, +101,109,34,32,110,97,109,101,61,34,73,68,77,95,68,73,83,67,95,65,34,62, +10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,104,97,110,103,101, +32,100,114,105,118,101,32,95,65,58,46,46,46,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110, +117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,68,73,83,67,95, +66,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,104,97,110, +103,101,32,100,114,105,118,101,32,95,66,58,46,46,46,60,47,108,97,98,101, +108,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77, +101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,69,74, +69,67,84,95,65,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62, +95,69,106,101,99,116,32,100,114,105,118,101,32,65,58,60,47,108,97,98,101, +108,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77, +101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,69,74, +69,67,84,95,66,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62, +69,106,101,99,116,32,100,114,105,118,101,32,66,58,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,101,112,97,114, +97,116,111,114,34,47,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,66,80,66,95,68,73,83,65,66,76,69,34,62,10, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,68,105,115,97,98,108,101, +32,66,80,66,32,99,104,101,99,107,105,110,103,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,60,99,104,101,99,107,97,98,108,101,62,49,60, +47,99,104,101,99,107,97,98,108,101,62,10,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,101,112,97,114,97,116,111,114,34,47,62,10,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77, +101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,68,73, +83,67,95,67,82,69,65,84,69,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98, +101,108,62,67,114,101,97,116,101,32,98,108,97,110,107,32,100,105,115,99, +32,105,109,97,103,101,46,46,46,60,47,108,97,98,101,108,62,10,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,101,112,97,114,97,116,111,114, +34,47,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61, +34,73,68,77,95,68,73,83,67,95,90,73,80,34,62,10,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,76,111,97,100,32,95,90,73,80,32,100,114,105,118, +101,46,46,46,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97, +109,101,61,34,73,68,77,95,69,74,69,67,84,95,90,73,80,34,62,10,32,32,32, +32,32,32,32,32,60,108,97,98,101,108,62,69,106,101,99,116,32,90,73,80,32, +100,114,105,118,101,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,34,32,110,97,109,101,61,34,73,68,77,95,67,68,82,79,77, +34,62,10,32,32,32,32,32,32,60,108,97,98,101,108,62,95,67,68,45,82,79,77, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32, +110,97,109,101,61,34,73,68,77,95,67,68,82,79,77,95,73,77,65,71,69,95,76, +79,65,68,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,76, +111,97,100,32,105,109,97,103,101,46,46,46,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,101,112,97,114,97, +116,111,114,34,47,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97, +109,101,61,34,73,68,77,95,67,68,82,79,77,95,69,77,80,84,89,34,62,10,32, +32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,69,109,112,116,121,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62, +49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61, +34,73,68,77,95,67,68,82,79,77,95,73,77,65,71,69,34,62,10,32,32,32,32,32, +32,32,32,60,108,97,98,101,108,62,95,73,109,97,103,101,46,46,46,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49, +60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117, +34,32,110,97,109,101,61,34,73,68,77,95,67,65,83,83,69,84,84,69,34,62,10, +32,32,32,32,32,32,60,108,97,98,101,108,62,67,95,97,115,115,101,116,116, +101,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34, +32,110,97,109,101,61,34,73,68,77,95,67,65,83,83,69,84,84,69,95,76,79,65, +68,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,76,111,97, +100,32,116,97,112,101,102,105,108,101,46,46,46,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110, +117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,67,65,83,83,69, +84,84,69,95,69,74,69,67,84,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98, +101,108,62,95,69,106,101,99,116,32,116,97,112,101,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,34,62,10,32,32,32,32,32, +32,60,108,97,98,101,108,62,86,105,100,101,111,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,77,101,110,117,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,82,101,115,111,108,117,116,105,111,110,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34, +73,68,77,95,86,73,68,95,82,69,83,79,76,85,84,73,79,78,91,48,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,79,114,105,103,105, +110,97,108,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117, +73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,82,69, +83,79,76,85,84,73,79,78,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,82,101,115,105,122,97,98,108,101,60,47,108,97,98, +101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49, +60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97, +109,101,61,34,73,68,77,95,86,73,68,95,82,69,83,79,76,85,84,73,79,78,91, +50,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67, +117,115,116,111,109,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32, +32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,101,112,97, +114,97,116,111,114,34,47,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109, +34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,82,69,83,79,76,85,84, +73,79,78,95,67,85,83,84,79,77,34,62,10,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,83,101,116,32,99,117,115,116,111,109,32,114,101,115, +111,108,117,116,105,111,110,46,46,46,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32, +110,97,109,101,61,34,73,68,77,95,86,73,68,95,82,69,77,69,77,66,69,82,34, +62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,82,101,109,101,109, +98,101,114,32,115,105,122,101,32,38,97,109,112,59,38,97,109,112,59,32,112, +111,115,105,116,105,111,110,60,47,108,97,98,101,108,62,10,32,32,32,32,32, +32,32,32,60,99,104,101,99,107,97,98,108,101,62,49,60,47,99,104,101,99,107, +97,98,108,101,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +101,112,97,114,97,116,111,114,34,47,62,10,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101, +109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,70,85,76,76,83,67, +82,69,69,78,95,84,79,71,71,76,69,34,62,10,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,84,111,103,103,108,101,32,102,117,108,108,115,99,114,101, +101,110,92,116,67,116,114,108,43,65,108,116,43,80,97,103,101,68,111,119, +110,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61, +34,73,68,77,95,86,73,68,95,70,85,76,76,83,67,82,69,69,78,34,62,10,32,32, +32,32,32,32,32,32,60,108,97,98,101,108,62,70,117,108,108,115,99,114,101, +101,110,32,111,110,32,105,110,112,117,116,32,103,114,97,98,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,60,99,104,101,99,107,97,98,108, +101,62,49,60,47,99,104,101,99,107,97,98,108,101,62,10,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,115,101,112,97,114,97,116,111,114,34,47, +62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,77,101,110,117,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98, +101,108,62,70,117,108,108,115,99,114,101,101,110,32,109,111,100,101,60, +47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34, +32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,70,83,95,77,79,68,69,91, +48,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95, +66,111,114,100,101,114,108,101,115,115,60,47,108,97,98,101,108,62,10,32, +32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100, +105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73, +68,77,95,86,73,68,95,70,83,95,77,79,68,69,91,49,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,60,108,97,98,101,108,62,95,69,120,99,108,117,115,105, +118,101,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60, +114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,77,101,110,117,34,32,110,97,109,101,61,34, +73,68,77,95,86,73,68,95,82,69,78,68,69,82,95,68,82,73,86,69,82,34,62,10, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,82,101,110,100,101,114, +32,100,114,105,118,101,114,60,47,108,97,98,101,108,62,10,32,32,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77, +101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73, +68,95,82,69,78,68,69,82,95,68,82,73,86,69,82,91,48,93,34,62,10,32,32,32, +32,32,32,32,32,32,32,60,108,97,98,101,108,62,65,117,116,111,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62, +49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,82,69,78,68,69,82,95,68,82,73, +86,69,82,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,68,105,114,101,99,116,51,68,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105, +111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68, +77,95,86,73,68,95,82,69,78,68,69,82,95,68,82,73,86,69,82,91,50,93,34,62, +10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,79,112,101,110, +71,76,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114, +97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116, +101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,82,69,78,68, +69,82,95,68,82,73,86,69,82,91,54,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,79,112,101,110,71,76,32,51,46,48,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62, +49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,82,69,78,68,69,82,95,68,82,73, +86,69,82,91,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,83,111,102,116,119,97,114,101,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105, +111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73, +116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,86,83,89, +78,67,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,86,83, +121,110,99,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,99, +104,101,99,107,97,98,108,101,62,49,60,47,99,104,101,99,107,97,98,108,101, +62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110, +117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,76, +79,83,84,95,70,79,67,85,83,95,68,73,77,34,62,10,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,95,68,105,109,32,100,105,115,112,108,97,121,32, +111,110,32,108,111,115,116,32,102,111,99,117,115,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,60,99,104,101,99,107,97,98,108,101,62,49, +60,47,99,104,101,99,107,97,98,108,101,62,10,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97, +109,101,61,34,73,68,77,95,86,73,68,95,65,76,84,69,82,78,65,84,73,86,69, +95,85,80,68,65,84,69,95,76,79,67,75,34,62,10,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,65,108,116,101,114,110,97,116,105,118,101,32,117,112, +100,97,116,101,45,108,111,99,107,60,47,108,97,98,101,108,62,10,32,32,32, +32,32,32,32,32,60,99,104,101,99,107,97,98,108,101,62,49,60,47,99,104,101, +99,107,97,98,108,101,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,101,112,97,114,97,116,111,114,34,47,62,10,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,34, +62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,99,97,108,101, +32,102,105,108,116,101,114,105,110,103,60,47,108,97,98,101,108,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68, +77,95,86,73,68,95,83,67,65,76,69,95,77,79,68,69,91,48,93,34,62,10,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,78,101,97,114,101,115, +116,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114, +97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116, +101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,83,67,65,76, +69,95,77,79,68,69,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,95,76,105,110,101,97,114,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97, +100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110, +117,34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,79,117,116, +112,117,116,32,115,116,114,101,116,99,104,45,109,111,100,101,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,70,83,91,48,93,34,62,10,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,78,111,110,101,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105, +111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34, +32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,70,83,91,49,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,52,58,51,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105, +111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34, +32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,70,83,91,50,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,83,113,117,97, +114,101,32,112,105,120,101,108,115,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105, +111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68, +77,95,86,73,68,95,70,83,91,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,95,73,110,116,101,103,101,114,32,115,99,97,108, +101,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114, +97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,77,101,110,117,34,32,110,97,109,101,61,34,73,68,77, +95,86,73,68,95,83,67,65,76,69,95,77,69,78,85,34,62,10,32,32,32,32,32,32, +32,32,60,108,97,98,101,108,62,79,117,116,112,117,116,32,115,99,97,108,101, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109, +34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,83,67,65,76,69,91,48, +93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,48,46, +53,120,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114, +97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116, +101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,83,67,65,76, +69,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,49,120,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60, +114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73, +116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,83,67,65, +76,69,91,50,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,49,46,53,120,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32, +32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101, +110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68, +95,83,67,65,76,69,91,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,50,120,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32, +32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77, +101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73, +68,95,83,67,65,76,69,91,52,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,50,46,53,120,60,47,108,97,98,101,108,62,10,32,32,32, +32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111, +62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95, +86,73,68,95,83,67,65,76,69,91,53,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,51,120,60,47,108,97,98,101,108,62,10,32,32,32, +32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111, +62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95, +86,73,68,95,83,67,65,76,69,91,54,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,51,46,53,120,60,47,108,97,98,101,108,62,10,32, +32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100, +105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73, +68,77,95,86,73,68,95,83,67,65,76,69,91,55,93,34,62,10,32,32,32,32,32,32, +32,32,32,32,60,108,97,98,101,108,62,52,120,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97, +100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,101,112,97,114, +97,116,111,114,34,47,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,34,32,110,97,109,101,61, +34,73,68,77,95,86,73,68,95,71,76,51,34,62,10,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,79,112,101,110,71,76,32,51,46,48,32,114,101,110,100, +101,114,101,114,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117, +34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,73,110,112, +117,116,32,115,116,114,101,116,99,104,45,109,111,100,101,60,47,108,97,98, +101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,73,78,80,85,84,95, +83,84,82,69,84,67,72,91,48,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,95,78,111,110,101,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47, +114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32, +110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,73,78,80,85,84, +95,83,84,82,69,84,67,72,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,108,97,98,101,108,62,95,52,58,51,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114, +97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,73,78,80,85,84,95, +83,84,82,69,84,67,72,91,50,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,95,83,113,117,97,114,101,32,112,105,120,101, +108,115,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86, +73,68,95,71,76,51,95,73,78,80,85,84,95,83,84,82,69,84,67,72,91,51,93,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,73, +110,116,101,103,101,114,32,115,99,97,108,101,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47, +114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,77,101,110,117,34,62,10,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,73,110,112,117,116,32,115,99,97,108,101,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34, +32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,73,78,80,85, +84,95,83,67,65,76,69,91,48,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,48,46,53,120,60,47,108,97,98,101,108,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114, +97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,73,78,80,85,84,95, +83,67,65,76,69,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,49,120,60,47,108,97,98,101,108,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34, +73,68,77,95,86,73,68,95,71,76,51,95,73,78,80,85,84,95,83,67,65,76,69,91, +50,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,49,46,53,120,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95, +86,73,68,95,71,76,51,95,73,78,80,85,84,95,83,67,65,76,69,91,51,93,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,50,120,60, +47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97, +100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117, +73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76, +51,95,73,78,80,85,84,95,83,67,65,76,69,91,52,93,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,108,97,98,101,108,62,50,46,53,120,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105, +111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73, +116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51, +95,73,78,80,85,84,95,83,67,65,76,69,91,53,93,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,108,97,98,101,108,62,51,120,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60, +47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34, +32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,73,78,80,85, +84,95,83,67,65,76,69,91,54,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,51,46,53,120,60,47,108,97,98,101,108,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114, +97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,73,78,80,85,84,95, +83,67,65,76,69,91,55,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,52,120,60,47,108,97,98,101,108,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101, +110,117,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62, +83,104,97,100,101,114,32,114,101,102,114,101,115,104,32,114,97,116,101, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101, +109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,83,72, +65,68,69,82,95,82,69,70,82,69,83,72,95,82,65,84,69,91,48,93,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,97,109,101, +32,97,115,32,101,109,117,108,97,116,101,100,32,100,105,115,112,108,97,121, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,114, +97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110, +117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71, +76,51,95,83,72,65,68,69,82,95,82,69,70,82,69,83,72,95,82,65,84,69,91,49, +48,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,49,48,32,104,122,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62, +10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73, +68,77,95,86,73,68,95,71,76,51,95,83,72,65,68,69,82,95,82,69,70,82,69,83, +72,95,82,65,84,69,91,50,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,50,53,32,104,122,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47, +114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32, +110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,83,72,65,68,69, +82,95,82,69,70,82,69,83,72,95,82,65,84,69,91,51,48,93,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,51,48,32,104,122,60, +47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97, +100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117, +73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76, +51,95,83,72,65,68,69,82,95,82,69,70,82,69,83,72,95,82,65,84,69,91,53,48, +93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62, +53,48,32,104,122,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68, +77,95,86,73,68,95,71,76,51,95,83,72,65,68,69,82,95,82,69,70,82,69,83,72, +95,82,65,84,69,91,54,48,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,54,48,32,104,122,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114, +97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,83,72,65,68,69,82, +95,82,69,70,82,69,83,72,95,82,65,84,69,91,55,50,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,55,50,32,104,122,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100, +105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73, +116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51, +95,83,72,65,68,69,82,95,82,69,70,82,69,83,72,95,82,65,84,69,91,56,53,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,56, +53,32,104,122,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,101,112,97,114,97, +116,111,114,34,47,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32, +110,97,109,101,61,34,73,68,77,95,86,73,68,95,71,76,51,95,83,72,65,68,69, +82,95,77,65,78,65,71,69,82,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,83,104,97,100,101,114,32,109,97,110,97,103,101,114,60, +47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,34,62,10,32,32,32, +32,32,32,60,108,97,98,101,108,62,83,111,117,110,100,60,47,108,97,98,101, +108,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,77,101,110,117,34,62,10,32,32,32,32,32,32,32,32,60,108,97, +98,101,108,62,95,66,117,102,102,101,114,32,108,101,110,103,116,104,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32, +110,97,109,101,61,34,73,68,77,95,83,78,68,95,66,85,70,91,48,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,53,48,32,109,115, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100, +105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109, +34,32,110,97,109,101,61,34,73,68,77,95,83,78,68,95,66,85,70,91,49,93,34, +62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,49,48,48, +32,109,115,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117, +73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,83,78,68,95,66,85, +70,91,50,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,95,50,48,48,32,109,115,60,47,108,97,98,101,108,62,10,32,32,32,32,32, +32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62, +10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,83, +78,68,95,66,85,70,91,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,95,52,48,48,32,109,115,60,47,108,97,98,101,108,62,10,32, +32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100, +105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117, +34,62,10,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,79,117,116, +112,117,116,32,108,101,118,101,108,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95, +83,78,68,95,71,65,73,78,91,48,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,95,78,111,114,109,97,108,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114, +97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61, +34,73,68,77,95,83,78,68,95,71,65,73,78,91,49,93,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,108,97,98,101,108,62,43,95,50,32,100,66,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62, +49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,83,78,68,95,71,65,73,78,91,50,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,43,95,52,32,100,66, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100, +105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109, +34,32,110,97,109,101,61,34,73,68,77,95,83,78,68,95,71,65,73,78,91,51,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,43,95,54, +32,100,66,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60, +114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73, +116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,83,78,68,95,71,65,73, +78,91,52,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,43,95,56,32,100,66,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32, +32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101, +110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,83,78,68, +95,71,65,73,78,91,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97, +98,101,108,62,43,95,49,48,32,100,66,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105, +111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68, +77,95,83,78,68,95,71,65,73,78,91,54,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,108,97,98,101,108,62,43,49,50,32,100,66,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114, +97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61, +34,73,68,77,95,83,78,68,95,71,65,73,78,91,55,93,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,108,97,98,101,108,62,43,49,52,32,100,66,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62, +49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110, +97,109,101,61,34,73,68,77,95,83,78,68,95,71,65,73,78,91,56,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,43,49,54,32,100,66, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,114,97,100, +105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109, +34,32,110,97,109,101,61,34,73,68,77,95,83,78,68,95,71,65,73,78,91,57,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,43,49,56, +32,100,66,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60, +114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77, +101,110,117,34,62,10,32,32,32,32,32,32,60,108,97,98,101,108,62,77,105,115, +99,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,34,62,10,32,32,32, +32,32,32,32,32,60,108,97,98,101,108,62,95,83,99,114,101,101,110,115,104, +111,116,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116, +101,109,34,32,110,97,109,101,61,34,73,68,77,95,83,67,82,69,69,78,83,72, +79,84,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95, +84,97,107,101,32,115,99,114,101,101,110,115,104,111,116,92,116,67,116,114, +108,43,65,108,116,43,80,97,103,101,85,112,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77, +101,110,117,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,95,70,111,114,109,97,116,60,47,108,97,98,101,108,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,77,101,110,117,73,116,101,109,34,32,110,97,109,101,61,34,73,68,77,95, +83,67,82,69,69,78,83,72,79,84,95,70,79,82,77,65,84,91,48,93,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,80,78,71,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100, +105,111,62,49,60,47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73, +116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,83,67,82,69,69,78,83, +72,79,84,95,70,79,82,77,65,84,91,49,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,108,97,98,101,108,62,84,73,70,70,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60, +47,114,97,100,105,111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34, +32,110,97,109,101,61,34,73,68,77,95,83,67,82,69,69,78,83,72,79,84,95,70, +79,82,77,65,84,91,50,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,66,77,80,60,47,108,97,98,101,108,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105, +111,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32,110,97,109,101, +61,34,73,68,77,95,83,67,82,69,69,78,83,72,79,84,95,70,79,82,77,65,84,91, +51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,74,80,71,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,114,97,100,105,111,62,49,60,47,114,97,100,105,111,62,10,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,77,101,110,117,73, +116,101,109,34,32,110,97,109,101,61,34,73,68,77,95,83,67,82,69,69,78,83, +72,79,84,95,70,76,65,83,72,34,62,10,32,32,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,70,108,97,115,104,32,115,99,114,101,101,110,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,60,99,104,101,99,107, +97,98,108,101,62,49,60,47,99,104,101,99,107,97,98,108,101,62,10,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,77,101,110,117,73,116,101,109,34,32, +110,97,109,101,61,34,73,68,77,95,83,84,65,84,85,83,34,62,10,32,32,32,32, +32,32,32,32,60,108,97,98,101,108,62,95,77,97,99,104,105,110,101,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,60,105,100,115,45,114,97,110,103,101,32,110,97,109,101, +61,34,73,68,67,95,72,68,80,65,78,69,76,34,32,115,116,97,114,116,61,34,49, +48,34,47,62,10,32,32,60,105,100,115,45,114,97,110,103,101,32,110,97,109, +101,61,34,73,68,67,95,67,79,77,66,79,68,82,73,86,69,84,89,80,69,34,32,115, +116,97,114,116,61,34,49,48,48,34,47,62,10,32,32,60,105,100,115,45,114,97, +110,103,101,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,70,78,34, +32,115,116,97,114,116,61,34,51,48,48,34,47,62,10,32,32,60,105,100,115,45, +114,97,110,103,101,32,110,97,109,101,61,34,73,68,67,95,70,73,76,69,34,32, +115,116,97,114,116,61,34,52,48,48,34,47,62,10,32,32,60,105,100,115,45,114, +97,110,103,101,32,110,97,109,101,61,34,73,68,67,95,69,74,69,67,84,34,32, +115,116,97,114,116,61,34,53,48,48,34,47,62,10,32,32,60,105,100,115,45,114, +97,110,103,101,32,110,97,109,101,61,34,73,68,67,95,78,69,87,34,32,115,116, +97,114,116,61,34,54,48,48,34,47,62,10,32,32,60,105,100,115,45,114,97,110, +103,101,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,83,80,84,34, +32,115,116,97,114,116,61,34,55,48,48,34,47,62,10,32,32,60,105,100,115,45, +114,97,110,103,101,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,72, +80,67,34,32,115,116,97,114,116,61,34,56,48,48,34,47,62,10,32,32,60,105, +100,115,45,114,97,110,103,101,32,110,97,109,101,61,34,73,68,67,95,69,68, +73,84,95,67,89,76,34,32,115,116,97,114,116,61,34,57,48,48,34,47,62,10,32, +32,60,105,100,115,45,114,97,110,103,101,32,110,97,109,101,61,34,73,68,67, +95,84,69,88,84,95,83,73,90,69,34,32,115,116,97,114,116,61,34,49,48,48,48, +34,47,62,10,32,32,60,105,100,115,45,114,97,110,103,101,32,110,97,109,101, +61,34,73,68,67,95,72,68,68,95,76,65,66,69,76,34,32,115,116,97,114,116,61, +34,49,49,48,48,34,47,62,10,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,68,105,97,108,111,103,34,32,110,97,109,101,61,34, +67,111,110,102,105,103,117,114,101,68,108,103,34,62,10,32,32,32,32,60,115, +116,121,108,101,62,119,120,68,69,70,65,85,76,84,95,68,73,65,76,79,71,95, +83,84,89,76,69,60,47,115,116,121,108,101,62,10,32,32,32,32,60,116,105,116, +108,101,62,67,111,110,102,105,103,117,114,101,32,80,67,101,109,60,47,116, +105,116,108,101,62,10,32,32,32,32,60,99,101,110,116,101,114,101,100,62, +49,60,47,99,101,110,116,101,114,101,100,62,10,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110,101,108,34,32,110, +97,109,101,61,34,82,79,79,84,95,80,65,78,69,76,34,62,10,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101, +120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32, +60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32,32, +32,32,60,99,111,108,115,62,49,60,47,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32,32, +32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,47,62,10, +32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115, +47,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +65,76,76,124,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,78,111,116,101,98,111,111,107,34,32, +110,97,109,101,61,34,73,68,67,95,78,79,84,69,66,79,79,75,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,78,66,95, +68,69,70,65,85,76,84,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,110, +111,116,101,98,111,111,107,112,97,103,101,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,115,101,108,101,99,116,101,100,62,49,60,47,115, +101,108,101,99,116,101,100,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101, +115,46,99,112,112,36,105,99,111,110,115,95,51,50,120,51,50,95,109,111,116, +104,101,114,98,111,97,114,100,46,112,110,103,60,47,98,105,116,109,97,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,80,97,110,101,108,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120, +84,65,66,95,84,82,65,86,69,82,83,65,76,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,70,108,101,120,71,114,105,100,83,105, +122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,51,60,47,99, +111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,104,103,97,112,62,48,60,47,104,103, +97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103, +114,111,119,97,98,108,101,99,111,108,115,62,49,60,47,103,114,111,119,97, +98,108,101,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62, +53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101, +62,56,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,77,97,99, +104,105,110,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60, +47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105, +111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,66,111,120,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116,62,119,120, +72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111,109,98,111, +66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66,79,49,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79, +87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108, +101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101, +110,116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117, +116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,67,79,78,70,73,71, +85,82,69,77,79,68,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115, +111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120, +49,54,95,115,101,116,116,105,110,103,95,116,111,111,108,115,46,112,110, +103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60, +47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62, +53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101, +62,56,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,80,85, +58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97, +112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83, +105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90, +79,78,84,65,76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111,120, +34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66,79,67,80,85,77,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87, +78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,105,122,101,62,49,50,48,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111,109, +98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66,79, +51,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82,79,80, +68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116, +121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,50,50,48,44,45,49,60,47,115, +105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110, +116,101,110,116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105, +122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69, +82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,56,48,44, +45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,70,80,85,58,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101, +114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65, +76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110, +97,109,101,61,34,73,68,67,95,67,79,77,66,79,70,80,85,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119, +120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,49,50,48,44,45,49,60,47,115,105,122,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110,116, +47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48, +44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,104,101, +99,107,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,72,69,67,75, +68,89,78,65,82,69,67,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,68,121,110,97,109,105,99, +32,114,101,99,111,109,112,105,108,101,114,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99, +104,101,99,107,101,100,62,48,60,47,99,104,101,99,107,101,100,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119, +120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47, +102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99, +84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,108,97,98,101,108,62,77,101,109,111,114,121,58,60, +47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47, +102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78, +84,65,76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,83,112,105,110,67,116,114,108,34,32,110, +97,109,101,61,34,73,68,67,95,77,69,77,83,80,73,78,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +116,121,108,101,62,119,120,83,80,95,65,82,82,79,87,95,75,69,89,83,60,47, +115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,62,48,60,47,118, +97,108,117,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,109,105,110,62,48,60,47,109,105,110,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,109,97,120,62,49,48,60,47,109,97,120,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84, +69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120, +116,34,32,110,97,109,101,61,34,73,68,67,95,84,69,88,84,95,77,66,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,108,97,98,101,108,62,77,66,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,87,97,105,116,115,116,97,116,101,115,58,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101, +114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65, +76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110, +97,109,101,61,34,73,68,67,95,67,79,77,66,79,87,83,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120, +67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110,116,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48, +44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,104,101, +99,107,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,72,69,67,75, +83,89,78,67,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,108,97,98,101,108,62,83,121,110,99,104,114,111,110,105, +122,101,32,116,105,109,101,32,116,111,32,104,111,115,116,32,99,108,111, +99,107,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,99,104,101,99,107,101,100,62,48,60,47, +99,104,101,99,107,101,100,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,110,111,116,101,98,111,111,107,112, +97,103,101,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,101, +108,101,99,116,101,100,62,48,60,47,115,101,108,101,99,116,101,100,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119, +120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110, +115,95,51,50,120,51,50,95,118,105,100,101,111,95,109,111,100,101,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +80,97,110,101,108,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,116,121,108,101,62,119,120,84,65,66,95,84,82,65,86,69,82,83,65, +76,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114, +111,119,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118,103, +97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,104, +103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108, +115,62,49,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98, +108,101,114,111,119,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120, +65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,105,122,101,62,56,48,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,68,101,118,105,99,101,58,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114, +105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114, +105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61, +34,73,68,67,95,67,79,77,66,79,86,73,68,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108, +101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67,66,95,82, +69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105, +122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97, +108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,66,105,116,109,97,112,66,117,116,116,111,110,34,32, +110,97,109,101,61,34,73,68,67,95,67,79,78,70,73,71,85,82,69,86,73,68,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115, +46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,115,101,116,116, +105,110,103,95,116,111,111,108,115,46,112,110,103,60,47,98,105,116,109, +97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102,97,117,108, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32, +119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116, +105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,56,48,44,45,49,60,47,115, +105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,108,97,98,101,108,62,83,112,101,101,100,58,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110, +97,109,101,61,34,73,68,67,95,67,79,77,66,79,83,80,68,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121, +108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,32,124,32,119,120,67, +66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108, +117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115, +105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60, +47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105, +122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79, +78,84,65,76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108, +97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100, +101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,67,104,101,99,107,66,111,120,34,32,110, +97,109,101,61,34,73,68,67,95,67,72,69,67,75,86,79,79,68,79,79,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,108,97,98,101,108,62,86,111,111,100,111,111,32,71,114,97,112,104, +105,99,115,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,104,101,99,107,101, +100,62,48,60,47,99,104,101,99,107,101,100,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61, +34,73,68,67,95,67,79,78,70,73,71,85,82,69,86,79,79,68,79,79,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105, +116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46,99,112, +112,36,105,99,111,110,115,95,49,54,120,49,54,95,115,101,116,116,105,110, +103,95,116,111,111,108,115,46,112,110,103,60,47,98,105,116,109,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +100,101,102,97,117,108,116,62,48,60,47,100,101,102,97,117,108,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,110,111,116, +101,98,111,111,107,112,97,103,101,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,101,108,101,99,116,101,100,62,48,60,47,115,101,108,101, +99,116,101,100,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105, +116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46,99,112, +112,36,105,99,111,110,115,95,51,50,120,51,50,95,115,111,117,110,100,46, +112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,80,97,110,101,108,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,115,116,121,108,101,62,119,120,84,65,66,95,84,82,65,86,69,82,83, +65,76,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60, +47,114,111,119,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118, +103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111, +108,115,62,49,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119, +97,98,108,101,114,111,119,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120, +65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,105,122,101,62,56,48,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,68,101,118,105,99,101,58,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114, +105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114, +105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61, +34,73,68,67,95,67,79,77,66,79,83,78,68,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108, +101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67,66,95,82, +69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105, +122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97, +108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,66,105,116,109,97,112,66,117,116,116,111,110,34,32, +110,97,109,101,61,34,73,68,67,95,67,79,78,70,73,71,85,82,69,83,78,68,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115, +46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,115,101,116,116, +105,110,103,95,116,111,111,108,115,46,112,110,103,60,47,98,105,116,109, +97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102,97,117,108, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62, +48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,104,101,99, +107,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,72,69,67,75,51, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,67,77,83,32,47,32,71,97,109,101,32,66,108,97, +115,116,101,114,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,104,101,99,107,101,100,62, +48,60,47,99,104,101,99,107,101,100,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101, +114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115, +105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,67,104,101,99,107,66,111,120,34,32,110, +97,109,101,61,34,73,68,67,95,67,72,69,67,75,71,85,83,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,71,114,97,118,105,115,32,85,108,116,114,97,115,111,117,110,100,60, +47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,99,104,101,99,107,101,100,62,48,60,47,99,104,101, +99,107,101,100,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60, +47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65, +78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,67,104,101,99,107,66,111,120,34,32,110,97,109,101,61,34,73,68,67, +95,67,72,69,67,75,83,83,73,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,73,110,110,111,118, +97,116,105,111,110,32,83,83,73,45,50,48,48,49,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +99,104,101,99,107,101,100,62,48,60,47,99,104,101,99,107,101,100,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119, +120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47, +102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99, +84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,105,122,101,62,56,48,44,45,49,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,76,80,84,32,68,101,118,105,99,101,58,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101, +114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65, +76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110, +97,109,101,61,34,73,68,67,95,67,79,77,66,79,76,80,84,49,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,115,116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124, +119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,110, +111,116,101,98,111,111,107,112,97,103,101,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,115,101,108,101,99,116,101,100,62,48,60,47,115, +101,108,101,99,116,101,100,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101, +115,46,99,112,112,36,105,99,111,110,115,95,51,50,120,51,50,95,100,114,105, +118,101,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,80,97,110,101,108,34,32,110,97,109,101,61,34,80,65,78,69, +76,95,68,82,73,86,69,83,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,115,116,121,108,101,62,119,120,84,65,66,95,84,82,65,86,69,82, +83,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60, +47,114,111,119,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,99,111,108,115,62,49,60,47,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118, +103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111, +108,115,62,48,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119, +97,98,108,101,114,111,119,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47, +102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,111,114,100,101,114,62,48,60,47,98,111,114,100,101,114,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101,120,71,114, +105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119, +115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97,112,62,48, +60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103, +114,111,119,97,98,108,101,99,111,108,115,62,49,60,47,103,114,111,119,97, +98,108,101,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119, +115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +105,122,101,62,56,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97, +98,101,108,62,72,68,68,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114, +97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76, +60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61,34,73, +68,67,95,67,79,77,66,79,72,68,68,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116, +121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67, +66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117,116,116,111, +110,34,32,110,97,109,101,61,34,73,68,67,95,67,79,78,70,73,71,85,82,69,72, +68,68,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115, +111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120, +49,54,95,115,101,116,116,105,110,103,95,116,111,111,108,115,46,112,110, +103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108, +116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105, +111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100, +101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,56,48,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,108,97,98,101,108,62,70,68,68,49,58,60,47,108,97,98,101, +108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83, +105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116,62,119,120,72, +79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111,120, +34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66,79,68,82,65,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82,79,80, +68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116, +121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45, +49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105, +122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120, +65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101, +62,56,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,70,68,68,50,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112, +62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62, +53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47, +111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61,34,73, +68,67,95,67,79,77,66,79,68,82,66,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116, +121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67, +66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95, +67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105, +99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,56,48,44,45,49,60, +47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,68,32,77,111,100, +101,108,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105, +122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111, +114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67, +95,67,79,77,66,79,95,67,68,77,79,68,69,76,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119, +120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95, +67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105, +99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,56,48,44,45,49,60, +47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,68,32,83,112,101, +101,100,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105, +122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111, +114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67, +95,67,79,77,66,79,95,67,68,83,80,69,69,68,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119, +120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,32,124,32,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116, +105,99,76,105,110,101,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,76,73,95,72,79, +82,73,90,79,78,84,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,32,124,32,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,104,111, +105,99,101,98,111,111,107,34,32,110,97,109,101,61,34,73,68,67,95,72,68, +67,66,79,79,75,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,72,66,95,68,69,70, +65,85,76,84,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,110,111,116,101,98,111,111,107,112, +97,103,101,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,101, +108,101,99,116,101,100,62,48,60,47,115,101,108,101,99,116,101,100,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119, +120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110, +115,95,51,50,120,51,50,95,109,111,117,115,101,95,112,99,46,112,110,103, +60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110, +101,108,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +116,121,108,101,62,119,120,84,65,66,95,84,82,65,86,69,82,83,65,76,60,47, +115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101, +120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119, +115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111, +108,115,62,50,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,104,103,97, +112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49, +60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101, +114,111,119,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,56,48,44,45,49,60,47,115,105,122,101,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97, +98,101,108,62,77,111,117,115,101,58,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114, +97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110, +116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47, +102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95, +67,79,77,66,79,77,79,85,83,69,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62, +119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67,66,95,82,69,65, +68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101, +62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117, +101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,110,111,116,101,98,111,111,107,112, +97,103,101,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,101, +108,101,99,116,101,100,62,48,60,47,115,101,108,101,99,116,101,100,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119, +120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110, +115,95,51,50,120,51,50,95,106,111,121,115,116,105,99,107,46,112,110,103, +60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110, +101,108,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +116,121,108,101,62,119,120,84,65,66,95,84,82,65,86,69,82,83,65,76,60,47, +115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101, +120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,50,60,47,114,111,119, +115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111, +108,115,62,48,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,104,103,97, +112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,47,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111, +119,97,98,108,101,114,111,119,115,47,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,70,108,101,120,71,114,105,100,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62, +52,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108, +101,99,111,108,115,62,49,60,47,103,114,111,119,97,98,108,101,99,111,108, +115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116, +105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,56,48,44,45,49, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,74,111,121,115, +116,105,99,107,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112, +62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62, +53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47, +111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61,34,73, +68,67,95,67,79,77,66,79,74,79,89,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116, +121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67, +66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,71,114,105,100, +83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +99,111,108,115,62,52,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108, +97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100, +101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,66,117,116,116,111,110,34,32,110,97, +109,101,61,34,73,68,67,95,74,79,89,49,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,74,111,121,115,116,105,99,107,32,49,46,46,46,60,47,108,97,98,101, +108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,100,101,102,97,117,108,116,62,49,60,47,100,101,102,97, +117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117, +116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,74,79,89,50,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,108,97,98,101,108,62,74,111,121,115,116,105,99,107,32,50,46, +46,46,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116, +62,49,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,74,79,89,51,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,74,111,121, +115,116,105,99,107,32,51,46,46,46,60,47,108,97,98,101,108,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +100,101,102,97,117,108,116,62,49,60,47,100,101,102,97,117,108,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116,116,111,110, +34,32,110,97,109,101,61,34,73,68,67,95,74,79,89,52,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,74,111,121,115,116,105,99,107,32,52,46,46,46,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,49,60,47,100, +101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,110,111,116,101,98,111,111,107,112,97,103,101,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,47,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,115,101,108,101,99,116,101,100,62,48,60, +47,115,101,108,101,99,116,101,100,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114, +99,101,115,46,99,112,112,36,105,99,111,110,115,95,51,50,120,51,50,95,110, +101,116,119,111,114,107,95,101,116,104,101,114,110,101,116,46,112,110,103, +60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110, +101,108,34,32,110,97,109,101,61,34,109,95,112,97,110,101,108,110,101,116, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121, +108,101,62,119,120,84,65,66,95,84,82,65,86,69,82,83,65,76,60,47,115,116, +121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101,120,71, +114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108, +115,62,50,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,104,103,97,112,62, +48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49,60,47, +103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111, +119,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97, +109,101,61,34,109,95,115,116,97,116,105,99,84,101,120,116,55,48,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +105,122,101,62,56,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,78,101,116,119,111,114,107,32,99,97,114,100,32,58,60,47,108,97,98,101, +108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47, +111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101, +61,34,73,68,67,95,67,79,77,66,79,95,78,69,84,67,65,82,68,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,115,116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124, +119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,105,116, +109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95, +67,79,78,70,73,71,85,82,69,95,78,69,84,67,65,82,68,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +116,121,108,101,62,119,120,66,85,95,65,85,84,79,68,82,65,87,60,47,115,116, +121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101, +115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54, +120,49,54,95,115,101,116,116,105,110,103,95,116,111,111,108,115,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108, +116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105, +122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60, +47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100, +101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111, +120,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47, +111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100, +101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116, +116,111,110,34,32,110,97,109,101,61,34,119,120,73,68,95,79,75,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62, +79,75,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,100,101,102,97,117,108,116,62,49,60,47,100,101,102,97,117, +108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,117,116,116,111,110,34,32,110,97,109,101,61,34,119,120,73,68,95,67,65, +78,67,69,76,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,67,97,110,99,101,108,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108, +116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110,101,108,34, +32,110,97,109,101,61,34,73,68,67,95,72,68,80,65,78,69,76,91,48,93,34,62, +10,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,84,65,66,95,84,82, +65,86,69,82,83,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101, +120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32, +60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32,32, +32,32,60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32,32, +32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,50,60, +47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32,32, +32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,48,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,105,122,101,62,55,53,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,84,121, +112,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101, +109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111, +109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66, +79,68,82,73,86,69,84,89,80,69,91,48,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82, +79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115, +116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117, +116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,78,69,87,91,48,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,78,101,119,60,47,116,111,111,108,116,105,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62, +119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111, +110,115,95,49,54,120,49,54,95,100,114,105,118,101,95,97,100,100,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102, +97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,70,73,76,69,91,48,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,116,111,111,108,116,105,112,62,66,114,111,119,115,101,60,47,116, +111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46, +99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,102,111,108,100, +101,114,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101, +102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84, +73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34, +73,68,67,95,72,68,68,95,76,65,66,69,76,91,49,93,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,108,97,98,101,108,62,70,105,108,101,58,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112, +62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119, +120,65,76,76,124,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111, +114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,84,101,120,116,67,116,114,108,34, +32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,70,78,91,48,93,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120, +84,69,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60, +47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97, +108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,69,74,69,67,84,91,48,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114, +99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,99, +111,110,116,114,111,108,95,101,106,101,99,116,46,112,110,103,60,47,98,105, +116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,69,106,101,99,116,60,47,116,111,111,108,116,105,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116, +62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65, +78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111, +114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,52,60,47, +99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97, +112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49,44, +51,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115, +47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73, +71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68, +67,95,72,68,68,95,76,65,66,69,76,91,50,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,101,99,116,111,114, +115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69, +78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97, +116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67,95,69,68, +73,84,95,83,80,84,91,48,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82, +84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116, +34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69,76,91,51, +93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98, +101,108,62,72,101,97,100,115,58,60,47,108,97,98,101,108,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47, +119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120, +65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61, +34,73,68,67,95,69,68,73,84,95,72,80,67,91,48,93,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108, +97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78, +84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116, +105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95, +76,65,66,69,76,91,52,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,108,97,98,101,108,62,67,121,108,105,110,100,101,114,58,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,67,89,76, +91,48,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118, +97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120, +65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61, +34,73,68,67,95,72,68,68,95,76,65,66,69,76,91,53,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,105,122, +101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69, +78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97, +116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67,95,84,69, +88,84,95,83,73,90,69,91,48,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,80,97,110,101,108,34,32,110,97,109,101,61,34,73, +68,67,95,72,68,80,65,78,69,76,91,49,93,34,62,10,32,32,32,32,32,32,60,115, +116,121,108,101,62,119,120,84,65,66,95,84,82,65,86,69,82,83,65,76,60,47, +115,116,121,108,101,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,70,108,101,120,71,114,105,100,83,105,122, +101,114,34,62,10,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47, +114,111,119,115,62,10,32,32,32,32,32,32,32,32,60,99,111,108,115,62,51,60, +47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,60,118,103,97,112,62,48, +60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,60,104,103,97,112,62, +48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32,60,103,114,111,119, +97,98,108,101,99,111,108,115,62,50,60,47,103,114,111,119,97,98,108,101, +99,111,108,115,62,10,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108, +101,114,111,119,115,47,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108, +97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78, +84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34, +32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69,76,91,49,48, +93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,55, +53,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,84,121,112,101,58,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47, +119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,66,111,120,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65, +76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110,97,109, +101,61,34,73,68,67,95,67,79,77,66,79,68,82,73,86,69,84,89,80,69,91,49,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121, +108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67,66,95, +82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45,49, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112, +97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,78,69,87,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,116,111,111,108,116,105,112,62,78,101,119,60,47,116,111, +111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101, +115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,100,114,105, +118,101,95,97,100,100,46,112,110,103,60,47,98,105,116,109,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108, +116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,66,105,116,109,97,112,66,117,116,116,111,110,34,32,110, +97,109,101,61,34,73,68,67,95,70,73,76,69,91,49,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,116,111,111,108,116,105,112,62,66,114,111,119, +115,101,60,47,116,111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117, +114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95, +102,111,108,100,101,114,46,112,110,103,60,47,98,105,116,109,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48, +60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69,76,91,49,49,93,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,70,105, +108,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101, +109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,76,124,119,120,69,88,80,65,78,68,60,47, +102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120, +116,67,116,114,108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95, +70,78,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116, +121,108,101,62,119,120,84,69,95,82,69,65,68,79,78,76,89,60,47,115,116,121, +108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62, +51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97, +109,101,61,34,73,68,67,95,69,74,69,67,84,91,49,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101, +115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54, +120,49,54,95,99,111,110,116,114,111,108,95,101,106,101,99,116,46,112,110, +103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,116,111,111,108,116,105,112,62,69,106,101,99,116,60,47,116,111,111, +108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102, +97,117,108,116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119, +120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114, +111,119,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115, +62,52,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108, +115,62,49,44,51,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114, +111,119,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120, +65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61, +34,73,68,67,95,72,68,68,95,76,65,66,69,76,91,49,50,93,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,101,99, +116,111,114,115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,83,80,84,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,49,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,72,101,97,100,115,58,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62, +45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,69,68,73,84,95,72,80,67,91,49,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,49,52,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,121,108,105,110,100, +101,114,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,67,89,76,91,49,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,49,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,83,105,122,101,58,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32, +119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97, +109,101,61,34,73,68,67,95,84,69,88,84,95,83,73,90,69,91,49,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,115,105,122, +101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110,101, +108,34,32,110,97,109,101,61,34,73,68,67,95,72,68,80,65,78,69,76,91,50,93, +34,62,10,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,84,65,66,95, +84,82,65,86,69,82,83,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108, +101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32, +32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32, +32,32,32,60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32, +32,32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32, +32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,50, +60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,50,48,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,55,53,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,84,121, +112,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101, +109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111, +109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66, +79,68,82,73,86,69,84,89,80,69,91,50,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82, +79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115, +116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117, +116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,78,69,87,91,50,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,78,101,119,60,47,116,111,111,108,116,105,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62, +119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111, +110,115,95,49,54,120,49,54,95,100,114,105,118,101,95,97,100,100,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102, +97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,70,73,76,69,91,50,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,116,111,111,108,116,105,112,62,66,114,111,119,115,101,60,47,116, +111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46, +99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,102,111,108,100, +101,114,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101, +102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84, +73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34, +73,68,67,95,72,68,68,95,76,65,66,69,76,91,50,49,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,70,105,108,101,58,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114, +97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,124,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120,116,67,116,114, +108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,70,78,91,50,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62, +119,120,84,69,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45, +49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118, +97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,69,74,69,67,84,91,50,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114, +99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,99, +111,110,116,114,111,108,95,101,106,101,99,116,46,112,110,103,60,47,98,105, +116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,69,106,101,99,116,60,47,116,111,111,108,116,105,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116, +62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65, +78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111, +114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,52,60,47, +99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97, +112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49,44, +51,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115, +47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73, +71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68, +67,95,72,68,68,95,76,65,66,69,76,91,50,50,93,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,101,99,116,111, +114,115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,83,80,84,91,50,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,50,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,72,101,97,100,115,58,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62, +45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,69,68,73,84,95,72,80,67,91,50,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,50,52,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,121,108,105,110,100, +101,114,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,67,89,76,91,50,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,50,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,83,105,122,101,58,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32, +119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97, +109,101,61,34,73,68,67,95,84,69,88,84,95,83,73,90,69,91,50,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,115,105,122, +101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110,101, +108,34,32,110,97,109,101,61,34,73,68,67,95,72,68,80,65,78,69,76,91,51,93, +34,62,10,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,84,65,66,95, +84,82,65,86,69,82,83,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108, +101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32, +32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32, +32,32,32,60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32, +32,32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32, +32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,50, +60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,51,48,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,55,53,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,84,121, +112,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101, +109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111, +109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66, +79,68,82,73,86,69,84,89,80,69,91,51,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82, +79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115, +116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117, +116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,78,69,87,91,51,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,78,101,119,60,47,116,111,111,108,116,105,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62, +119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111, +110,115,95,49,54,120,49,54,95,100,114,105,118,101,95,97,100,100,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102, +97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,70,73,76,69,91,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,116,111,111,108,116,105,112,62,66,114,111,119,115,101,60,47,116, +111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46, +99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,102,111,108,100, +101,114,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101, +102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84, +73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34, +73,68,67,95,72,68,68,95,76,65,66,69,76,91,51,49,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,70,105,108,101,58,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114, +97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,124,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120,116,67,116,114, +108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,70,78,91,51,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62, +119,120,84,69,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45, +49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118, +97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,69,74,69,67,84,91,51,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114, +99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,99, +111,110,116,114,111,108,95,101,106,101,99,116,46,112,110,103,60,47,98,105, +116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,69,106,101,99,116,60,47,116,111,111,108,116,105,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116, +62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65, +78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111, +114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,52,60,47, +99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97, +112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49,44, +51,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115, +47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73, +71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68, +67,95,72,68,68,95,76,65,66,69,76,91,51,50,93,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,101,99,116,111, +114,115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,83,80,84,91,51,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,51,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,72,101,97,100,115,58,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62, +45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,69,68,73,84,95,72,80,67,91,51,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,51,52,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,121,108,105,110,100, +101,114,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,67,89,76,91,51,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,51,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,83,105,122,101,58,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32, +119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97, +109,101,61,34,73,68,67,95,84,69,88,84,95,83,73,90,69,91,51,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,115,105,122, +101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110,101, +108,34,32,110,97,109,101,61,34,73,68,67,95,72,68,80,65,78,69,76,91,52,93, +34,62,10,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,84,65,66,95, +84,82,65,86,69,82,83,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108, +101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32, +32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32, +32,32,32,60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32, +32,32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32, +32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,50, +60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,52,48,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,55,53,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,84,121, +112,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101, +109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111, +109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66, +79,68,82,73,86,69,84,89,80,69,91,52,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82, +79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115, +116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117, +116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,78,69,87,91,52,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,78,101,119,60,47,116,111,111,108,116,105,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62, +119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111, +110,115,95,49,54,120,49,54,95,100,114,105,118,101,95,97,100,100,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102, +97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,70,73,76,69,91,52,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,116,111,111,108,116,105,112,62,66,114,111,119,115,101,60,47,116, +111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46, +99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,102,111,108,100, +101,114,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101, +102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84, +73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34, +73,68,67,95,72,68,68,95,76,65,66,69,76,91,52,49,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,70,105,108,101,58,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114, +97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,124,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120,116,67,116,114, +108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,70,78,91,52,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62, +119,120,84,69,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45, +49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118, +97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,69,74,69,67,84,91,52,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114, +99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,99, +111,110,116,114,111,108,95,101,106,101,99,116,46,112,110,103,60,47,98,105, +116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,69,106,101,99,116,60,47,116,111,111,108,116,105,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116, +62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65, +78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111, +114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,52,60,47, +99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97, +112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49,44, +51,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115, +47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73, +71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68, +67,95,72,68,68,95,76,65,66,69,76,91,52,50,93,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,101,99,116,111, +114,115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,83,80,84,91,52,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,52,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,72,101,97,100,115,58,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62, +45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,69,68,73,84,95,72,80,67,91,52,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,52,52,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,121,108,105,110,100, +101,114,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,67,89,76,91,52,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,52,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,83,105,122,101,58,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32, +119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97, +109,101,61,34,73,68,67,95,84,69,88,84,95,83,73,90,69,91,52,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,115,105,122, +101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110,101, +108,34,32,110,97,109,101,61,34,73,68,67,95,72,68,80,65,78,69,76,91,53,93, +34,62,10,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,84,65,66,95, +84,82,65,86,69,82,83,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108, +101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32, +32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32, +32,32,32,60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32, +32,32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32, +32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,50, +60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,53,48,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,55,53,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,84,121, +112,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101, +109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111, +109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66, +79,68,82,73,86,69,84,89,80,69,91,53,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82, +79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115, +116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117, +116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,78,69,87,91,53,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,78,101,119,60,47,116,111,111,108,116,105,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62, +119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111, +110,115,95,49,54,120,49,54,95,100,114,105,118,101,95,97,100,100,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102, +97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,70,73,76,69,91,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,116,111,111,108,116,105,112,62,66,114,111,119,115,101,60,47,116, +111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46, +99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,102,111,108,100, +101,114,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101, +102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84, +73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34, +73,68,67,95,72,68,68,95,76,65,66,69,76,91,53,49,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,70,105,108,101,58,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114, +97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,124,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120,116,67,116,114, +108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,70,78,91,53,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62, +119,120,84,69,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45, +49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118, +97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,69,74,69,67,84,91,53,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114, +99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,99, +111,110,116,114,111,108,95,101,106,101,99,116,46,112,110,103,60,47,98,105, +116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,69,106,101,99,116,60,47,116,111,111,108,116,105,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116, +62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65, +78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111, +114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,52,60,47, +99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97, +112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49,44, +51,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115, +47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73, +71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68, +67,95,72,68,68,95,76,65,66,69,76,91,53,50,93,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,101,99,116,111, +114,115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,83,80,84,91,53,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,53,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,72,101,97,100,115,58,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62, +45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,69,68,73,84,95,72,80,67,91,53,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,53,52,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,121,108,105,110,100, +101,114,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,67,89,76,91,53,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,53,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,83,105,122,101,58,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32, +119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97, +109,101,61,34,73,68,67,95,84,69,88,84,95,83,73,90,69,91,53,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,115,105,122, +101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97,110,101, +108,34,32,110,97,109,101,61,34,73,68,67,95,72,68,80,65,78,69,76,91,54,93, +34,62,10,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,84,65,66,95, +84,82,65,86,69,82,83,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108, +101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32, +32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32, +32,32,32,60,99,111,108,115,62,51,60,47,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32, +32,32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32, +32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,50, +60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32, +32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,54,48,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,55,53,44,45,49,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,84,121, +112,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101, +109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111, +109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66, +79,68,82,73,86,69,84,89,80,69,91,54,93,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82, +79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115, +116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117, +116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,78,69,87,91,54,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,78,101,119,60,47,116,111,111,108,116,105,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62, +119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111, +110,115,95,49,54,120,49,54,95,100,114,105,118,101,95,97,100,100,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102, +97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,70,73,76,69,91,54,93,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,116,111,111,108,116,105,112,62,66,114,111,119,115,101,60,47,116, +111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115,46, +99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,102,111,108,100, +101,114,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101, +102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84, +73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34, +73,68,67,95,72,68,68,95,76,65,66,69,76,91,54,49,93,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,70,105,108,101,58,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114, +97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,124,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120,116,67,116,114, +108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,95,70,78,91,54,93, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62, +119,120,84,69,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45, +49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118, +97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,69,74,69,67,84,91,54,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114, +99,101,115,46,99,112,112,36,105,99,111,110,115,95,49,54,120,49,54,95,99, +111,110,116,114,111,108,95,101,106,101,99,116,46,112,110,103,60,47,98,105, +116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111, +108,116,105,112,62,69,106,101,99,116,60,47,116,111,111,108,116,105,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116, +62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65, +78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111, +114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,52,60,47, +99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97, +112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49,44, +51,60,47,103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115, +47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73, +71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68, +67,95,72,68,68,95,76,65,66,69,76,91,54,50,93,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,83,101,99,116,111, +114,115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,83,80,84,91,54,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,54,51,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,72,101,97,100,115,58,60,47,108,97,98,101,108,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62, +45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,69,68,73,84,95,72,80,67,91,54,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,72,68,68,95,76,65,66,69,76,91,54,52,93,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,121,108,105,110,100, +101,114,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,73,68,67, +95,69,68,73,84,95,67,89,76,91,54,93,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,32,124,32,119,120,65,76,73,71,78,95,67,69,78,84,69,82, +95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101, +120,116,34,32,110,97,109,101,61,34,73,68,67,95,72,68,68,95,76,65,66,69, +76,91,54,53,93,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,83,105,122,101,58,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32, +119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97, +109,101,61,34,73,68,67,95,84,69,88,84,95,83,73,90,69,91,54,93,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,115,105,122, +101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,68,105,97,108,111,103,34,32,110,97,109,101,61,34,72,100, +78,101,119,68,108,103,34,62,10,32,32,32,32,60,116,105,116,108,101,62,78, +101,119,32,72,97,114,100,32,68,105,115,99,60,47,116,105,116,108,101,62, +10,32,32,32,32,60,99,101,110,116,101,114,101,100,62,49,60,47,99,101,110, +116,101,114,101,100,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,80,97,110,101,108,34,32,110,97,109,101,61,34,82, +79,79,84,95,80,65,78,69,76,34,62,10,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,70,108,101,120,71,114,105,100, +83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,60,114,111,119,115, +62,48,60,47,114,111,119,115,62,10,32,32,32,32,32,32,32,32,60,99,111,108, +115,62,49,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,60,118,103, +97,112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,60,104, +103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32,60, +103,114,111,119,97,98,108,101,99,111,108,115,47,62,10,32,32,32,32,32,32, +32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78, +68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +70,108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114,111,119,115,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,51,60,47,99, +111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97,112, +62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115,62,49,60,47, +103,114,111,119,97,98,108,101,99,111,108,115,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,108,97,98,101,108,62,73,109,97,103,101,32,70,111, +114,109,97,116,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111, +109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,72,68,70,79, +82,77,65,84,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,116,121,108,101,62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119, +120,67,66,95,82,69,65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53, +48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101, +62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,73, +71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,124,119,120,65,76, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,56,48, +44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,108,97,98,101,108,62,78,101,119,32,70,105,108,101,58,60, +47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,84,101,120,116,67,116,114,108,34, +32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,67,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45, +49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,66,105,116,109,97,112,66,117,116,116,111,110,34,32, +110,97,109,101,61,34,73,68,67,95,67,70,73,76,69,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,66,85, +95,65,85,84,79,68,82,65,87,60,47,115,116,121,108,101,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120, +45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115, +95,49,54,120,49,54,95,102,111,108,100,101,114,46,112,110,103,60,47,98,105, +116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +100,101,102,97,117,108,116,62,48,60,47,100,101,102,97,117,108,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111, +114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105, +122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,70,108,101,120,71,114,105,100,83, +105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62,52,60,47,99,111,108, +115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97, +112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101, +99,111,108,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,73,71,78,95,67, +69,78,84,69,82,95,86,69,82,84,73,67,65,76,124,119,120,65,76,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,83,101,99,116,111,114,115,58,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119, +114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105, +111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120,116,67,116,114, +108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,49,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117, +101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105, +122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69, +82,84,73,67,65,76,124,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,72, +101,97,100,115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119, +114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,84,101,120,116,67,116,114,108,34,32,110,97,109,101,61,34, +73,68,67,95,69,68,73,84,50,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,124,119,120, +65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116, +105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,108,97,98,101,108,62,67,121,108,105,110,100,101,114, +115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,84,101,120,116,67,116,114,108,34,32,110,97,109,101,61,34,73,68,67,95, +69,68,73,84,51,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,124,119,120,65,76,76,60, +47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120, +116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,83,105,122,101,32,40,77,66,41,58,60,47,108,97,98, +101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,124,119,120, +65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120,116, +67,116,114,108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,52,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118, +97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112, +97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48, +60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120, +65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,84,121,112,101, +58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108, +97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111, +120,34,32,110,97,109,101,61,34,73,68,67,95,72,68,84,89,80,69,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62, +119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67,66,95,82,69,65, +68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115, +105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118, +97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,99,111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101, +114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105, +111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60, +47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115, +105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120, +65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110,97,109,101,61, +34,73,68,67,95,72,68,66,76,79,67,75,83,73,90,69,76,65,66,69,76,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62, +66,108,111,99,107,32,115,105,122,101,58,60,47,108,97,98,101,108,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49, +60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,67,111,109,98,111,66,111,120,34,32,110,97,109,101,61,34,73,68, +67,95,72,68,66,76,79,67,75,83,73,90,69,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66,95,68,82, +79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89,60,47,115, +116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110, +116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101, +109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105,101,110,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108, +97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,66,117,116,116,111,110,34,32,110, +97,109,101,61,34,119,120,73,68,95,79,75,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,79,75,60,47,108,97,98,101, +108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102, +97,117,108,116,62,49,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,117,116,116,111,110,34,32, +110,97,109,101,61,34,119,120,73,68,95,67,65,78,67,69,76,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,67,97, +110,99,101,108,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101, +102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,68,105,97, +108,111,103,34,32,110,97,109,101,61,34,72,100,83,105,122,101,68,108,103, +34,62,10,32,32,32,32,60,116,105,116,108,101,62,72,97,114,100,32,68,105, +115,99,32,80,97,114,97,109,101,116,101,114,115,60,47,116,105,116,108,101, +62,10,32,32,32,32,60,99,101,110,116,101,114,101,100,62,49,60,47,99,101, +110,116,101,114,101,100,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,80,97,110,101,108,34,32,110,97,109,101,61, +34,82,79,79,84,95,80,65,78,69,76,34,62,10,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101,120,71,114,105, +100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,60,114,111,119, +115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32,32,32,32,60,99,111, +108,115,62,49,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,60,118, +103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32,60, +104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32, +60,103,114,111,119,97,98,108,101,99,111,108,115,47,62,10,32,32,32,32,32, +32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,32,124, +32,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67,65, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,108,97,98,101,108,62,73,110,105,116,105,97,108,32,115,101,116, +116,105,110,103,115,32,97,114,101,32,98,97,115,101,100,32,111,110,32,102, +105,108,101,32,115,105,122,101,60,47,108,97,98,101,108,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62, +53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101,120, +71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,99,111,108,115,62,51,60,47,99,111,108,115,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118, +103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,104,103,97,112, +62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +103,114,111,119,97,98,108,101,99,111,108,115,62,49,60,47,103,114,111,119, +97,98,108,101,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,103,114,111,119,97,98,108,101,114,111,119,115,47,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,48, +44,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68, +60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,119,120,70,108,101,120,71,114,105,100,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,114,111,119, +115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,99,111,108,115,62,52,60,47,99,111,108,115,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47, +118,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108,115, +47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111, +119,97,98,108,101,114,111,119,115,47,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95, +86,69,82,84,73,67,65,76,124,119,120,65,76,76,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100, +101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,83,101,99,116,111,114,115,58,60,47,108,97,98,101,108,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62, +45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,84,101,120,116,67,116,114,108,34,32,110,97, +109,101,61,34,73,68,67,95,69,68,73,84,49,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,47,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86,69,82,84,73,67, +65,76,124,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,72,101,97,100, +115,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,84,101,120,116,67,116,114,108,34,32,110,97,109,101,61,34,73,68,67,95, +69,68,73,84,50,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,124,119,120,65,76,76,60, +47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120, +116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,67,121,108,105,110,100,101,114,115,58,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111, +114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,84,101,120, +116,67,116,114,108,34,32,110,97,109,101,61,34,73,68,67,95,69,68,73,84,51, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +118,97,108,117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,65,76,73,71,78,95,67,69,78,84, +69,82,95,86,69,82,84,73,67,65,76,124,119,120,65,76,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111, +114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,83,105,122,101,58,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60, +47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,102,108,97,103,62,119,120,65,76,73,71,78,95,67,69,78,84,69, +82,95,86,69,82,84,73,67,65,76,124,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,84,69,88,84,49,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,48,109, +98,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100, +101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,76,32,124,32,119,120,65,76,73,71,78, +95,67,69,78,84,69,82,95,86,69,82,84,73,67,65,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,108,97,98,101,108,62,84,121,112,101,58,60,47,108, +97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111,120,34, +32,110,97,109,101,61,34,73,68,67,95,72,68,84,89,80,69,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120, +67,66,95,68,82,79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78, +76,89,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,105,122,101,62,51,53,48,44,45,49,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108, +117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99, +111,110,116,101,110,116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122, +101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62, +53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83, +105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114, +105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114, +105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49, +60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116, +116,111,110,34,32,110,97,109,101,61,34,119,120,73,68,95,79,75,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62, +79,75,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,100,101,102,97,117,108,116,62,49,60,47,100,101,102,97,117, +108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114, +62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,117,116,116,111,110,34,32,110,97,109,101,61,34,119,120,73,68,95,67,65, +78,67,69,76,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +108,97,98,101,108,62,67,97,110,99,101,108,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108, +116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,68,105,97,108,111,103,34,32,110,97,109,101,61,34,67,111,110, +102,105,103,117,114,101,83,101,108,101,99,116,105,111,110,68,108,103,34, +62,10,32,32,32,32,60,116,105,116,108,101,62,80,67,101,109,32,67,111,110, +102,105,103,117,114,97,116,105,111,110,32,77,97,110,97,103,101,114,60,47, +116,105,116,108,101,62,10,32,32,32,32,60,99,101,110,116,101,114,101,100, +62,49,60,47,99,101,110,116,101,114,101,100,62,10,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,70,108,101,120,71,114, +105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32,60,114,111,119,115, +62,49,60,47,114,111,119,115,62,10,32,32,32,32,32,32,60,99,111,108,115,62, +49,60,47,99,111,108,115,62,10,32,32,32,32,32,32,60,118,103,97,112,62,48, +60,47,118,103,97,112,62,10,32,32,32,32,32,32,60,104,103,97,112,62,48,60, +47,104,103,97,112,62,10,32,32,32,32,32,32,60,103,114,111,119,97,98,108, +101,99,111,108,115,62,48,60,47,103,114,111,119,97,98,108,101,99,111,108, +115,62,10,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119, +115,62,48,60,47,103,114,111,119,97,98,108,101,114,111,119,115,62,10,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,124,119,120,69,88, +80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,60,98,111, +114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32, +32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,70, +108,101,120,71,114,105,100,83,105,122,101,114,34,62,10,32,32,32,32,32,32, +32,32,32,32,60,114,111,119,115,62,50,60,47,114,111,119,115,62,10,32,32, +32,32,32,32,32,32,32,32,60,99,111,108,115,62,50,60,47,99,111,108,115,62, +10,32,32,32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118,103, +97,112,62,10,32,32,32,32,32,32,32,32,32,32,60,104,103,97,112,62,48,60,47, +104,103,97,112,62,10,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97, +98,108,101,99,111,108,115,62,48,60,47,103,114,111,119,97,98,108,101,99, +111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98, +108,101,114,111,119,115,62,48,60,47,103,114,111,119,97,98,108,101,114,111, +119,115,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105, +101,110,116,62,119,120,86,69,82,84,73,67,65,76,60,47,111,114,105,101,110, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,124,119,120, +69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,76,105,115,116,66,111, +120,34,32,110,97,109,101,61,34,73,68,67,95,76,73,83,84,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62, +119,120,76,66,95,83,73,78,71,76,69,60,47,115,116,121,108,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,50, +53,48,44,51,48,48,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119, +120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116,62,119, +120,86,69,82,84,73,67,65,76,60,47,111,114,105,101,110,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60, +47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +119,120,66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101, +61,34,119,120,73,68,95,79,75,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,66,85,95,65,85,84, +79,68,82,65,87,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,116,111,111,108,116,105,112,62,76,111, +97,100,60,47,116,111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114, +101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,51, +50,120,51,50,95,99,111,110,116,114,111,108,95,112,108,97,121,95,98,108, +117,101,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62, +49,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34, +73,68,67,95,67,79,78,70,73,71,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,66,85,95,65,85,84, +79,68,82,65,87,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,116,111,111,108,116,105,112,62,67,111, +110,102,105,103,117,114,101,60,47,116,111,111,108,116,105,112,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97, +112,62,119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105, +99,111,110,115,95,51,50,120,51,50,95,115,101,116,116,105,110,103,95,116, +111,111,108,115,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108, +116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105, +111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108, +97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,66,105,116,109,97,112,66,117,116,116,111,110,34,32,110, +97,109,101,61,34,73,68,67,95,67,79,78,70,73,71,95,72,79,83,84,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108, +101,62,119,120,66,85,95,65,85,84,79,68,82,65,87,60,47,115,116,121,108,101, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111, +111,108,116,105,112,62,67,111,110,102,105,103,117,114,101,32,72,111,115, +116,60,47,116,111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101, +115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,51,50, +120,51,50,95,119,105,100,101,115,99,114,101,101,110,46,112,110,103,60,47, +98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101,102,97,117,108, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98, +111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122, +101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105, +101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105, +101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60, +47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,66,105,116,109,97,112,66,117,116,116,111,110, +34,32,110,97,109,101,61,34,73,68,67,95,78,69,87,34,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120, +66,85,95,65,85,84,79,68,82,65,87,60,47,115,116,121,108,101,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111,108,116, +105,112,62,78,101,119,60,47,116,111,111,108,116,105,112,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62, +119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111, +110,115,95,51,50,120,51,50,95,99,111,109,112,117,116,101,114,95,97,100, +100,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48, +60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34, +115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,105, +116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61,34,73,68, +67,95,82,69,78,65,77,69,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,115,116,121,108,101,62,119,120,66,85,95,65,85,84,79,68, +82,65,87,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,116,111,111,108,116,105,112,62,82,101,110,97, +109,101,60,47,116,111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114, +101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,51, +50,120,51,50,95,99,111,109,112,117,116,101,114,95,101,100,105,116,46,112, +110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47,100,101, +102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,105,116,109,97,112, +66,117,116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,67,79,80, +89,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115, +116,121,108,101,62,119,120,66,85,95,65,85,84,79,68,82,65,87,60,47,115,116, +121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,116,111,111,108,116,105,112,62,67,111,112,121,60,47,116,111,111,108, +116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115, +46,99,112,112,36,105,99,111,110,115,95,51,50,120,51,50,95,99,111,109,112, +117,116,101,114,95,103,111,46,112,110,103,60,47,98,105,116,109,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102, +97,117,108,116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62, +48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100, +101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109, +101,61,34,73,68,67,95,68,69,76,69,84,69,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,66,85,95, +65,85,84,79,68,82,65,87,60,47,115,116,121,108,101,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,116,111,111,108,116,105,112,62, +68,101,108,101,116,101,60,47,116,111,111,108,116,105,112,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109,97,112,62, +119,120,45,114,101,115,111,117,114,99,101,115,46,99,112,112,36,105,99,111, +110,115,95,51,50,120,51,50,95,99,111,109,112,117,116,101,114,95,100,101, +108,101,116,101,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108, +116,62,48,60,47,100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47, +102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,66,105,116,109,97,112,66,117,116,116,111,110,34,32,110,97,109,101,61, +34,119,120,73,68,95,67,65,78,67,69,76,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,66,85,95,65,85,84,79, +68,82,65,87,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,116,111,111,108,116,105,112,62,81,117,105,116,60,47,116, +111,111,108,116,105,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,105,116,109,97,112,62,119,120,45,114,101,115,111,117,114,99,101,115, +46,99,112,112,36,105,99,111,110,115,95,51,50,120,51,50,95,100,111,111,114, +95,105,110,46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,48,60,47, +100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +68,105,97,108,111,103,34,32,110,97,109,101,61,34,83,104,97,100,101,114, +77,97,110,97,103,101,114,68,108,103,34,62,10,32,32,32,32,60,115,116,121, +108,101,62,119,120,68,69,70,65,85,76,84,95,68,73,65,76,79,71,95,83,84,89, +76,69,124,119,120,83,84,65,89,95,79,78,95,84,79,80,60,47,115,116,121,108, +101,62,10,32,32,32,32,60,116,105,116,108,101,62,80,67,101,109,32,83,104, +97,100,101,114,32,77,97,110,97,103,101,114,60,47,116,105,116,108,101,62, +10,32,32,32,32,60,99,101,110,116,101,114,101,100,62,49,60,47,99,101,110, +116,101,114,101,100,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,80,97,110,101,108,34,32,110,97,109,101,61,34,82, +79,79,84,95,80,65,78,69,76,34,62,10,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97, +103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105, +122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105, +101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114,105, +101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119, +120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,111,114,100,101,114,62,48,60,47,98,111,114,100,101,114,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,76,105,115,116,66,111,120,34,32,110,97, +109,101,61,34,73,68,67,95,76,73,83,84,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,76,66,95,83,73, +78,71,76,69,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,115,105,122,101,62,51,48,48,44,51,53,48,60,47,115, +105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119, +120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,48,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114,105, +101,110,116,62,119,120,86,69,82,84,73,67,65,76,60,47,111,114,105,101,110, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108, +97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,48,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,66,117,116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,65,68, +68,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,108,97,98,101,108,62,65,100,100,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105, +116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,48,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,66,117,116,116,111,110,34,32,110,97,109,101,61,34,73,68,67, +95,82,69,77,79,86,69,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,108,97,98,101,108,62,82,101,109,111,118,101,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,112,97,99,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,48,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +66,117,116,116,111,110,34,32,110,97,109,101,61,34,73,68,67,95,67,79,78, +70,73,71,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,108,97,98,101,108,62,67,111,110,102,105,103,117,114,101,46,46, +46,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,48,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116,116, +111,110,34,32,110,97,109,101,61,34,73,68,67,95,77,79,86,69,95,85,80,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,77,111,118,101,32,117,112,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,48,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,66,117,116,116,111,110,34,32,110,97,109,101,61, +34,73,68,67,95,77,79,86,69,95,68,79,87,78,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,77,111,118, +101,32,100,111,119,110,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78, +68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,48,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,119,120,66,117,116,116,111,110,34,32,110,97, +109,101,61,34,73,68,67,95,65,80,80,76,89,34,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,65,112,112, +108,121,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,48,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116,116, +111,110,34,32,110,97,109,101,61,34,119,120,73,68,95,79,75,34,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,79,75,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,49,60,47, +100,101,102,97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97, +115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120, +65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,98,111,114,100,101,114,62,48,60,47,98,111,114,100, +101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116,116, +111,110,34,32,110,97,109,101,61,34,119,120,73,68,95,67,65,78,67,69,76,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108, +97,98,101,108,62,67,97,110,99,101,108,60,47,108,97,98,101,108,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,68,105,97, +108,111,103,34,32,110,97,109,101,61,34,67,111,110,102,105,114,109,82,101, +109,101,109,98,101,114,68,108,103,34,62,10,32,32,32,32,60,115,116,121,108, +101,62,119,120,68,69,70,65,85,76,84,95,68,73,65,76,79,71,95,83,84,89,76, +69,124,119,120,83,84,65,89,95,79,78,95,84,79,80,60,47,115,116,121,108,101, +62,10,32,32,32,32,60,116,105,116,108,101,62,80,67,101,109,60,47,116,105, +116,108,101,62,10,32,32,32,32,60,99,101,110,116,101,114,101,100,62,49,60, +47,99,101,110,116,101,114,101,100,62,10,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,80,97,110,101,108,34,32,110,97,109, +101,61,34,82,79,79,84,95,80,65,78,69,76,34,62,10,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105, +122,101,114,34,62,10,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,86,69,82,84,73,67,65,76,60,47,111,114,105,101,110,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,66,111,120,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65, +76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,66,105,116,109,97,112,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,105,116,109, +97,112,32,115,116,111,99,107,95,105,100,61,34,119,120,65,82,84,95,81,85, +69,83,84,73,79,78,34,32,115,116,111,99,107,95,99,108,105,101,110,116,61, +34,119,120,65,82,84,95,67,77,78,95,68,73,65,76,79,71,34,47,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,65,76,73,71,78,95,67,69,78,84,69,82,124,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120,116,34,32,110, +97,109,101,61,34,73,68,67,95,67,79,78,70,73,82,77,95,76,65,66,69,76,34, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101, +108,62,73,68,67,95,67,79,78,70,73,82,77,95,76,65,66,69,76,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119, +114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,67,104,101,99,107,66,111,120,34,32,110,97,109,101,61, +34,73,68,67,95,67,79,78,70,73,82,77,95,82,69,77,69,77,66,69,82,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,73,68,67,95, +67,79,78,70,73,82,77,95,82,69,77,69,77,66,69,82,60,47,108,97,98,101,108, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,104,101,99,107,101,100, +62,48,60,47,99,104,101,99,107,101,100,62,10,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10, +32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111, +112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101, +114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,83,116,100,68,105,97,108,111,103,66,117,116, +116,111,110,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,98,117,116,116,111, +110,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,72,79,82,73,90,79,78, +84,65,76,124,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111, +114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116,116,111, +110,34,32,110,97,109,101,61,34,119,120,73,68,95,79,75,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,79,75, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,100,101,102,97,117,108,116,62,49,60,47,100,101,102,97,117,108, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,98,117,116,116,111,110,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,73,71, +78,95,67,69,78,84,69,82,95,72,79,82,73,90,79,78,84,65,76,124,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,66,117,116,116,111,110,34,32,110,97,109,101,61, +34,119,120,73,68,95,67,65,78,67,69,76,34,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,67,97,110,99,101,108, +60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99, +116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +68,105,97,108,111,103,34,32,110,97,109,101,61,34,67,117,115,116,111,109, +82,101,115,111,108,117,116,105,111,110,68,108,103,34,62,10,32,32,32,32, +60,115,116,121,108,101,62,119,120,68,69,70,65,85,76,84,95,68,73,65,76,79, +71,95,83,84,89,76,69,124,119,120,83,84,65,89,95,79,78,95,84,79,80,60,47, +115,116,121,108,101,62,10,32,32,32,32,60,116,105,116,108,101,62,67,117, +115,116,111,109,32,114,101,115,111,108,117,116,105,111,110,60,47,116,105, +116,108,101,62,10,32,32,32,32,60,99,101,110,116,101,114,101,100,62,49,60, +47,99,101,110,116,101,114,101,100,62,10,32,32,32,32,60,111,98,106,101,99, +116,32,99,108,97,115,115,61,34,119,120,80,97,110,101,108,34,32,110,97,109, +101,61,34,82,79,79,84,95,80,65,78,69,76,34,62,10,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105, +122,101,114,34,62,10,32,32,32,32,32,32,32,32,60,111,114,105,101,110,116, +62,119,120,86,69,82,84,73,67,65,76,60,47,111,114,105,101,110,116,62,10, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32, +32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62, +10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98, +111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32, +32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119, +120,66,111,120,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,114,105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65, +76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,112,105,110,67,116,114,108,34,32,110,97,109, +101,61,34,73,68,67,95,87,73,68,84,72,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,83,80,95,65,82,82, +79,87,95,75,69,89,83,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,62,54,52,48,60,47,118, +97,108,117,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +109,105,110,62,49,60,47,109,105,110,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,109,97,120,62,49,54,51,56,52,60,47,109,97,120,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47, +111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,86, +69,82,84,73,67,65,76,124,119,120,65,76,76,60,47,102,108,97,103,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53, +60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116, +97,116,105,99,84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,60,108,97,98,101,108,62,120,60,47,108,97,98,101,108,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112,62,45, +49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102, +108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61, +34,119,120,83,112,105,110,67,116,114,108,34,32,110,97,109,101,61,34,73, +68,67,95,72,69,73,71,72,84,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,115,116,121,108,101,62,119,120,83,80,95,65,82,82,79,87,95, +75,69,89,83,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,118,97,108,117,101,62,52,56,48,60,47,118,97,108, +117,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,109,105, +110,62,49,60,47,109,105,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,109,97,120,62,49,54,51,56,52,60,47,109,97,120,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116, +101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110, +62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32, +60,102,108,97,103,62,119,120,69,88,80,65,78,68,32,124,32,119,120,65,76, +76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120, +83,116,97,116,105,99,76,105,110,101,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,60,115,116,121,108,101,62,119,120,76,73,95,72,79,82,73,90,79,78, +84,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,83,116,100,68,105,97,108,111,103,66,117,116,116, +111,110,83,105,122,101,114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,98,117,116,116,111, +110,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,72,79,82,73,90,79,78, +84,65,76,124,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111, +114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116,116,111, +110,34,32,110,97,109,101,61,34,119,120,73,68,95,79,75,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,38,97,109, +112,59,79,75,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,100,101,102,97,117,108,116,62,49,60,47,100,101,102, +97,117,108,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,98,117,116,116,111,110,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65, +76,73,71,78,95,67,69,78,84,69,82,95,72,79,82,73,90,79,78,84,65,76,124,119, +120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,66,117,116,116,111,110,34,32,110,97,109, +101,61,34,119,120,73,68,95,67,65,78,67,69,76,34,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,38,97,109,112,59, +67,97,110,99,101,108,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,68,105,97,108,111,103,34,32,110,97,109,101,61,34,65,98,111, +117,116,68,108,103,34,62,10,32,32,32,32,60,115,116,121,108,101,62,119,120, +68,69,70,65,85,76,84,95,68,73,65,76,79,71,95,83,84,89,76,69,60,47,115,116, +121,108,101,62,10,32,32,32,32,60,116,105,116,108,101,47,62,10,32,32,32, +32,60,99,101,110,116,101,114,101,100,62,49,60,47,99,101,110,116,101,114, +101,100,62,10,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115, +61,34,119,120,80,97,110,101,108,34,32,110,97,109,101,61,34,82,79,79,84, +95,80,65,78,69,76,34,62,10,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101,114,34,62,10, +32,32,32,32,32,32,32,32,60,111,114,105,101,110,116,62,119,120,86,69,82, +84,73,67,65,76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,60,111,112,116, +105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103, +62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60, +47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98, +106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99, +84,101,120,116,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98, +101,108,62,80,67,101,109,32,118,49,55,92,110,104,116,116,112,115,58,47, +47,112,99,101,109,45,101,109,117,108,97,116,111,114,46,99,111,46,117,107, +47,92,110,92,110,84,104,105,115,32,112,114,111,103,114,97,109,32,105,115, +32,108,105,99,101,110,115,101,100,32,117,110,100,101,114,32,116,104,101, +32,71,78,85,32,71,101,110,101,114,97,108,32,80,117,98,108,105,99,32,76, +105,99,101,110,115,101,32,118,101,114,115,105,111,110,32,50,46,92,110,83, +101,101,32,67,79,80,89,73,78,71,32,102,111,114,32,109,111,114,101,32,100, +101,116,97,105,108,115,46,92,110,92,110,84,111,111,108,98,97,114,45,105, +99,111,110,115,32,109,97,100,101,32,98,121,32,82,111,117,110,100,105,99, +111,110,115,32,40,104,116,116,112,115,58,47,47,114,111,117,110,100,105, +99,111,110,115,46,99,111,109,47,41,32,102,114,111,109,32,119,119,119,46, +102,108,97,116,105,99,111,110,46,99,111,109,92,110,79,116,104,101,114,32, +105,99,111,110,115,32,109,97,100,101,32,98,121,32,70,97,116,67,111,119, +32,40,104,116,116,112,58,47,47,119,119,119,46,102,97,116,99,111,119,46, +99,111,109,47,102,114,101,101,45,105,99,111,110,115,47,41,60,47,108,97, +98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,119,114,97,112, +62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101, +99,116,62,10,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116, +105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119, +120,69,88,80,65,78,68,32,124,32,119,120,65,76,76,60,47,102,108,97,103,62, +10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,76,105, +110,101,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108, +101,62,119,120,76,73,95,72,79,82,73,90,79,78,84,65,76,60,47,115,116,121, +108,101,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47, +102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116, +116,111,110,34,32,110,97,109,101,61,34,119,120,73,68,95,79,75,34,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,95,79,75,60, +47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,100,101, +102,97,117,108,116,62,49,60,47,100,101,102,97,117,108,116,62,10,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +60,47,111,98,106,101,99,116,62,10,32,32,60,111,98,106,101,99,116,32,99, +108,97,115,115,61,34,119,120,68,105,97,108,111,103,34,32,110,97,109,101, +61,34,72,111,115,116,67,111,110,102,105,103,34,62,10,32,32,32,32,60,115, +116,121,108,101,62,119,120,68,69,70,65,85,76,84,95,68,73,65,76,79,71,95, +83,84,89,76,69,124,119,120,83,84,65,89,95,79,78,95,84,79,80,60,47,115,116, +121,108,101,62,10,32,32,32,32,60,115,105,122,101,62,52,57,57,44,49,55,53, +60,47,115,105,122,101,62,10,32,32,32,32,60,116,105,116,108,101,62,72,111, +115,116,32,67,111,110,102,105,103,117,114,97,116,105,111,110,60,47,116, +105,116,108,101,62,10,32,32,32,32,60,99,101,110,116,101,114,101,100,62, +49,60,47,99,101,110,116,101,114,101,100,62,10,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101, +114,34,62,10,32,32,32,32,32,32,60,111,114,105,101,110,116,62,119,120,86, +69,82,84,73,67,65,76,60,47,111,114,105,101,110,116,62,10,32,32,32,32,32, +32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101, +114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,60,111,112,116,105, +111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32, +32,60,102,108,97,103,62,119,120,69,88,80,65,78,68,32,124,32,119,120,65, +76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,80,97, +110,101,108,34,32,110,97,109,101,61,34,109,95,112,97,110,101,108,50,48, +34,62,10,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120, +84,65,66,95,84,82,65,86,69,82,83,65,76,60,47,115,116,121,108,101,62,10, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,70,108,101,120,71,114,105,100,83,105,122,101,114,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,60,114,111,119,115,62,48,60,47,114, +111,119,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115, +62,49,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60, +118,103,97,112,62,48,60,47,118,103,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,60,104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,99,111,108, +115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97, +98,108,101,114,111,119,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +112,116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80, +65,78,68,32,124,32,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47, +98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,78,111,116, +101,98,111,111,107,34,32,110,97,109,101,61,34,109,95,110,111,116,101,98, +111,111,107,50,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,110,111,116,101,98, +111,111,107,112,97,103,101,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,108,97,98,101,108,47,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,115,101,108,101,99,116,101,100,62,48,60, +47,115,101,108,101,99,116,101,100,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,98,105,116,109,97,112,62,119,120,45,114,101,115, +111,117,114,99,101,115,46,99,112,112,36,105,99,111,110,115,95,51,50,120, +51,50,95,110,101,116,119,111,114,107,95,101,116,104,101,114,110,101,116, +46,112,110,103,60,47,98,105,116,109,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115, +115,61,34,119,120,80,97,110,101,108,34,32,110,97,109,101,61,34,109,95,112, +97,110,101,108,49,57,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,84,65,66,95,84,82,65, +86,69,82,83,65,76,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,70,108,101,120,71,114,105,100,83,105,122,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,114,111,119,115,62,48,60,47,114,111,119,115,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,108,115,62, +50,60,47,99,111,108,115,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,118,103,97,112,62,48,60,47,118,103,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +104,103,97,112,62,48,60,47,104,103,97,112,62,10,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,103,114,111,119,97,98,108, +101,99,111,108,115,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,103,114,111,119,97,98,108,101,114,111,119,115,47, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114, +105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112, +116,105,111,110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,83,116, +97,116,105,99,84,101,120,116,34,32,110,97,109,101,61,34,109,95,115,116, +97,116,105,99,84,101,120,116,55,50,34,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108, +62,78,101,116,119,111,114,107,32,116,121,112,101,32,58,60,47,108,97,98, +101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,119,114,97,112,62,45,49,60,47,119,114,97,112,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,102,108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,67,111,109,98,111, +66,111,120,34,32,110,97,109,101,61,34,73,68,67,95,67,79,77,66,79,95,78, +69,84,87,79,82,75,95,84,89,80,69,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101, +62,119,120,67,66,95,68,82,79,80,68,79,87,78,124,119,120,67,66,95,82,69, +65,68,79,78,76,89,60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122, +101,62,53,53,48,44,45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108, +117,101,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,99,111,110,116,101,110,116,47,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111, +98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,112,116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102, +108,97,103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114, +100,101,114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101, +99,116,32,99,108,97,115,115,61,34,119,120,83,116,97,116,105,99,84,101,120, +116,34,32,110,97,109,101,61,34,109,95,115,116,97,116,105,99,84,101,120, +116,55,51,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,78,101,116,119,111,114, +107,32,100,101,118,105,99,101,32,58,60,47,108,97,98,101,108,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,119,114,97,112,62,45,49,60,47,119,114,97,112,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,48,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97, +103,62,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,119,120,67,111,109,98,111,66,111,120,34,32,110, +97,109,101,61,34,73,68,67,95,67,79,77,66,79,95,78,69,84,87,79,82,75,95, +68,69,86,73,67,69,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,115,116,121,108,101,62,119,120,67,66, +95,68,82,79,80,68,79,87,78,124,119,120,67,66,95,82,69,65,68,79,78,76,89, +60,47,115,116,121,108,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,115,105,122,101,62,53,53,48,44, +45,49,60,47,115,105,122,101,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,118,97,108,117,101,62,67,111, +109,98,111,33,60,47,118,97,108,117,101,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,99,111,110,116,101, +110,116,47,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,115, +105,122,101,114,105,116,101,109,34,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,111,112,116,105,111,110,62,49,60,47,111,112,116,105,111, +110,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62, +119,120,69,88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,66,111,120,83,105,122,101, +114,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,114, +105,101,110,116,62,119,120,72,79,82,73,90,79,78,84,65,76,60,47,111,114, +105,101,110,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +111,98,106,101,99,116,32,99,108,97,115,115,61,34,115,112,97,99,101,114, +34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112, +116,105,111,110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69, +88,80,65,78,68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114, +100,101,114,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +60,115,105,122,101,62,48,44,48,60,47,115,105,122,101,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32, +99,108,97,115,115,61,34,115,105,122,101,114,105,116,101,109,34,62,10,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,112,116,105,111, +110,62,49,60,47,111,112,116,105,111,110,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,60,102,108,97,103,62,119,120,69,88,80,65,78, +68,60,47,102,108,97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114, +62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106, +101,99,116,32,99,108,97,115,115,61,34,119,120,83,116,100,68,105,97,108, +111,103,66,117,116,116,111,110,83,105,122,101,114,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116, +32,99,108,97,115,115,61,34,98,117,116,116,111,110,34,62,10,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,102,108,97,103, +62,119,120,65,76,73,71,78,95,67,69,78,84,69,82,95,72,79,82,73,90,79,78, +84,65,76,124,119,120,65,76,76,60,47,102,108,97,103,62,10,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,98,111,114,100,101, +114,62,53,60,47,98,111,114,100,101,114,62,10,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,111,98,106,101,99,116,32,99,108, +97,115,115,61,34,119,120,66,117,116,116,111,110,34,32,110,97,109,101,61, +34,119,120,73,68,95,79,75,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,60,108,97,98,101,108,62,38,97,109,112, +59,79,75,60,47,108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,111,98,106,101,99,116,32,99,108,97,115,115,61,34,98,117,116,116, +111,110,34,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,60,102,108,97,103,62,119,120,65,76,73,71,78,95,67,69,78,84, +69,82,95,72,79,82,73,90,79,78,84,65,76,124,119,120,65,76,76,60,47,102,108, +97,103,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,60,98,111,114,100,101,114,62,53,60,47,98,111,114,100,101,114,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,111, +98,106,101,99,116,32,99,108,97,115,115,61,34,119,120,66,117,116,116,111, +110,34,32,110,97,109,101,61,34,119,120,73,68,95,67,65,78,67,69,76,34,62, +10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,60,108,97,98,101,108,62,38,97,109,112,59,67,97,110,99,101,108,60,47, +108,97,98,101,108,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47,111,98,106, +101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,32,32,60,47, +111,98,106,101,99,116,62,10,32,32,32,32,32,32,32,32,32,32,60,47,111,98, +106,101,99,116,62,10,32,32,32,32,32,32,32,32,60,47,111,98,106,101,99,116, +62,10,32,32,32,32,32,32,60,47,111,98,106,101,99,116,62,10,32,32,32,32,60, +47,111,98,106,101,99,116,62,10,32,32,60,47,111,98,106,101,99,116,62,10, +60,47,114,101,115,111,117,114,99,101,62,10}; + +void InitXmlResource() +{ + + // Check for memory FS. If not present, load the handler: + { + wxMemoryFSHandler::AddFile(wxT("XRC_resource/dummy_file"), wxT("dummy one")); + wxFileSystem fsys; + wxFSFile *f = fsys.OpenFile(wxT("memory:XRC_resource/dummy_file")); + wxMemoryFSHandler::RemoveFile(wxT("XRC_resource/dummy_file")); + if (f) delete f; + else wxFileSystem::AddHandler(new wxMemoryFSHandler); + } + + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_16x16_drive.png"), xml_res_file_0, xml_res_size_0, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_16x16_diskette.png"), xml_res_file_1, xml_res_size_1, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_16x16_cd.png"), xml_res_file_2, xml_res_size_2, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_24x24_play.png"), xml_res_file_3, xml_res_size_3, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_24x24_pause.png"), xml_res_file_4, xml_res_size_4, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_24x24_stop.png"), xml_res_file_5, xml_res_size_5, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_24x24_refresh.png"), xml_res_file_6, xml_res_size_6, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_motherboard.png"), xml_res_file_7, xml_res_size_7, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_16x16_setting_tools.png"), xml_res_file_8, xml_res_size_8, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_video_mode.png"), xml_res_file_9, xml_res_size_9, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_sound.png"), xml_res_file_10, xml_res_size_10, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_drive.png"), xml_res_file_11, xml_res_size_11, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_mouse_pc.png"), xml_res_file_12, xml_res_size_12, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_joystick.png"), xml_res_file_13, xml_res_size_13, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_network_ethernet.png"), xml_res_file_14, xml_res_size_14, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_16x16_drive_add.png"), xml_res_file_15, xml_res_size_15, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_16x16_folder.png"), xml_res_file_16, xml_res_size_16, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_16x16_control_eject.png"), xml_res_file_17, xml_res_size_17, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_control_play_blue.png"), xml_res_file_18, xml_res_size_18, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_setting_tools.png"), xml_res_file_19, xml_res_size_19, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_widescreen.png"), xml_res_file_20, xml_res_size_20, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_computer_add.png"), xml_res_file_21, xml_res_size_21, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_computer_edit.png"), xml_res_file_22, xml_res_size_22, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_computer_go.png"), xml_res_file_23, xml_res_size_23, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_computer_delete.png"), xml_res_file_24, xml_res_size_24, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$icons_32x32_door_in.png"), xml_res_file_25, xml_res_size_25, wxT("image/png")); + XRC_ADD_FILE(wxT("XRC_resource/wx-resources.cpp$._pc.xrc"), xml_res_file_26, xml_res_size_26, wxT("text/xml")); + wxXmlResource::Get()->Load(wxT("memory:XRC_resource/wx-resources.cpp$._pc.xrc")); +} diff --git a/src/wx-sdl2-display-win.c b/src/wx-sdl2-display-win.c new file mode 100644 index 0000000..461ba16 --- /dev/null +++ b/src/wx-sdl2-display-win.c @@ -0,0 +1,1016 @@ +#define _WIN32_WINNT 0x0501 +#include +#include "video.h" +#include "wx-sdl2-video.h" +#include "wx-utils.h" +#include "ibm.h" +#include "mouse.h" +#include "wx-display.h" +#include "plat-keyboard.h" + +#ifdef _WIN32 +#define BITMAP WINDOWS_BITMAP +#undef UNICODE +#include +#include +#undef BITMAP +#endif + +HHOOK hKeyboardHook; + +static HINSTANCE hinstance = 0; +static HWND hwnd = 0; +static HMENU menu = 0; + +#define szClassName "PCemMainWnd" +#define szSubClassName "PCemSubWnd" + +static RAWINPUTDEVICE device; +static uint16_t scancode_map[65536]; + +SDL_mutex* rendererMutex; +SDL_cond* rendererCond; +SDL_Thread* renderthread = NULL; + +SDL_Window* window = NULL; +SDL_Window* dummy_window = NULL; + +int rendering = 0; + +int mousecapture = 0; + +extern int pause; +extern int video_scale; +extern int take_screenshot; + +void* window_ptr; +void* menu_ptr; + +SDL_Rect remembered_rect; +int remembered_mouse_x = 0; +int remembered_mouse_y = 0; + +int custom_resolution_width = 640; +int custom_resolution_height = 480; + +int win_doresize = 0; +int winsizex = 640, winsizey = 480; + +void renderer_start(); +void renderer_stop(int timeout); + +int trigger_fullscreen = 0; +int trigger_screenshot = 0; +int trigger_togglewindow = 0; +int trigger_inputrelease = 0; + +extern void device_force_redraw(); +extern void mouse_wheel_update(int); +extern void toggle_fullscreen(); + +/*Minimum window width to prevent menu wrapping. + This is a horrible hack to work around issues with PCem, SDL2, and the + AdjustWindowRectEx() function. Allowing the menu to wrap causes some quite odd + window behaviour, mainly shooting to the bottom of the screen when you try to + move it. + This hard coded limit is highly fragile and will be replaced by a proper fix as + soon as I work out what that should be!*/ +#define MIN_WIDTH 360 + +void display_resize(int width, int height) +{ + winsizex = width*(video_scale+1) >> 1; + winsizey = height*(video_scale+1) >> 1; + + SDL_Rect rect; + rect.x = rect.y = 0; + rect.w = winsizex; + rect.h = winsizey; + sdl_scale(video_fullscreen_scale, rect, &rect, winsizex, winsizey); + winsizex = rect.w; + winsizey = rect.h; + + if (winsizex < MIN_WIDTH) + winsizex = MIN_WIDTH; + win_doresize = 1; +} + +void releasemouse() +{ + if (mousecapture) + { + SDL_SetWindowGrab(window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + mousecapture = 0; + } +} + +int is_fullscreen() +{ + if (window) + { + int flags = SDL_GetWindowFlags(window); + return (flags&SDL_WINDOW_FULLSCREEN) || (flags&SDL_WINDOW_FULLSCREEN_DESKTOP); + } + return 0; +} + +/* 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 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; + pclog("Preparing scan code map list...\n"); + /* 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, (LPBYTE)buf, &bufSize) == ERROR_SUCCESS) + { + UINT32 *bufEx2 = (UINT32 *) buf; + int scMapCount = bufEx2[2]; + pclog("%lu scan code mappings found!\n", scMapCount); + if ((bufSize != 0) && (scMapCount != 0)) + { + UINT16 *bufEx = (UINT16 *) (buf + 12); + pclog("More than zero scan code mappings found, processing...\n"); + 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); + + scancode_map[scancode_unmapped] = scancode_mapped; + pclog("Scan code mapping %u detected: %X -> %X\n", scancode_unmapped, scancode_mapped, scancode_map[scancode_unmapped]); + } + pclog("Done processing!\n"); + } + } + RegCloseKey(hKey); + } + pclog("Done preparing!\n"); +} + +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 ); +} + +LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_COMMAND: + /* pass through commands to wx window */ + wx_winsendmessage(window_ptr, message, wParam, lParam); + return 0; + break; + case WM_INPUT: + { + UINT size; + RAWINPUT *raw; + + if (!infocus) + break; + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + + raw = malloc(size); + + /* Here we read the raw input data for the keyboard */ + GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); + + /* 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)) + { + 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); + } + } + free(raw); + + } + break; + case WM_SETFOCUS: + infocus=1; + break; + case WM_KILLFOCUS: + infocus=0; + if (is_fullscreen()) + window_dowindowed = 1; + window_doinputrelease = 1; + memset(rawinputkey, 0, sizeof(rawinputkey)); + break; + case WM_CLOSE: + case WM_DESTROY: + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + return 0; + + case WM_SYSCOMMAND: + if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0 && (video_fullscreen || mousecapture)) + return 0; /*disable ALT key for menu*/ + break; + default: + break; + } + return DefWindowProc (hwnd, message, wParam, lParam); +} + +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + return 0; +} + +int display_init() +{ + SDL_SetHint(SDL_HINT_WINDOWS_DISABLE_THREAD_NAMING, "1"); + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) + { + printf("SDL could not initialize! Error: %s\n", SDL_GetError()); + return 0; + } + + SDL_version ver; + SDL_GetVersion(&ver); + printf("SDL %i.%i.%i initialized.\n", ver.major, ver.minor, ver.patch); + + return 1; +} + +void display_close() +{ + SDL_Quit(); +} + +void display_start(void* wnd_ptr) +{ + window_ptr = wnd_ptr; + menu_ptr = wx_getmenu(wnd_ptr); + + get_registry_key_map(); + + infocus = 1; + + atexit(releasemouse); + rendererMutex = SDL_CreateMutex(); + rendererCond = SDL_CreateCond(); + renderer_start(); +} + +void display_stop() +{ + renderer_stop(10 * 1000); + + SDL_DestroyMutex(rendererMutex); + SDL_DestroyCond(rendererCond); + SDL_DetachThread(renderthread); + releasemouse(); + +} + +void sdl_set_window_title(const char* title) { + if (hwnd && !is_fullscreen()) + SetWindowText(hwnd, title); +} + +int get_border_size(int* top, int* left, int* bottom, int* right) +{ + int res = SDL_GetWindowBordersSize(window, top, left, bottom, right); + if (top) *top -= GetSystemMetrics(SM_CYMENUSIZE); + + return res; +} + +static const struct { + SDL_Scancode sdl; + int system; +} SDLScancodeToSystemScancode[] = { + { SDL_SCANCODE_A, 0x1e }, + { SDL_SCANCODE_B, 0x30 }, + { SDL_SCANCODE_C, 0x2e }, + { SDL_SCANCODE_D, 0x20 }, + { SDL_SCANCODE_E, 0x12 }, + { SDL_SCANCODE_F, 0x21 }, + { SDL_SCANCODE_G, 0x22 }, + { SDL_SCANCODE_H, 0x23 }, + { SDL_SCANCODE_I, 0x17 }, + { SDL_SCANCODE_J, 0x24 }, + { SDL_SCANCODE_K, 0x25 }, + { SDL_SCANCODE_L, 0x26 }, + { SDL_SCANCODE_M, 0x32 }, + { SDL_SCANCODE_N, 0x31 }, + { SDL_SCANCODE_O, 0x18 }, + { SDL_SCANCODE_P, 0x19 }, + { SDL_SCANCODE_Q, 0x10 }, + { SDL_SCANCODE_R, 0x13 }, + { SDL_SCANCODE_S, 0x1f }, + { SDL_SCANCODE_T, 0x14 }, + { SDL_SCANCODE_U, 0x16 }, + { SDL_SCANCODE_V, 0x2f }, + { SDL_SCANCODE_W, 0x11 }, + { SDL_SCANCODE_X, 0x2d }, + { SDL_SCANCODE_Y, 0x15 }, + { SDL_SCANCODE_Z, 0x2c }, + { SDL_SCANCODE_0, 0x0B }, + { SDL_SCANCODE_1, 0x02 }, + { SDL_SCANCODE_2, 0x03 }, + { SDL_SCANCODE_3, 0x04 }, + { SDL_SCANCODE_4, 0x05 }, + { SDL_SCANCODE_5, 0x06 }, + { SDL_SCANCODE_6, 0x07 }, + { SDL_SCANCODE_7, 0x08 }, + { SDL_SCANCODE_8, 0x09 }, + { SDL_SCANCODE_9, 0x0A }, + { SDL_SCANCODE_GRAVE, 0x29 }, + { SDL_SCANCODE_MINUS, 0x0c }, + { SDL_SCANCODE_EQUALS, 0x0d }, + { SDL_SCANCODE_NONUSBACKSLASH, 0x56 }, + { SDL_SCANCODE_BACKSLASH, 0x2b }, + { SDL_SCANCODE_BACKSPACE, 0x0e }, + { SDL_SCANCODE_SPACE, 0x39 }, + { SDL_SCANCODE_TAB, 0x0f }, + { SDL_SCANCODE_CAPSLOCK, 0x3a }, + { SDL_SCANCODE_LSHIFT, 0x2a }, + { SDL_SCANCODE_LCTRL, 0x1d }, + { SDL_SCANCODE_LGUI, 0xdb }, + { SDL_SCANCODE_LALT, 0x38 }, + { SDL_SCANCODE_RSHIFT, 0x36 }, + { SDL_SCANCODE_RCTRL, 0x9d }, + { SDL_SCANCODE_RGUI, 0xdc }, + { SDL_SCANCODE_RALT, 0xb8 }, + { SDL_SCANCODE_SYSREQ, 0x54 }, + { SDL_SCANCODE_APPLICATION, 0xdd }, + { SDL_SCANCODE_RETURN, 0x1c }, + { SDL_SCANCODE_ESCAPE, 0x01 }, + { SDL_SCANCODE_F1, 0x3B }, + { SDL_SCANCODE_F2, 0x3C }, + { SDL_SCANCODE_F3, 0x3D }, + { SDL_SCANCODE_F4, 0x3e }, + { SDL_SCANCODE_F5, 0x3f }, + { SDL_SCANCODE_F6, 0x40 }, + { SDL_SCANCODE_F7, 0x41 }, + { SDL_SCANCODE_F8, 0x42 }, + { SDL_SCANCODE_F9, 0x43 }, + { SDL_SCANCODE_F10, 0x44 }, + { SDL_SCANCODE_F11, 0x57 }, + { SDL_SCANCODE_F12, 0x58 }, + { SDL_SCANCODE_SCROLLLOCK, 0x46 }, + { SDL_SCANCODE_LEFTBRACKET, 0x1a }, + { SDL_SCANCODE_RIGHTBRACKET, 0x1b }, + { SDL_SCANCODE_INSERT, 0xd2 }, + { SDL_SCANCODE_HOME, 0xc7 }, + { SDL_SCANCODE_PAGEUP, 0xc9 }, + { SDL_SCANCODE_DELETE, 0xd3 }, + { SDL_SCANCODE_END, 0xcf }, + { SDL_SCANCODE_PAGEDOWN, 0xd1 }, + { SDL_SCANCODE_UP, 0xc8 }, + { SDL_SCANCODE_LEFT, 0xcb }, + { SDL_SCANCODE_DOWN, 0xd0 }, + { SDL_SCANCODE_RIGHT, 0xcd }, + { SDL_SCANCODE_NUMLOCKCLEAR, 0x45 }, + { SDL_SCANCODE_KP_DIVIDE, 0xb5 }, + { SDL_SCANCODE_KP_MULTIPLY, 0x37 }, + { SDL_SCANCODE_KP_MINUS, 0x4a }, + { SDL_SCANCODE_KP_PLUS, 0x4e }, + { SDL_SCANCODE_KP_ENTER, 0x9c }, + { SDL_SCANCODE_KP_PERIOD, 0x53 }, + { SDL_SCANCODE_KP_0, 0x52 }, + { SDL_SCANCODE_KP_1, 0x4f }, + { SDL_SCANCODE_KP_2, 0x50 }, + { SDL_SCANCODE_KP_3, 0x51 }, + { SDL_SCANCODE_KP_4, 0x48 }, + { SDL_SCANCODE_KP_5, 0x4c }, + { SDL_SCANCODE_KP_6, 0x4d }, + { SDL_SCANCODE_KP_7, 0x47 }, + { SDL_SCANCODE_KP_8, 0x48 }, + { SDL_SCANCODE_KP_9, 0x49 }, + { SDL_SCANCODE_SEMICOLON, 0x27 }, + { SDL_SCANCODE_APOSTROPHE, 0x28 }, + { SDL_SCANCODE_COMMA, 0x33 }, + { SDL_SCANCODE_PERIOD, 0x34 }, + { SDL_SCANCODE_SLASH, 0x35 }, + { SDL_SCANCODE_PRINTSCREEN, 0xb7 } +}; + +int sdl_scancode(SDL_Scancode scancode) +{ + int i; + for (i = 0; i < SDL_arraysize(SDLScancodeToSystemScancode); ++i) { + if (SDLScancodeToSystemScancode[i].sdl == scancode) { + return SDLScancodeToSystemScancode[i].system; + } + } + return -1; +} + +SDL_Event event; +SDL_Rect rect; +int border_x, border_y = 0; + +uint64_t render_time = 0; +int render_fps = 0; +uint32_t render_frame_time = 0; +uint32_t render_frames = 0; + +void window_setup() +{ + SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "0"); + SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); + SDL_SetHint(SDL_HINT_WINDOWS_NO_CLOSE_ON_ALT_F4, "1"); + + if (start_in_fullscreen) + { + start_in_fullscreen = 0; + window_dofullscreen = 1; + window_doinputgrab = 1; + } + + if (window_remember) + { + rect.x = window_x; + rect.y = window_y; + rect.w = window_w; + rect.h = window_h; + } + else + { + rect.x = SDL_WINDOWPOS_CENTERED; + rect.y = SDL_WINDOWPOS_CENTERED; + rect.w = 640; + rect.h = 480; + } + + if (vid_resize == 2) + { + rect.w = custom_resolution_width; + rect.h = custom_resolution_height; + } +} + +int window_create() +{ + int i; + WNDCLASSEX wincl; /* Data structure for the windowclass */ + + hinstance = (HINSTANCE)GetModuleHandle(NULL); + /* The Window structure */ + wincl.hInstance = hinstance; + 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 (NULL, IDI_APPLICATION); + wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION); + 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 = CreateMenu(); + HMENU native_menu = (HMENU)wx_getnativemenu(menu_ptr); + int count = GetMenuItemCount(native_menu); + MENUITEMINFO info; + for (i = 0; i < count; ++i) + { + char label[256]; + memset(&info, 0, sizeof(MENUITEMINFO)); + info.cbSize = sizeof(MENUITEMINFO); + info.fMask = MIIM_TYPE | MIIM_ID; + info.fType = MFT_STRING; + info.cch = 256; + info.dwTypeData = label; + if (GetMenuItemInfo(native_menu, i, 1, &info)) + AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)GetSubMenu(native_menu, i), info.dwTypeData); + } + + /* The class is registered, let's create the program*/ + hwnd = CreateWindowEx ( + 0, /* Extended possibilites for variation */ + szClassName, /* Classname */ + "PCem " PCEM_VERSION_STRING, /* 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 */ + hinstance, /* Program Instance handler */ + NULL /* No Window Creation data */ + ); + + /* Make the window visible on the screen */ + ShowWindow(hwnd, 1); + + 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"); + + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); + + if (requested_render_driver.sdl_window_params & SDL_WINDOW_OPENGL) + { + /* create dummy window for opengl */ + dummy_window = SDL_CreateWindow("GL3 test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1, 1, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + if (dummy_window) + { + char ptr[32]; + snprintf(ptr, 31, "%p", dummy_window); + ptr[31] = 0; + SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, ptr); + } + } + window = SDL_CreateWindowFrom(hwnd); + if (!window) + { + char message[200]; + sprintf(message, + "SDL window could not be created! Error: %s\n", + SDL_GetError()); + wx_messagebox(window_ptr, message, "SDL Error", WX_MB_OK); + return 0; + } + + SDL_SetWindowPosition(window, rect.x, rect.y); + SDL_SetWindowSize(window, rect.w, rect.h); + + if (vid_resize) + window_dosetresize = 1; + + render_time = 0; + render_fps = 0; + render_frame_time = SDL_GetTicks(); + render_frames = 0; + return 1; +} + +void window_close() +{ + int i; + sdl_renderer_close(); + + int count = GetMenuItemCount(menu); + for (i = 0; i < count; ++i) + RemoveMenu(menu, 0, MF_BYPOSITION); + DestroyMenu(menu); + menu = 0; + SetMenu(hwnd, 0); + + if (window) { + SDL_GetWindowPosition(window, &rect.x, &rect.y); + SDL_GetWindowSize(window, &rect.w, &rect.h); + get_border_size(&border_y, &border_x, 0, 0); + rect.x -= border_x; + rect.y -= border_y; + + SDL_DestroyWindow(window); + } + window = NULL; + + if (dummy_window) + { + SDL_SetHint(SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT, ""); + SDL_DestroyWindow(dummy_window); + } + dummy_window = NULL; + + UnhookWindowsHookEx( hKeyboardHook ); + DestroyWindow(hwnd); + hwnd = NULL; + + UnregisterClass(szSubClassName, hinstance); + UnregisterClass(szClassName, hinstance); + +} + +int render() +{ + uint64_t start_time = timer_read(); + uint64_t end_time; + + if (window_doreset) + { + pclog("window_doreset\n"); + window_doreset = 0; + renderer_doreset = 0; + return 0; + } + if (window_dosetresize) + { + window_dosetresize = 0; + SDL_GetWindowSize(window, &rect.w, &rect.h); + SDL_SetWindowResizable(window, vid_resize == 1); + SDL_SetWindowSize(window, rect.w, rect.h); + + if (vid_resize == 2) + SDL_SetWindowSize(window, custom_resolution_width, custom_resolution_height); + + device_force_redraw(); + } + if (renderer_doreset) + { + pclog("renderer_doreset\n"); + renderer_doreset = 0; + sdl_renderer_close(); + sdl_renderer_init(window); + + device_force_redraw(); + video_wait_for_blit(); + } + while(SDL_PollEvent(&event)) + { + switch (event.type) { + case SDL_MOUSEBUTTONUP: + if (!mousecapture) + { + if (event.button.button == SDL_BUTTON_LEFT && !pause) + { + window_doinputgrab = 1; + if (video_fullscreen) + window_dofullscreen = 1; + } + } + else if (event.button.button == SDL_BUTTON_MIDDLE && !is_fullscreen() && !(mouse_get_type(mouse_type) & MOUSE_TYPE_3BUTTON)) + window_doinputrelease = 1; + break; + case SDL_MOUSEWHEEL: + if (mousecapture) mouse_wheel_update(event.wheel.y); + break; + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_CLOSE) + wx_stop_emulation(window_ptr); + if (event.window.event == SDL_WINDOWEVENT_RESIZED) + device_force_redraw(); + + if (window_remember) + { + int flags = SDL_GetWindowFlags(window); + if (!(flags&SDL_WINDOW_FULLSCREEN) && !(flags&SDL_WINDOW_FULLSCREEN_DESKTOP)) + { + if (event.window.event == SDL_WINDOWEVENT_MOVED) + { + get_border_size(&border_y, &border_x, 0, 0); + window_x = event.window.data1-border_x; + window_y = event.window.data2-border_y; + } + else if (event.window.event == SDL_WINDOWEVENT_RESIZED) + { + window_w = event.window.data1; + window_h = event.window.data2; + } + //save_window_pos = 1; + } + } + + break; + } + } + if ((rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEDOWN)] || rawinputkey[sdl_scancode(SDL_SCANCODE_KP_3)]) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)])) + trigger_fullscreen = 1; + else if (trigger_fullscreen) + { + trigger_fullscreen = 0; + toggle_fullscreen(); + } + else if ((rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEUP)] || rawinputkey[sdl_scancode(SDL_SCANCODE_KP_9)]) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)])) + trigger_screenshot = 1; + else if (trigger_screenshot) + { + trigger_screenshot = 0; + take_screenshot = 1; + } + else if ((event.key.keysym.scancode == SDL_SCANCODE_END || event.key.keysym.scancode == SDL_SCANCODE_KP_1) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)])) + trigger_inputrelease = 1; + else if (trigger_inputrelease) + { + trigger_inputrelease = 0; + if (!is_fullscreen()) + window_doinputrelease = 1; + } + if (window_doremember) + { + window_doremember = 0; + SDL_GetWindowPosition(window, &window_x, &window_y); + SDL_GetWindowSize(window, &window_w, &window_h); + get_border_size(&border_y, &border_x, 0, 0); + window_x -= border_x; + window_y -= border_y; + saveconfig(NULL); + } + + if (window_dotogglefullscreen) + { + window_dotogglefullscreen = 0; + if (SDL_GetWindowGrab(window) || is_fullscreen()) + { + window_doinputrelease = 1; + if (is_fullscreen()) + window_dowindowed = 1; + } + else + { + window_doinputgrab = 1; + window_dofullscreen = 1; + } + } + + if (window_dofullscreen) + { + window_dofullscreen = 0; + SetMenu(hwnd, 0); + video_wait_for_blit(); + SDL_RaiseWindow(window); + SDL_GetGlobalMouseState(&remembered_mouse_x, &remembered_mouse_y); + SDL_GetWindowPosition(window, &remembered_rect.x, &remembered_rect.y); + get_border_size(&border_y, &border_x, 0, 0); + remembered_rect.x -= border_x; + remembered_rect.y -= border_y; + SDL_GetWindowSize(window, &remembered_rect.w, &remembered_rect.h); + SDL_SetWindowFullscreen(window, video_fullscreen_mode == 0 ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN); + device_force_redraw(); + } + if (window_doinputgrab) { + window_doinputgrab = 0; + mousecapture = 1; + SDL_GetRelativeMouseState(0, 0); + SDL_SetWindowGrab(window, SDL_TRUE); + SDL_SetRelativeMouseMode(SDL_TRUE); + } + if (mousecapture) + { + SDL_Rect rect; + SDL_GetWindowSize(window, &rect.w, &rect.h); + SDL_WarpMouseInWindow(window, rect.w/2, rect.h/2); + } + + if (window_doinputrelease) { + window_doinputrelease = 0; + releasemouse(); + } + if (window_dowindowed) + { + window_dowindowed = 0; + SetMenu(hwnd, menu); + SDL_SetWindowFullscreen(window, 0); + SDL_SetWindowSize(window, remembered_rect.w, remembered_rect.h); + SDL_SetWindowPosition(window, remembered_rect.x, remembered_rect.y); + SDL_WarpMouseGlobal(remembered_mouse_x, remembered_mouse_y); + device_force_redraw(); + } + + if (win_doresize) + { + int flags = SDL_GetWindowFlags(window); + win_doresize = 0; + if (!vid_resize || (flags&SDL_WINDOW_FULLSCREEN)) { + SDL_GetWindowSize(window, &rect.w, &rect.h); + if (rect.w != winsizex || rect.h != winsizey) { + SDL_GetWindowPosition(window, &rect.x, &rect.y); + SDL_SetWindowSize(window, winsizex, winsizey); + SDL_SetWindowPosition(window, rect.x, rect.y); + device_force_redraw(); + } + } + } + + if (sdl_renderer_update(window)) sdl_renderer_present(window); + + end_time = timer_read(); + render_time += end_time - start_time; + + ++render_frames; + uint32_t ticks = SDL_GetTicks(); + if (ticks-render_frame_time >= 1000) { + render_fps = render_frames/((ticks-render_frame_time)/1000.0); + render_frames = 0; + render_frame_time = ticks; + } + + return 1; +} + +int renderer_thread(void* params) +{ + int internal_rendering; + + SDL_LockMutex(rendererMutex); + SDL_CondSignal(rendererCond); + SDL_UnlockMutex(rendererMutex); + + window_setup(); + + rendering = 1; + while (rendering) { + + if (!window_create()) + rendering = 0; + + renderer_doreset = 1; + internal_rendering = 1; + while (rendering && internal_rendering) + { + if (!render()) + internal_rendering = 0; + + SDL_Delay(1); + } + window_close(); + } + + SDL_LockMutex(rendererMutex); + SDL_CondSignal(rendererCond); + SDL_UnlockMutex(rendererMutex); + + return SDL_TRUE; +} + +void* timer = 0; + +void render_timer() +{ +#ifdef PCEM_RENDER_TIMER_LOOP + /* For some reason this while-loop works on OSX, which also fixes missing events. No idea why though. */ + renderer_thread(0); +#else + if (rendering && !render()) + { + window_close(); + window_create(); + renderer_doreset = 1; + } +#endif +} + +void render_start_timer() +{ +#ifdef PCEM_RENDER_TIMER_LOOP + timer = wx_createtimer(render_timer); + wx_starttimer(timer, 500, 1); +#else + window_setup(); + if (window_create()) + { + rendering = 1; + renderer_doreset = 1; + wx_starttimer(timer, 1, 0); + } +#endif +} + +void renderer_start() +{ + if (!rendering) + { +#ifdef PCEM_RENDER_WITH_TIMER + render_start_timer(); +#else + SDL_LockMutex(rendererMutex); + renderthread = SDL_CreateThread(renderer_thread, "SDL2 Thread", NULL); + SDL_CondWait(rendererCond, rendererMutex); + SDL_UnlockMutex(rendererMutex); +#endif + } +} + +void renderer_stop(int timeout) +{ +#if defined(PCEM_RENDER_WITH_TIMER) && !defined(PCEM_RENDER_TIMER_LOOP) + rendering = 0; + window_close(); + wx_destroytimer(timer); +#else + if (rendering) + { + SDL_LockMutex(rendererMutex); + rendering = 0; + if (timeout) + SDL_CondWaitTimeout(rendererCond, rendererMutex, timeout); + else + SDL_CondWait(rendererCond, rendererMutex); + SDL_UnlockMutex(rendererMutex); + renderthread = NULL; + } + if (timer) + wx_destroytimer(timer); +#endif +} diff --git a/src/wx-sdl2-display.c b/src/wx-sdl2-display.c new file mode 100644 index 0000000..ac8c23e --- /dev/null +++ b/src/wx-sdl2-display.c @@ -0,0 +1,776 @@ +#include +#include "video.h" +#include "wx-sdl2-video.h" +#include "wx-utils.h" +#include "ibm.h" +#include "wx-display.h" +#include "plat-keyboard.h" + +#ifdef __WINDOWS__ +#define BITMAP WINDOWS_BITMAP +#undef UNICODE +#include +#include +#undef BITMAP + +HHOOK hKeyboardHook; +int modkeystate[255]; + +#endif + +SDL_mutex* rendererMutex; +SDL_cond* rendererCond; +SDL_Thread* renderthread = NULL; + +SDL_Window* window = NULL; + +int rendering = 0; + +int mousecapture = 0; + +extern int pause; +extern int video_scale; +extern int take_screenshot; + +void* ghwnd; +void* menu; + +SDL_Rect remembered_rect; +int remembered_mouse_x = 0; +int remembered_mouse_y = 0; + +int custom_resolution_width = 640; +int custom_resolution_height = 480; + +int win_doresize = 0; +int winsizex = 640, winsizey = 480; + +void renderer_start(); +void renderer_stop(int timeout); + +int trigger_fullscreen = 0; +int trigger_screenshot = 0; +int trigger_togglewindow = 0; +int trigger_inputrelease = 0; + +extern void device_force_redraw(); +extern void mouse_wheel_update(int); +extern void toggle_fullscreen(); + +void display_resize(int width, int height) +{ + winsizex = width*(video_scale+1) >> 1; + winsizey = height*(video_scale+1) >> 1; + + SDL_Rect rect; + rect.x = rect.y = 0; + rect.w = winsizex; + rect.h = winsizey; + sdl_scale(video_fullscreen_scale, rect, &rect, winsizex, winsizey); + winsizex = rect.w; + winsizey = rect.h; + + win_doresize = 1; +} + +void releasemouse() +{ + if (mousecapture) + { + SDL_SetWindowGrab(window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + mousecapture = 0; + } +} + +int display_init() +{ + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0) + { + printf("SDL could not initialize! Error: %s\n", SDL_GetError()); + return 0; + } + + SDL_version ver; + SDL_GetVersion(&ver); + printf("SDL %i.%i.%i initialized.\n", ver.major, ver.minor, ver.patch); + return 1; +} + +void display_close() +{ + SDL_Quit(); +} + +void display_start(void* hwnd) +{ + ghwnd = hwnd; + menu = wx_getmenu(hwnd); + atexit(releasemouse); + rendererMutex = SDL_CreateMutex(); + rendererCond = SDL_CreateCond(); + renderer_start(); +} + +void display_stop() +{ + renderer_stop(10 * 1000); + + SDL_DestroyMutex(rendererMutex); + SDL_DestroyCond(rendererCond); +#if SDL_VERSION_ATLEAST(2, 0, 2) + SDL_DetachThread(renderthread); +#endif + releasemouse(); +} + +int is_fullscreen() +{ + int flags = SDL_GetWindowFlags(window); + return (flags&SDL_WINDOW_FULLSCREEN) || (flags&SDL_WINDOW_FULLSCREEN_DESKTOP); +} + +void sdl_set_window_title(const char* title) { + if (window && !is_fullscreen()) + SDL_SetWindowTitle(window, title); +} + +int get_border_size(int* top, int* left, int* bottom, int* right) +{ +#if SDL_VERSION_ATLEAST(2, 0, 5) + return SDL_GetWindowBordersSize(window, top, left, bottom, right); +#else + if (top) *top = 0; + if (left) *left = 0; + if (bottom) *bottom = 0; + if (right) *right = 0; + return 0; +#endif +} + +static const struct { + SDL_Scancode sdl; + int system; +} SDLScancodeToSystemScancode[] = { + { SDL_SCANCODE_A, 0x1e }, + { SDL_SCANCODE_B, 0x30 }, + { SDL_SCANCODE_C, 0x2e }, + { SDL_SCANCODE_D, 0x20 }, + { SDL_SCANCODE_E, 0x12 }, + { SDL_SCANCODE_F, 0x21 }, + { SDL_SCANCODE_G, 0x22 }, + { SDL_SCANCODE_H, 0x23 }, + { SDL_SCANCODE_I, 0x17 }, + { SDL_SCANCODE_J, 0x24 }, + { SDL_SCANCODE_K, 0x25 }, + { SDL_SCANCODE_L, 0x26 }, + { SDL_SCANCODE_M, 0x32 }, + { SDL_SCANCODE_N, 0x31 }, + { SDL_SCANCODE_O, 0x18 }, + { SDL_SCANCODE_P, 0x19 }, + { SDL_SCANCODE_Q, 0x10 }, + { SDL_SCANCODE_R, 0x13 }, + { SDL_SCANCODE_S, 0x1f }, + { SDL_SCANCODE_T, 0x14 }, + { SDL_SCANCODE_U, 0x16 }, + { SDL_SCANCODE_V, 0x2f }, + { SDL_SCANCODE_W, 0x11 }, + { SDL_SCANCODE_X, 0x2d }, + { SDL_SCANCODE_Y, 0x15 }, + { SDL_SCANCODE_Z, 0x2c }, + { SDL_SCANCODE_0, 0x0B }, + { SDL_SCANCODE_1, 0x02 }, + { SDL_SCANCODE_2, 0x03 }, + { SDL_SCANCODE_3, 0x04 }, + { SDL_SCANCODE_4, 0x05 }, + { SDL_SCANCODE_5, 0x06 }, + { SDL_SCANCODE_6, 0x07 }, + { SDL_SCANCODE_7, 0x08 }, + { SDL_SCANCODE_8, 0x09 }, + { SDL_SCANCODE_9, 0x0A }, + { SDL_SCANCODE_GRAVE, 0x29 }, + { SDL_SCANCODE_MINUS, 0x0c }, + { SDL_SCANCODE_EQUALS, 0x0d }, + { SDL_SCANCODE_NONUSBACKSLASH, 0x56 }, + { SDL_SCANCODE_BACKSLASH, 0x2b }, + { SDL_SCANCODE_BACKSPACE, 0x0e }, + { SDL_SCANCODE_SPACE, 0x39 }, + { SDL_SCANCODE_TAB, 0x0f }, + { SDL_SCANCODE_CAPSLOCK, 0x3a }, + { SDL_SCANCODE_LSHIFT, 0x2a }, + { SDL_SCANCODE_LCTRL, 0x1d }, + { SDL_SCANCODE_LGUI, 0xdb }, + { SDL_SCANCODE_LALT, 0x38 }, + { SDL_SCANCODE_RSHIFT, 0x36 }, + { SDL_SCANCODE_RCTRL, 0x9d }, + { SDL_SCANCODE_RGUI, 0xdc }, + { SDL_SCANCODE_RALT, 0xb8 }, + { SDL_SCANCODE_SYSREQ, 0x54 }, + { SDL_SCANCODE_APPLICATION, 0xdd }, + { SDL_SCANCODE_RETURN, 0x1c }, + { SDL_SCANCODE_ESCAPE, 0x01 }, + { SDL_SCANCODE_F1, 0x3B }, + { SDL_SCANCODE_F2, 0x3C }, + { SDL_SCANCODE_F3, 0x3D }, + { SDL_SCANCODE_F4, 0x3e }, + { SDL_SCANCODE_F5, 0x3f }, + { SDL_SCANCODE_F6, 0x40 }, + { SDL_SCANCODE_F7, 0x41 }, + { SDL_SCANCODE_F8, 0x42 }, + { SDL_SCANCODE_F9, 0x43 }, + { SDL_SCANCODE_F10, 0x44 }, + { SDL_SCANCODE_F11, 0x57 }, + { SDL_SCANCODE_F12, 0x58 }, + { SDL_SCANCODE_SCROLLLOCK, 0x46 }, + { SDL_SCANCODE_LEFTBRACKET, 0x1a }, + { SDL_SCANCODE_RIGHTBRACKET, 0x1b }, + { SDL_SCANCODE_INSERT, 0xd2 }, + { SDL_SCANCODE_HOME, 0xc7 }, + { SDL_SCANCODE_PAGEUP, 0xc9 }, + { SDL_SCANCODE_DELETE, 0xd3 }, + { SDL_SCANCODE_END, 0xcf }, + { SDL_SCANCODE_PAGEDOWN, 0xd1 }, + { SDL_SCANCODE_UP, 0xc8 }, + { SDL_SCANCODE_LEFT, 0xcb }, + { SDL_SCANCODE_DOWN, 0xd0 }, + { SDL_SCANCODE_RIGHT, 0xcd }, + { SDL_SCANCODE_NUMLOCKCLEAR, 0x45 }, + { SDL_SCANCODE_KP_DIVIDE, 0xb5 }, + { SDL_SCANCODE_KP_MULTIPLY, 0x37 }, + { SDL_SCANCODE_KP_MINUS, 0x4a }, + { SDL_SCANCODE_KP_PLUS, 0x4e }, + { SDL_SCANCODE_KP_ENTER, 0x9c }, + { SDL_SCANCODE_KP_PERIOD, 0x53 }, + { SDL_SCANCODE_KP_0, 0x52 }, + { SDL_SCANCODE_KP_1, 0x4f }, + { SDL_SCANCODE_KP_2, 0x50 }, + { SDL_SCANCODE_KP_3, 0x51 }, + { SDL_SCANCODE_KP_4, 0x4b }, + { SDL_SCANCODE_KP_5, 0x4c }, + { SDL_SCANCODE_KP_6, 0x4d }, + { SDL_SCANCODE_KP_7, 0x47 }, + { SDL_SCANCODE_KP_8, 0x48 }, + { SDL_SCANCODE_KP_9, 0x49 }, + { SDL_SCANCODE_SEMICOLON, 0x27 }, + { SDL_SCANCODE_APOSTROPHE, 0x28 }, + { SDL_SCANCODE_COMMA, 0x33 }, + { SDL_SCANCODE_PERIOD, 0x34 }, + { SDL_SCANCODE_SLASH, 0x35 }, + { SDL_SCANCODE_PRINTSCREEN, 0xb7 } +}; + +int sdl_scancode(SDL_Scancode scancode) +{ + int i; + for (i = 0; i < SDL_arraysize(SDLScancodeToSystemScancode); ++i) { + if (SDLScancodeToSystemScancode[i].sdl == scancode) { + return SDLScancodeToSystemScancode[i].system; + } + } + return -1; +} + +SDL_Event event; +SDL_Rect rect; +int border_x, border_y = 0; + +uint64_t render_time = 0; +int render_fps = 0; +uint32_t render_frame_time = 0; +uint32_t render_frames = 0; + +void window_setup() +{ + SDL_SetHint(SDL_HINT_GRAB_KEYBOARD, "1"); +#if SDL_VERSION_ATLEAST(2, 0, 5) + SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); +#endif + + if (start_in_fullscreen) + { + start_in_fullscreen = 0; + window_dofullscreen = 1; + window_doinputgrab = 1; + } + + if (window_remember) + { + rect.x = window_x; + rect.y = window_y; + rect.w = window_w; + rect.h = window_h; + } + else + { + rect.x = SDL_WINDOWPOS_CENTERED; + rect.y = SDL_WINDOWPOS_CENTERED; + rect.w = 640; + rect.h = 480; + } + + if (vid_resize == 2) + { + rect.w = custom_resolution_width; + rect.h = custom_resolution_height; + } +} + +#ifdef __WINDOWS__ +int sdl_winhook(int code) +{ + switch(code) + { + case VK_LMENU: + return SDL_SCANCODE_LALT; + case VK_LCONTROL: + return SDL_SCANCODE_LCTRL; + case VK_LWIN: + return SDL_SCANCODE_LGUI; + case VK_LSHIFT: + return SDL_SCANCODE_LSHIFT; + case VK_RMENU: + return SDL_SCANCODE_RALT; + case VK_RCONTROL: + return SDL_SCANCODE_RCTRL; + case VK_RWIN: + return SDL_SCANCODE_RGUI; + case VK_RSHIFT: + return SDL_SCANCODE_RSHIFT; + } + + return -1; +} + +LRESULT CALLBACK LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam; + + int c = p->vkCode; + + int steal = 0; + int s = sdl_winhook(c); + if (s != -1) + { + int key_state = !(p->flags & LLKHF_UP); + if (abs(modkeystate[c]) != key_state) + { + /* if mousecapture is 0, key_state should be negative */ + if (!mousecapture) + key_state = -key_state; + /* if key_state is 0 and modkeystate[c] is negative, + an sdl_event should not be generated */ + if (key_state > 0 || modkeystate[c] > 0) + { + steal = key_state != 0; + SDL_Event event; + event.key.keysym.scancode = s; + event.key.timestamp = p->time; + + event.type = key_state ? SDL_KEYDOWN : SDL_KEYUP; + SDL_PushEvent(&event); + } + modkeystate[c] = key_state; + } + if (steal) + return 1; + } + + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); +} +#endif + +int window_create() +{ + window = SDL_CreateWindow("PCem Display", + rect.x, rect.y, rect.w, rect.h, + requested_render_driver.sdl_window_params | (vid_resize == 1 ? SDL_WINDOW_RESIZABLE : 0)); + if (!window) + { + char message[200]; + sprintf(message, + "SDL window could not be created! Error: %s\n", + SDL_GetError()); + wx_messagebox(ghwnd, message, "SDL Error", WX_MB_OK); + return 0; + } + +#ifdef __WINDOWS__ + memset(modkeystate, 0, sizeof(modkeystate)); + hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0); +#endif + + render_time = 0; + render_fps = 0; + render_frame_time = SDL_GetTicks(); + render_frames = 0; + return 1; +} + +void window_close() +{ +#ifdef __WINDOWS__ + UnhookWindowsHookEx( hKeyboardHook ); +#endif + + sdl_renderer_close(); + + if (window) { + SDL_GetWindowPosition(window, &rect.x, &rect.y); + SDL_GetWindowSize(window, &rect.w, &rect.h); + get_border_size(&border_y, &border_x, 0, 0); + rect.x -= border_x; + rect.y -= border_y; + + SDL_DestroyWindow(window); + } + window = NULL; +} + +int render() +{ + uint64_t start_time = timer_read(); + uint64_t end_time; + + if (window_dosetresize) + { + window_dosetresize = 0; +#if SDL_VERSION_ATLEAST(2, 0, 5) + SDL_GetWindowSize(window, &rect.w, &rect.h); + SDL_SetWindowResizable(window, vid_resize == 1); + SDL_SetWindowSize(window, rect.w, rect.h); +#else + window_doreset = 1; +#endif + if (vid_resize == 2) + SDL_SetWindowSize(window, custom_resolution_width, custom_resolution_height); + + device_force_redraw(); + } + if (window_doreset) + { + pclog("window_doreset\n"); + window_doreset = 0; + renderer_doreset = 0; + return 0; + } + if (renderer_doreset) + { + pclog("renderer_doreset\n"); + renderer_doreset = 0; + sdl_renderer_close(); + sdl_renderer_init(window); + + device_force_redraw(); + video_wait_for_blit(); + } + while(SDL_PollEvent(&event)) + { + switch (event.type) { + case SDL_MOUSEBUTTONUP: + if (!mousecapture) + { + if (event.button.button == SDL_BUTTON_LEFT && !pause) + { + window_doinputgrab = 1; + if (video_fullscreen) + window_dofullscreen = 1; + } + else if (event.button.button == SDL_BUTTON_RIGHT) + wx_popupmenu(ghwnd, menu, 0, 0); + + } + else if (event.button.button == SDL_BUTTON_MIDDLE && !is_fullscreen()) + window_doinputrelease = 1; + break; + case SDL_MOUSEWHEEL: + if (mousecapture) mouse_wheel_update(event.wheel.y); + break; + case SDL_WINDOWEVENT: + if (event.window.event == SDL_WINDOWEVENT_CLOSE) + wx_stop_emulation(ghwnd); + if (event.window.event == SDL_WINDOWEVENT_RESIZED) + device_force_redraw(); + if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) + { + if (is_fullscreen()) + window_dowindowed = 1; + window_doinputrelease = 1; + } + + if (window_remember) + { + int flags = SDL_GetWindowFlags(window); + if (!(flags&SDL_WINDOW_FULLSCREEN) && !(flags&SDL_WINDOW_FULLSCREEN_DESKTOP)) + { + if (event.window.event == SDL_WINDOWEVENT_MOVED) + { + get_border_size(&border_y, &border_x, 0, 0); + window_x = event.window.data1-border_x; + window_y = event.window.data2-border_y; + } + else if (event.window.event == SDL_WINDOWEVENT_RESIZED) + { + window_w = event.window.data1; + window_h = event.window.data2; + } + //save_window_pos = 1; + } + } + + break; + case SDL_KEYDOWN: + { +#ifdef __WINDOWS__ + /* international keyboard workaround */ + if (event.key.keysym.scancode == SDL_SCANCODE_RALT && + (event.key.keysym.mod&KMOD_LCTRL) && + event.key.timestamp == rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)]) + rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] = 0; +#endif + int key_idx = sdl_scancode(event.key.keysym.scancode); + if (key_idx != -1) + rawinputkey[key_idx] = event.key.timestamp; + break; + } + case SDL_KEYUP: + { + int key_idx = sdl_scancode(event.key.keysym.scancode); + if (key_idx != -1) + rawinputkey[key_idx] = 0; + break; + } + } + } + if ((rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEDOWN)] || rawinputkey[sdl_scancode(SDL_SCANCODE_KP_3)]) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)])) + trigger_fullscreen = 1; + else if (trigger_fullscreen) + { + trigger_fullscreen = 0; + toggle_fullscreen(); + } + else if ((rawinputkey[sdl_scancode(SDL_SCANCODE_PAGEUP)] || rawinputkey[sdl_scancode(SDL_SCANCODE_KP_9)]) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)]) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LALT)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RALT)])) + trigger_screenshot = 1; + else if (trigger_screenshot) + { + trigger_screenshot = 0; + take_screenshot = 1; + } + else if ((event.key.keysym.scancode == SDL_SCANCODE_END || event.key.keysym.scancode == SDL_SCANCODE_KP_1) && + (rawinputkey[sdl_scancode(SDL_SCANCODE_LCTRL)] || rawinputkey[sdl_scancode(SDL_SCANCODE_RCTRL)])) + trigger_inputrelease = 1; + else if (trigger_inputrelease) + { + trigger_inputrelease = 0; + if (!is_fullscreen()) + window_doinputrelease = 1; + } + if (window_doremember) + { + window_doremember = 0; + SDL_GetWindowPosition(window, &window_x, &window_y); + SDL_GetWindowSize(window, &window_w, &window_h); + get_border_size(&border_y, &border_x, 0, 0); + window_x -= border_x; + window_y -= border_y; + saveconfig(NULL); + } + + if (window_dotogglefullscreen) + { + window_dotogglefullscreen = 0; + if (SDL_GetWindowGrab(window) || is_fullscreen()) + { + window_doinputrelease = 1; + if (is_fullscreen()) + window_dowindowed = 1; + } + else + { + window_doinputgrab = 1; + window_dofullscreen = 1; + } + } + + if (window_dofullscreen) + { + window_dofullscreen = 0; + video_wait_for_blit(); + SDL_RaiseWindow(window); +#if SDL_VERSION_ATLEAST(2, 0, 4) + SDL_GetGlobalMouseState(&remembered_mouse_x, &remembered_mouse_y); +#endif + SDL_GetWindowPosition(window, &remembered_rect.x, &remembered_rect.y); + get_border_size(&border_y, &border_x, 0, 0); + remembered_rect.x -= border_x; + remembered_rect.y -= border_y; + SDL_GetWindowSize(window, &remembered_rect.w, &remembered_rect.h); + SDL_SetWindowFullscreen(window, video_fullscreen_mode == 0 ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN); + device_force_redraw(); + } + if (window_doinputgrab) { + window_doinputgrab = 0; + mousecapture = 1; + SDL_GetRelativeMouseState(0, 0); + SDL_SetWindowGrab(window, SDL_TRUE); + SDL_SetRelativeMouseMode(SDL_TRUE); + } + + if (window_doinputrelease) { + window_doinputrelease = 0; + mousecapture = 0; + SDL_SetWindowGrab(window, SDL_FALSE); + SDL_SetRelativeMouseMode(SDL_FALSE); + } + if (window_dowindowed) + { + window_dowindowed = 0; + SDL_SetWindowFullscreen(window, 0); + SDL_SetWindowSize(window, remembered_rect.w, remembered_rect.h); + SDL_SetWindowPosition(window, remembered_rect.x, remembered_rect.y); +#if SDL_VERSION_ATLEAST(2, 0, 4) + SDL_WarpMouseGlobal(remembered_mouse_x, remembered_mouse_y); +#endif + device_force_redraw(); + } + + if (win_doresize) + { + int flags = SDL_GetWindowFlags(window); + + win_doresize = 0; + if (!vid_resize || (flags&SDL_WINDOW_FULLSCREEN)) { + SDL_GetWindowSize(window, &rect.w, &rect.h); + if (rect.w != winsizex || rect.h != winsizey) { + SDL_GetWindowPosition(window, &rect.x, &rect.y); + SDL_SetWindowSize(window, winsizex, winsizey); + SDL_SetWindowPosition(window, rect.x, rect.y); + device_force_redraw(); + } + } + } + + if (sdl_renderer_update(window)) sdl_renderer_present(window); + + end_time = timer_read(); + render_time += end_time - start_time; + + ++render_frames; + uint32_t ticks = SDL_GetTicks(); + if (ticks-render_frame_time >= 1000) { + render_fps = render_frames/((ticks-render_frame_time)/1000.0); + render_frames = 0; + render_frame_time = ticks; + } + + return 1; +} + +int renderer_thread(void* params) +{ + int internal_rendering; + + SDL_LockMutex(rendererMutex); + SDL_CondSignal(rendererCond); + SDL_UnlockMutex(rendererMutex); + + window_setup(); + + rendering = 1; + while (rendering) { + + if (!window_create()) + rendering = 0; + + renderer_doreset = 1; + internal_rendering = 1; + while (rendering && internal_rendering) + { + if (!render()) + internal_rendering = 0; + + SDL_Delay(1); + } + window_close(); + } + + SDL_LockMutex(rendererMutex); + SDL_CondSignal(rendererCond); + SDL_UnlockMutex(rendererMutex); + + return SDL_TRUE; +} + +void* timer = 0; + +void render_timer() +{ +#ifdef PCEM_RENDER_TIMER_LOOP + /* For some reason this while-loop works on OSX, which also fixes missing events. No idea why though. */ + renderer_thread(0); +#else + if (rendering && !render()) + { + window_close(); + window_create(); + renderer_doreset = 1; + } +#endif +} + +void render_start_timer() +{ +#ifdef PCEM_RENDER_TIMER_LOOP + timer = wx_createtimer(render_timer); + wx_starttimer(timer, 500, 1); +#else + window_setup(); + if (window_create()) + { + rendering = 1; + renderer_doreset = 1; + wx_starttimer(timer, 1, 0); + } +#endif +} + +void renderer_start() +{ + if (!rendering) + { +#ifdef PCEM_RENDER_WITH_TIMER + render_start_timer(); +#else + SDL_LockMutex(rendererMutex); + renderthread = SDL_CreateThread(renderer_thread, "SDL2 Thread", NULL); + SDL_CondWait(rendererCond, rendererMutex); + SDL_UnlockMutex(rendererMutex); +#endif + } +} + +void renderer_stop(int timeout) +{ +#if defined(PCEM_RENDER_WITH_TIMER) && !defined(PCEM_RENDER_TIMER_LOOP) + rendering = 0; + window_close(); + wx_destroytimer(timer); +#else + if (rendering) + { + SDL_LockMutex(rendererMutex); + rendering = 0; + if (timeout) + SDL_CondWaitTimeout(rendererCond, rendererMutex, timeout); + else + SDL_CondWait(rendererCond, rendererMutex); + SDL_UnlockMutex(rendererMutex); + renderthread = NULL; + } + if (timer) + wx_destroytimer(timer); +#endif +} diff --git a/src/wx-sdl2-glw.h b/src/wx-sdl2-glw.h new file mode 100644 index 0000000..babf48b --- /dev/null +++ b/src/wx-sdl2-glw.h @@ -0,0 +1,92 @@ +#ifndef SRC_WX_SDL2_GLW_H_ +#define SRC_WX_SDL2_GLW_H_ + +typedef struct glw_t { + PFNGLACTIVETEXTUREPROC glActiveTexture; + PFNGLCREATESHADERPROC glCreateShader; + PFNGLSHADERSOURCEPROC glShaderSource; + PFNGLCOMPILESHADERPROC glCompileShader; + PFNGLGETSHADERIVPROC glGetShaderiv; + PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog; + PFNGLCREATEPROGRAMPROC glCreateProgram; + PFNGLATTACHSHADERPROC glAttachShader; + PFNGLLINKPROGRAMPROC glLinkProgram; + PFNGLGETPROGRAMIVPROC glGetProgramiv; + PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog; + PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation; + PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation; + PFNGLUSEPROGRAMPROC glUseProgram; + PFNGLGENERATEMIPMAPPROC glGenerateMipmap; + PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers; + PFNGLDELETESHADERPROC glDeleteShader; + PFNGLDELETEPROGRAMPROC glDeleteProgram; + PFNGLDELETEBUFFERSPROC glDeleteBuffers; + PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays; + PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers; + PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer; + PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D; + PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus; + PFNGLGENVERTEXARRAYSPROC glGenVertexArrays; + PFNGLBINDVERTEXARRAYPROC glBindVertexArray; + PFNGLGENBUFFERSPROC glGenBuffers; + PFNGLBINDBUFFERPROC glBindBuffer; + PFNGLBUFFERDATAPROC glBufferData; + PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer; + PFNGLUNIFORM1IPROC glUniform1i; + PFNGLUNIFORM1FPROC glUniform1f; + PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray; + PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv; + PFNGLUNIFORM2FVPROC glUniform2fv; + PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray; + PFNGLBUFFERSUBDATAPROC glBufferSubData; +} glw_t; + +glw_t* glw_init() +{ + glw_t* glw = malloc(sizeof(glw_t)); + glw->glActiveTexture = SDL_GL_GetProcAddress("glActiveTexture"); + glw->glCreateShader = SDL_GL_GetProcAddress("glCreateShader"); + glw->glShaderSource = SDL_GL_GetProcAddress("glShaderSource"); + glw->glCompileShader = SDL_GL_GetProcAddress("glCompileShader"); + glw->glGetShaderiv = SDL_GL_GetProcAddress("glGetShaderiv"); + glw->glGetShaderInfoLog = SDL_GL_GetProcAddress("glGetShaderInfoLog"); + glw->glCreateProgram = SDL_GL_GetProcAddress("glCreateProgram"); + glw->glAttachShader = SDL_GL_GetProcAddress("glAttachShader"); + glw->glLinkProgram = SDL_GL_GetProcAddress("glLinkProgram"); + glw->glGetProgramiv = SDL_GL_GetProcAddress("glGetProgramiv"); + glw->glGetProgramInfoLog = SDL_GL_GetProcAddress("glGetProgramInfoLog"); + glw->glGetUniformLocation = SDL_GL_GetProcAddress("glGetUniformLocation"); + glw->glGetAttribLocation = SDL_GL_GetProcAddress("glGetAttribLocation"); + glw->glUseProgram = SDL_GL_GetProcAddress("glUseProgram"); + glw->glGenerateMipmap = SDL_GL_GetProcAddress("glGenerateMipmap"); + glw->glDeleteFramebuffers = SDL_GL_GetProcAddress("glDeleteFramebuffers"); + glw->glDeleteShader = SDL_GL_GetProcAddress("glDeleteShader"); + glw->glDeleteProgram = SDL_GL_GetProcAddress("glDeleteProgram"); + glw->glDeleteBuffers = SDL_GL_GetProcAddress("glDeleteBuffers"); + glw->glDeleteVertexArrays = SDL_GL_GetProcAddress("glDeleteVertexArrays"); + glw->glGenFramebuffers = SDL_GL_GetProcAddress("glGenFramebuffers"); + glw->glBindFramebuffer = SDL_GL_GetProcAddress("glBindFramebuffer"); + glw->glFramebufferTexture2D = SDL_GL_GetProcAddress("glFramebufferTexture2D"); + glw->glCheckFramebufferStatus = SDL_GL_GetProcAddress("glCheckFramebufferStatus"); + glw->glGenVertexArrays = SDL_GL_GetProcAddress("glGenVertexArrays"); + glw->glBindVertexArray = SDL_GL_GetProcAddress("glBindVertexArray"); + glw->glGenBuffers = SDL_GL_GetProcAddress("glGenBuffers"); + glw->glBindBuffer = SDL_GL_GetProcAddress("glBindBuffer"); + glw->glBufferData = SDL_GL_GetProcAddress("glBufferData"); + glw->glVertexAttribPointer = SDL_GL_GetProcAddress("glVertexAttribPointer"); + glw->glUniform1i = SDL_GL_GetProcAddress("glUniform1i"); + glw->glUniform1f = SDL_GL_GetProcAddress("glUniform1f"); + glw->glEnableVertexAttribArray = SDL_GL_GetProcAddress("glEnableVertexAttribArray"); + glw->glUniformMatrix4fv = SDL_GL_GetProcAddress("glUniformMatrix4fv"); + glw->glUniform2fv = SDL_GL_GetProcAddress("glUniform2fv"); + glw->glDisableVertexAttribArray = SDL_GL_GetProcAddress("glDisableVertexAttribArray"); + glw->glBufferSubData = SDL_GL_GetProcAddress("glBufferSubData"); + return glw; +} + +void glw_free(glw_t* glw) +{ + free(glw); +} + +#endif /* SRC_WX_SDL2_GLW_H_ */ diff --git a/src/wx-sdl2-joystick.c b/src/wx-sdl2-joystick.c new file mode 100644 index 0000000..8aa487b --- /dev/null +++ b/src/wx-sdl2-joystick.c @@ -0,0 +1,165 @@ +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "gameport.h" +#include "plat-joystick.h" + +int joysticks_present; +joystick_t joystick_state[MAX_JOYSTICKS]; + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +static SDL_Joystick *sdl_joy[MAX_PLAT_JOYSTICKS]; + +void joystick_init() +{ + int c; + + SDL_InitSubSystem(SDL_INIT_JOYSTICK); + joysticks_present = SDL_NumJoysticks(); + + memset(sdl_joy, 0, sizeof(sdl_joy)); + for (c = 0; c < joysticks_present; c++) + { + sdl_joy[c] = SDL_JoystickOpen(c); + + if (sdl_joy[c]) + { + int d; + + pclog("Opened Joystick %i\n", c); + pclog(" Name: %s\n", SDL_JoystickName(sdl_joy[c])); + pclog(" Number of Axes: %d\n", SDL_JoystickNumAxes(sdl_joy[c])); + pclog(" Number of Buttons: %d\n", SDL_JoystickNumButtons(sdl_joy[c])); + pclog(" Number of Hats: %d\n", SDL_JoystickNumHats(sdl_joy[c])); + + strncpy(plat_joystick_state[c].name, SDL_JoystickNameForIndex(c), 64); + plat_joystick_state[c].nr_axes = SDL_JoystickNumAxes(sdl_joy[c]); + plat_joystick_state[c].nr_buttons = SDL_JoystickNumButtons(sdl_joy[c]); + plat_joystick_state[c].nr_povs = SDL_JoystickNumHats(sdl_joy[c]); + + for (d = 0; d < MIN(plat_joystick_state[c].nr_axes, 8); d++) + { + sprintf(plat_joystick_state[c].axis[d].name, "Axis %i", d); + plat_joystick_state[c].axis[d].id = d; + } + for (d = 0; d < MIN(plat_joystick_state[c].nr_buttons, 8); d++) + { + sprintf(plat_joystick_state[c].button[d].name, "Button %i", d); + plat_joystick_state[c].button[d].id = d; + } + for (d = 0; d < MIN(plat_joystick_state[c].nr_povs, 4); d++) + { + sprintf(plat_joystick_state[c].pov[d].name, "POV %i", d); + plat_joystick_state[c].pov[d].id = d; + } + } + } +} +void joystick_close() +{ + int c; + + for (c = 0; c < joysticks_present; c++) + { + if (sdl_joy[c]) + SDL_JoystickClose(sdl_joy[c]); + } +} + +static int joystick_get_axis(int joystick_nr, int mapping) +{ + if (mapping & POV_X) + { + switch (plat_joystick_state[joystick_nr].p[mapping & 3]) + { + case SDL_HAT_LEFTUP: case SDL_HAT_LEFT: case SDL_HAT_LEFTDOWN: + return -32767; + + case SDL_HAT_RIGHTUP: case SDL_HAT_RIGHT: case SDL_HAT_RIGHTDOWN: + return 32767; + + default: + return 0; + } + } + else if (mapping & POV_Y) + { + switch (plat_joystick_state[joystick_nr].p[mapping & 3]) + { + case SDL_HAT_LEFTUP: case SDL_HAT_UP: case SDL_HAT_RIGHTUP: + return -32767; + + case SDL_HAT_LEFTDOWN: case SDL_HAT_DOWN: case SDL_HAT_RIGHTDOWN: + return 32767; + + default: + return 0; + } + } + else + return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; +} +void joystick_poll() +{ + int c, d; + + SDL_JoystickUpdate(); + for (c = 0; c < joysticks_present; c++) + { + int b; + + plat_joystick_state[c].a[0] = SDL_JoystickGetAxis(sdl_joy[c], 0); + plat_joystick_state[c].a[1] = SDL_JoystickGetAxis(sdl_joy[c], 1); + plat_joystick_state[c].a[2] = SDL_JoystickGetAxis(sdl_joy[c], 2); + plat_joystick_state[c].a[3] = SDL_JoystickGetAxis(sdl_joy[c], 3); + plat_joystick_state[c].a[4] = SDL_JoystickGetAxis(sdl_joy[c], 4); + plat_joystick_state[c].a[5] = SDL_JoystickGetAxis(sdl_joy[c], 5); + + for (b = 0; b < 16; b++) + plat_joystick_state[c].b[b] = SDL_JoystickGetButton(sdl_joy[c], b); + + for (b = 0; b < 4; b++) + plat_joystick_state[c].p[b] = SDL_JoystickGetHat(sdl_joy[c], 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++) + joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); + 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]]; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + { + int x, y; + double angle, magnitude; + + x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); + y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); + + angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); + magnitude = sqrt((double)x*(double)x + (double)y*(double)y); + + if (magnitude < 16384) + joystick_state[c].pov[d] = -1; + else + joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360; + } + } + 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; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + joystick_state[c].pov[d] = -1; + } + } +} diff --git a/src/wx-sdl2-keyboard.c b/src/wx-sdl2-keyboard.c new file mode 100644 index 0000000..adf8e8a --- /dev/null +++ b/src/wx-sdl2-keyboard.c @@ -0,0 +1,23 @@ +#include "plat-keyboard.h" +#include + +uint8_t pcem_key[272]; +int rawinputkey[272]; + +void keyboard_init() +{ + memset(pcem_key, 0, sizeof(pcem_key)); +} + +void keyboard_close() +{ +} + +void keyboard_poll_host() +{ + int c; + + for (c = 0; c < 272; ++c) + pcem_key[c] = rawinputkey[c] > 0; +} + diff --git a/src/wx-sdl2-midi.c b/src/wx-sdl2-midi.c new file mode 100644 index 0000000..9f89456 --- /dev/null +++ b/src/wx-sdl2-midi.c @@ -0,0 +1,23 @@ +#include +#include "plat-midi.h" + +void midi_init() +{ +} + +void midi_close() +{ +} + +void midi_write(uint8_t val) +{ +} + +int midi_get_num_devs() +{ + return 0; +} + +void midi_get_dev_name(int num, char *s) +{ +} diff --git a/src/wx-sdl2-mouse.c b/src/wx-sdl2-mouse.c new file mode 100644 index 0000000..a9326cf --- /dev/null +++ b/src/wx-sdl2-mouse.c @@ -0,0 +1,60 @@ +#include +#include +#include "plat-mouse.h" + +int mouse_buttons; +static int mouse_x = 0, mouse_y = 0, mouse_z = 0; + +int mouse[3]; + +void mouse_init() +{ + memset(mouse, 0, sizeof(mouse)); +} + +void mouse_close() +{ +} + +void mouse_wheel_update(int dir) +{ + mouse[2] += dir; +} + +void mouse_poll_host() +{ + if (mousecapture) + { + uint32_t mb = SDL_GetRelativeMouseState(&mouse[0], &mouse[1]); + mouse_buttons = 0; + if (mb & SDL_BUTTON(SDL_BUTTON_LEFT)) + { + mouse_buttons |= 1; + } + if (mb & SDL_BUTTON(SDL_BUTTON_RIGHT)) + { + mouse_buttons |= 2; + } + if (mb & SDL_BUTTON(SDL_BUTTON_MIDDLE)) + { + mouse_buttons |= 4; + } + mouse_x += mouse[0]; + mouse_y += mouse[1]; + mouse_z += mouse[2]; + mouse[2] = 0; + } + else + { + mouse_x = mouse_y = mouse_z = mouse_buttons = 0; + } +} + +void mouse_get_mickeys(int *x, int *y, int *z) +{ + *x = mouse_x; + *y = mouse_y; + *z = mouse_z; + mouse_x = mouse_y = mouse_z = 0; +} + diff --git a/src/wx-sdl2-status.c b/src/wx-sdl2-status.c new file mode 100644 index 0000000..71c01ac --- /dev/null +++ b/src/wx-sdl2-status.c @@ -0,0 +1,179 @@ +#include +#include "video.h" +#include "wx-sdl2.h" +#include "wx-sdl2-video.h" +#include "ibm.h" +#include "device.h" +#include "x86_ops.h" +#include "mem.h" +#include "codegen.h" +#include "cpu.h" +#include "model.h" +#include "fdd.h" +#include "hdd.h" +#include "ide.h" +#include "cdrom-image.h" +#include "scsi_zip.h" +#include "codegen_allocator.h" +#include "wx-common.h" + +drive_info_t drive_info[10]; + +int status_is_open = 0; + +extern int sreadlnum, swritelnum, segareads, segawrites, scycles_lost; +extern int render_fps, fps; + +extern uint64_t main_time; +extern uint64_t render_time; +static uint64_t status_time; + +drive_info_t* get_machine_info(char* s, int* num_drive_info) { + int drive, i; + int pos = 0; + sprintf(s, + "Model: %s\n" + "CPU: %s", + model_getname(), + models[model].cpu[cpu_manufacturer].cpus[cpu].name); + if (emulation_state == EMULATION_RUNNING) + sprintf(s+strlen(s), "\nEmulation speed: %d%%", fps); + else if (emulation_state == EMULATION_PAUSED) + strcat(s, "\nEmulation is paused."); + else + strcat(s, "\nEmulation is not running."); + + for (i = 0; i < 2; ++i) + { + drive = 'A'+i; + if (fdd_get_type(i) > 0) + { + strcpy(drive_info[pos].fn, discfns[i]); + drive_info[pos].enabled = strlen(drive_info[pos].fn) > 0; + drive_info[pos].drive = i; + drive_info[pos].drive_letter = drive; + drive_info[pos].type = DRIVE_TYPE_FDD; + drive_info[pos].readflash = readflash_get(READFLASH_FDC, i); + readflash_clear(READFLASH_FDC, i); + pos++; + } + } + int num_hdds = hdd_controller_current_is_mfm() ? 2 : (hdd_controller_current_is_scsi() ? 7 : 4); + for (i = 0; i < num_hdds; ++i) + { + drive = 'C'+i; + if (!hdd_controller_current_is_mfm() && i == cdrom_channel) + { + if (cdrom_drive < 0) + continue; + if (cdrom_drive == CDROM_IMAGE) + { + if (!strlen(image_path)) + continue; + strcpy(drive_info[pos].fn, image_path); + } + else + strcpy(drive_info[pos].fn, ""); + drive_info[pos].enabled = strlen(drive_info[pos].fn) > 0; + drive_info[pos].drive = i; + drive_info[pos].drive_letter = drive; + drive_info[pos].type = DRIVE_TYPE_CDROM; + drive_info[pos].readflash = readflash_get(READFLASH_HDC, i); + readflash_clear(READFLASH_HDC, i); + pos++; + } + else if (!hdd_controller_current_is_mfm() && i == zip_channel) + { + strcpy(drive_info[pos].fn, ""); + drive_info[pos].enabled = zip_loaded(); + drive_info[pos].drive = i; + drive_info[pos].drive_letter = drive; + drive_info[pos].type = DRIVE_TYPE_FDD; + drive_info[pos].readflash = readflash_get(READFLASH_HDC, i); + readflash_clear(READFLASH_HDC, i); + pos++; + } + else if (strlen(ide_fn[i]) > 0) + { + strcpy(drive_info[pos].fn, ide_fn[i]); + drive_info[pos].enabled = 1; + drive_info[pos].drive = i; + drive_info[pos].drive_letter = drive; + drive_info[pos].type = DRIVE_TYPE_HDD; + drive_info[pos].readflash = readflash_get(READFLASH_HDC, i); + readflash_clear(READFLASH_HDC, i); + pos++; + } + } + *num_drive_info = pos; + return drive_info; +} + +int get_status(char* machine, char* device) +{ +// if (!status_is_open) { +// return 0; +// } +// char device_s[4096]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + sprintf(machine, + "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" + "Render time : %f%% (%f%%)\n" + "Renderer: %s\n" + "Render FPS: %d\n" + "\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\nMem blocks used : %i (%g MB)" + // "\nFully recompiled ins %% : %f%%" + ,mips, + flops, + /*#ifndef DYNAREC + sreadlnum, + swritelnum, + #endif*/ + segareads, + segawrites, + cpu_get_speed() - scycles_lost, + pit_timer0_freq(), + ((double)main_time * 100.0) / status_diff, + ((double)main_time * 100.0) / timer_freq, + ((double)render_time * 100.0) / status_diff, + ((double)render_time * 100.0) / timer_freq, + current_render_driver_name, + render_fps + + , 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), + codegen_allocator_usage, + (double)(codegen_allocator_usage * MEM_BLOCK_SIZE) / (1024.0*1024.0) + // ((double)cpu_recomp_full_ins_latched / (double)cpu_recomp_ins_latched) * 100.0 + // cpu_reps_latched, cpu_notreps_latched + ); + main_time = 0; + render_time = 0; + /*#ifndef DYNAREC + device_add_status_info(device_s, 4096); + #endif*/ + +// device_s[0] = 0; + device[0] = 0; + device_add_status_info(device, 4096); + + return 1; +} diff --git a/src/wx-sdl2-video-gl3.c b/src/wx-sdl2-video-gl3.c new file mode 100644 index 0000000..3e4330c --- /dev/null +++ b/src/wx-sdl2-video-gl3.c @@ -0,0 +1,1676 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#if SDL_VERSION_ATLEAST(2, 0, 4) +#include +#endif +#undef BITMAP +#include "wx-sdl2-glw.h" +#include +#include +#include +#include "video.h" +#include "wx-sdl2-video.h" +#include "wx-sdl2-video-renderer.h" +#include "ibm.h" +#include "wx-glslp-parser.h" +#include "wx-utils.h" +#include "config.h" +#include "wx-glsl.h" + +extern char* get_filename(char*); + +extern int take_screenshot; +extern void screenshot_taken(unsigned char* rgb, int width, int height); + +#define SCALE_SOURCE 0 +#define SCALE_VIEWPORT 1 +#define SCALE_ABSOLUTE 2 + +float gl3_shader_refresh_rate = 0; +float gl3_input_scale = 1.0f; +int gl3_input_stretch = FULLSCR_SCALE_FULL; +char gl3_shader_file[MAX_USER_SHADERS][512]; + +static int max_texture_size; + +static SDL_GLContext context = NULL; +static struct shader_texture scene_texture; + +static glsl_t* active_shader; + +static glw_t* glw; + +static GLfloat matrix[] = { + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 +}; + + +extern int video_scale_mode; +extern int video_vsync; +extern int video_focus_dim; +extern int video_refresh_rate; + +static int glsl_version[2]; + +const char* vertex_shader_default_tex_src = + "#version 130\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec2 TexCoord;\n" + "\n" + "out vec2 texCoord;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " texCoord = TexCoord;\n" + "}\n"; + +const char* fragment_shader_default_tex_src = + "#version 130\n" + "\n" + "in vec2 texCoord;\n" + "uniform sampler2D Texture;\n" + "\n" + "out vec4 color;" + "\n" + "void main()\n" + "{\n" + " color = texture(Texture, texCoord);\n" + "}\n"; + +const char* vertex_shader_default_color_src = + "#version 130\n" + "\n" + "in vec4 VertexCoord;\n" + "in vec4 Color;\n" + "\n" + "out vec4 color;\n" + "\n" + "void main()\n" + "{\n" + " gl_Position = VertexCoord;\n" + " color = Color;\n" + "}\n"; + +const char* fragment_shader_default_color_src = + "#version 130\n" + "\n" + "in vec4 color;\n" + "\n" + "out vec4 outColor;" + "\n" + "void main()\n" + "{\n" + " outColor = color;\n" + "}\n"; + +static int next_pow2(unsigned int n) +{ + n--; + n |= n >> 1; // Divide by 2^k for consecutive doublings of k up to 32, + n |= n >> 2; // and then or the results. + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + n++; + + return n; +} + +static int compile_shader(GLenum shader_type, const char* prepend, const char* program, int* dst) +{ + const char* source[3]; + char version[50]; + int ver = 0; + char *version_loc = strstr(program, "#version"); + if (version_loc) + ver = (int)strtol(version_loc + 8, (char**)&program, 10); + else + { + ver = glsl_version[0] * 100 + glsl_version[1] * 10; + if (ver == 300) + ver = 130; + else if (ver == 310) + ver = 140; + else if (ver == 320) + ver = 150; + } + sprintf(version, "#version %d\n", ver); + source[0] = version; + source[1] = prepend ? prepend : ""; + source[2] = program; + + pclog("GLSL version %d\n", ver); + + GLuint shader = glw->glCreateShader(shader_type); + glw->glShaderSource(shader, 3, source, NULL); + glw->glCompileShader(shader); + + GLint status = 0; + glw->glGetShaderiv(shader, GL_COMPILE_STATUS, &status); + if (!status) + { + GLint length; + glw->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + char* log = malloc(length); + glw->glGetShaderInfoLog(shader, length, &length, log); + wx_simple_messagebox("GLSL Error", "Could not compile shader:\n%s", log); + pclog("Could not compile shader: %s\n", log); +// pclog("Shader: %s\n", program); + + free(log); + return 0; + } + + *dst = shader; + + return 1; +} + +static int create_program(struct shader_program* program) +{ + GLint status; + program->id = glw->glCreateProgram(); + glw->glAttachShader(program->id, program->vertex_shader); + glw->glAttachShader(program->id, program->fragment_shader); + + glw->glLinkProgram(program->id); + + glw->glDeleteShader(program->vertex_shader); + glw->glDeleteShader(program->fragment_shader); + + program->vertex_shader = program->fragment_shader = 0; + + glw->glGetProgramiv(program->id, GL_LINK_STATUS, &status); + + if (!status) + { + int maxLength; + int length; + glw->glGetProgramiv(program->id, GL_INFO_LOG_LENGTH, &maxLength); + char* log = malloc(maxLength); + glw->glGetProgramInfoLog(program->id, maxLength, &length, log); + wx_simple_messagebox("GLSL Error", "Program not linked:\n%s", log); + free(log); + return 0; + } + + return 1; +} + +static GLuint get_uniform(GLuint program, const char* name) +{ + return glw->glGetUniformLocation(program, name); +} + +static GLuint get_attrib(GLuint program, const char* name) +{ + return glw->glGetAttribLocation(program, name); +} + +static void find_uniforms(struct glsl_shader* glsl, int num_pass) +{ + int i; + char s[50]; + struct shader_pass* pass = &glsl->passes[num_pass]; + int p = pass->program.id; + glw->glUseProgram(p); + + struct shader_uniforms* u = &pass->uniforms; + + u->mvp_matrix = get_uniform(p, "MVPMatrix"); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->tex_coord = get_attrib(p, "TexCoord"); + u->color = get_attrib(p, "Color"); + + u->frame_count = get_uniform(p, "FrameCount"); + u->frame_direction = get_uniform(p, "FrameDirection"); + + u->texture = get_uniform(p, "Texture"); + u->input_size = get_uniform(p, "InputSize"); + u->texture_size = get_uniform(p, "TextureSize"); + u->output_size = get_uniform(p, "OutputSize"); + + u->orig.texture = get_uniform(p, "OrigTexture"); + u->orig.input_size = get_uniform(p, "OrigInputSize"); + u->orig.texture_size = get_uniform(p, "OrigTextureSize"); + + for (i = 0; i < glsl->num_passes; ++i) + { + sprintf(s, "Pass%dTexture", (i+1)); + u->pass[i].texture = get_uniform(p, s); + sprintf(s, "Pass%dInputSize", (i+1)); + u->pass[i].input_size = get_uniform(p, s); + sprintf(s, "Pass%dTextureSize", (i+1)); + u->pass[i].texture_size = get_uniform(p, s); + + sprintf(s, "PassPrev%dTexture", num_pass-i); + u->prev_pass[i].texture = get_uniform(p, s); + sprintf(s, "PassPrev%dInputSize", num_pass-i); + u->prev_pass[i].input_size = get_uniform(p, s); + sprintf(s, "PassPrev%dTextureSize", num_pass-i); + u->prev_pass[i].texture_size = get_uniform(p, s); + } + + u->prev[0].texture = get_uniform(p, "PrevTexture"); + u->prev[0].tex_coord = get_attrib(p, "PrevTexCoord"); + for (i = 1; i < MAX_PREV; ++i) + { + sprintf(s, "Prev%dTexture", i); + u->prev[i].texture = get_uniform(p, s); + sprintf(s, "Prev%dTexCoord", i); + u->prev[i].tex_coord = get_attrib(p, s); + } + for (i = 0; i < MAX_PREV; ++i) + if (u->prev[i].texture >= 0) glsl->has_prev = 1; + + for (i = 0; i < glsl->num_lut_textures; ++i) + u->lut_textures[i] = get_uniform(p, glsl->lut_textures[i].name); + + for (i = 0; i < glsl->num_parameters; ++i) + u->parameters[i] = get_uniform(p, glsl->parameters[i].id); + + glw->glUseProgram(0); +} + +static void set_scale_mode(char* scale, int* dst) +{ + if (!strcmp(scale, "viewport")) + *dst = SCALE_VIEWPORT; + else if (!strcmp(scale, "absolute")) + *dst = SCALE_ABSOLUTE; + else + *dst = SCALE_SOURCE; +} + +static void setup_scale(struct shader* shader, struct shader_pass* pass) +{ + set_scale_mode(shader->scale_type_x, &pass->scale.mode[0]); + set_scale_mode(shader->scale_type_y, &pass->scale.mode[1]); + pass->scale.value[0] = shader->scale_x; + pass->scale.value[1] = shader->scale_y; +} + +static void create_texture(struct shader_texture* tex) +{ + if (tex->width > max_texture_size) + tex->width = max_texture_size; + if (tex->height > max_texture_size) + tex->height = max_texture_size; + pclog("Create texture with size %dx%d\n", tex->width, tex->height); + glGenTextures(1, (GLuint *)&tex->id); + glBindTexture(GL_TEXTURE_2D, tex->id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, tex->wrap_mode); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, tex->wrap_mode); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex->min_filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex->mag_filter); + glTexImage2D(GL_TEXTURE_2D, 0, tex->internal_format, tex->width, tex->height, 0, tex->format, tex->type, tex->data); + if (tex->mipmap) + glw->glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); +} + +static void delete_texture(struct shader_texture* tex) +{ + if (tex->id > 0) + glDeleteTextures(1, (GLuint *)&tex->id); + tex->id = 0; +} + +static void delete_fbo(struct shader_fbo* fbo) +{ + if (fbo->id >= 0) + { + glw->glDeleteFramebuffers(1, (GLuint *)&fbo->id); + delete_texture(&fbo->texture); + } +} + +static void delete_program(struct shader_program* program) +{ + if (program->vertex_shader) glw->glDeleteShader(program->vertex_shader); + if (program->fragment_shader) glw->glDeleteShader(program->fragment_shader); + glw->glDeleteProgram(program->id); +} + +static void delete_vbo(struct shader_vbo* vbo) +{ + if (vbo->color >= 0) glw->glDeleteBuffers(1, (GLuint *)&vbo->color); + glw->glDeleteBuffers(1, (GLuint *)&vbo->vertex_coord); + glw->glDeleteBuffers(1, (GLuint *)&vbo->tex_coord); +} + +static void delete_pass(struct shader_pass* pass) +{ + delete_fbo(&pass->fbo); + delete_vbo(&pass->vbo); + delete_program(&pass->program); + glw->glDeleteVertexArrays(1, (GLuint *)&pass->vertex_array); +} + +static void delete_prev(struct shader_prev* prev) +{ + delete_fbo(&prev->fbo); + delete_vbo(&prev->vbo); +} + +static void delete_shader(struct glsl_shader* glsl) +{ + int i; + for (i = 0; i < glsl->num_passes; ++i) + delete_pass(&glsl->passes[i]); + if (glsl->has_prev) + { + delete_pass(&glsl->prev_scene); + for (i = 0; i < MAX_PREV; ++i) + delete_prev(&glsl->prev[i]); + } + for (i = 0; i < glsl->num_lut_textures; ++i) + delete_texture(&glsl->lut_textures[i].texture); +} + +static void delete_glsl(glsl_t* glsl) +{ + int i; + for (i = 0; i < glsl->num_shaders; ++i) + delete_shader(&glsl->shaders[i]); + delete_pass(&glsl->scene); + delete_pass(&glsl->fs_color); + delete_pass(&glsl->final_pass); +#ifdef SDL2_SHADER_DEBUG + delete_pass(&glsl->debug); +#endif +} + +static void create_fbo(struct shader_fbo* fbo) +{ + create_texture(&fbo->texture); + + glw->glGenFramebuffers(1, (GLuint *)&fbo->id); + glw->glBindFramebuffer(GL_FRAMEBUFFER, fbo->id); + glw->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo->texture.id, 0); + + if (glw->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + pclog("Could not create framebuffer!\n"); + + glw->glBindFramebuffer(GL_FRAMEBUFFER, 0); +} + +static void setup_fbo(struct shader* shader, struct shader_fbo* fbo) +{ + fbo->texture.internal_format = GL_RGBA8; + fbo->texture.format = GL_RGBA; + fbo->texture.min_filter = fbo->texture.mag_filter = shader->filter_linear ? GL_LINEAR : GL_NEAREST; + fbo->texture.width = 1024; + fbo->texture.height = 1024; + fbo->texture.type = GL_UNSIGNED_BYTE; + if (!strcmp(shader->wrap_mode, "repeat")) + fbo->texture.wrap_mode = GL_REPEAT; + else if (!strcmp(shader->wrap_mode, "mirrored_repeat")) + fbo->texture.wrap_mode = GL_MIRRORED_REPEAT; + else if (!strcmp(shader->wrap_mode, "clamp_to_edge")) + fbo->texture.wrap_mode = GL_CLAMP_TO_EDGE; + else + fbo->texture.wrap_mode = GL_CLAMP_TO_BORDER; + fbo->srgb = 0; + if (shader->srgb_framebuffer) + { + fbo->texture.internal_format = GL_SRGB8_ALPHA8; + fbo->srgb = 1; + } + else if (shader->float_framebuffer) + { + fbo->texture.internal_format = GL_RGBA32F; + fbo->texture.type = GL_FLOAT; + } + + if (fbo->texture.mipmap) + fbo->texture.min_filter = shader->filter_linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + create_fbo(fbo); +} + +static void recreate_fbo(struct shader_fbo* fbo, int width, int height) +{ + if (width != fbo->texture.width || height != fbo->texture.height) + { + glw->glDeleteFramebuffers(1, (GLuint *)&fbo->id); + glDeleteTextures(1, (GLuint *)&fbo->texture.id); + fbo->texture.width = width; + fbo->texture.height = height; + create_fbo(fbo); + } +} + +static int create_default_shader_tex(struct shader_pass* pass) +{ + if ( + !compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_tex_src, &pass->program.vertex_shader) || + !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_tex_src, &pass->program.fragment_shader) || + !create_program(&pass->program)) + return 0; + glw->glGenVertexArrays(1, (GLuint *)&pass->vertex_array); + + struct shader_uniforms* u = &pass->uniforms; + int p = pass->program.id; + memset(u, -1, sizeof(struct shader_uniforms)); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->tex_coord = get_attrib(p, "TexCoord"); + u->texture = get_uniform(p, "Texture"); + pass->scale.mode[0] = pass->scale.mode[1] = SCALE_SOURCE; + pass->scale.value[0] = pass->scale.value[1] = 1.0f; + pass->fbo.id = -1; + pass->active = 1; + return 1; +} + +static int create_default_shader_color(struct shader_pass* pass) +{ + if ( + !compile_shader(GL_VERTEX_SHADER, 0, vertex_shader_default_color_src, &pass->program.vertex_shader) || + !compile_shader(GL_FRAGMENT_SHADER, 0, fragment_shader_default_color_src, &pass->program.fragment_shader) || + !create_program(&pass->program)) + return 0; + glw->glGenVertexArrays(1, (GLuint *)&pass->vertex_array); + + struct shader_uniforms* u = &pass->uniforms; + int p = pass->program.id; + memset(u, -1, sizeof(struct shader_uniforms)); + u->vertex_coord = get_attrib(p, "VertexCoord"); + u->color = get_attrib(p, "Color"); + pass->scale.mode[0] = pass->scale.mode[1] = SCALE_SOURCE; + pass->scale.value[0] = pass->scale.value[1] = 1.0f; + pass->fbo.id = -1; + pass->active = 1; + return 1; +} + +/* create the default scene shader */ +static void create_scene_shader() +{ + struct shader scene_shader_conf; + memset(&scene_shader_conf, 0, sizeof(struct shader)); + create_default_shader_tex(&active_shader->scene); + scene_shader_conf.filter_linear = video_scale_mode; + if (active_shader->num_shaders > 0 && active_shader->shaders[0].input_filter_linear >= 0) + scene_shader_conf.filter_linear = active_shader->shaders[0].input_filter_linear; + setup_fbo(&scene_shader_conf, &active_shader->scene.fbo); + + memset(&scene_shader_conf, 0, sizeof(struct shader)); + create_default_shader_color(&active_shader->fs_color); + setup_fbo(&scene_shader_conf, &active_shader->fs_color.fbo); +} + +static int load_texture(const char* f, struct shader_texture* tex) +{ + void* img = wx_image_load(f); + if (!img) + return 0; + int width, height; + wx_image_get_size(img, &width, &height); + + if (width != next_pow2(width) || height != next_pow2(height)) + wx_image_rescale(img, next_pow2(width), next_pow2(height)); + + wx_image_get_size(img, &width, &height); + + GLubyte* rgb = wx_image_get_data(img); + GLubyte* alpha = wx_image_get_alpha(img); + + int bpp = alpha ? 4 : 3; + + GLubyte* data = malloc(width*height*bpp); + + int x, y, Y; + for (y = 0; y < height; ++y) + { + Y = height-y-1; + for (x = 0; x < width; x++) + { + data[(y*width+x)*bpp+0] = rgb[(Y*width+x)*3+0]; + data[(y*width+x)*bpp+1] = rgb[(Y*width+x)*3+1]; + data[(y*width+x)*bpp+2] = rgb[(Y*width+x)*3+2]; + + if (alpha) + data[(y*width+x)*bpp+3] = alpha[Y*width+x]; + } + } + wx_image_free(img); + + tex->width = width; + tex->height = height; + tex->internal_format = alpha ? GL_RGBA8 : GL_RGB8; + tex->format = alpha ? GL_RGBA : GL_RGB; + tex->type = GL_UNSIGNED_BYTE; + tex->data = data; + return 1; +} + +static glsl_t* load_glslp(glsl_t* glsl, int num_shader, const char* f) +{ + int i, j; + glslp_t* p = glslp_parse(f); + + if (p) + { + char path[512]; + char file[1024]; + int failed = 0; + strcpy(path, f); + char* filename = get_filename(path); + + struct glsl_shader* gshader = &glsl->shaders[num_shader]; + + strcpy(gshader->name, p->name); + *filename = 0; + + gshader->num_lut_textures = p->num_textures; + + for (i = 0; i < p->num_textures; ++i) + { + struct texture* texture = &p->textures[i]; + + sprintf(file, "%s%s", path, texture->path); + + struct shader_lut_texture* tex = &gshader->lut_textures[i]; + strcpy(tex->name, texture->name); + + pclog("Load texture %s...\n", file); + + if (!load_texture(file, &tex->texture)) + { + wx_simple_messagebox("GLSL Error", "Could not load texture: %s", file); + pclog("Could not load texture %s!\n", file); + failed = 1; + break; + } + + if (!strcmp(texture->wrap_mode, "repeat")) + tex->texture.wrap_mode = GL_REPEAT; + else if (!strcmp(texture->wrap_mode, "mirrored_repeat")) + tex->texture.wrap_mode = GL_MIRRORED_REPEAT; + else if (!strcmp(texture->wrap_mode, "clamp_to_edge")) + tex->texture.wrap_mode = GL_CLAMP_TO_EDGE; + else + tex->texture.wrap_mode = GL_CLAMP_TO_BORDER; + + tex->texture.mipmap = texture->mipmap; + + tex->texture.min_filter = tex->texture.mag_filter = texture->linear ? GL_LINEAR : GL_NEAREST; + if (tex->texture.mipmap) + tex->texture.min_filter = texture->linear ? GL_LINEAR_MIPMAP_LINEAR : GL_NEAREST_MIPMAP_NEAREST; + + create_texture(&tex->texture); + free(tex->texture.data); + tex->texture.data = 0; + } + + if (!failed) + { + gshader->input_filter_linear = p->input_filter_linear; + + gshader->num_parameters = p->num_parameters; + for (j = 0; j < gshader->num_parameters; ++j) + memcpy(&gshader->parameters[j], &p->parameters[j], sizeof(struct shader_parameter)); + + gshader->num_passes = p->num_shaders; + + for (i = 0; i < p->num_shaders; ++i) + { + struct shader* shader = &p->shaders[i]; + struct shader_pass* pass = &gshader->passes[i]; + + strcpy(pass->alias, shader->alias); + if (!strlen(pass->alias)) + sprintf(pass->alias, "Pass %u", (i+1)); + + pclog("Creating pass %u (%s)\n", (i+1), pass->alias); + pclog("Loading shader %s...\n", shader->shader_fn); + if (!shader->shader_program) + { + wx_simple_messagebox("GLSL Error", "Could not load shader: %s", shader->shader_fn); + pclog("Could not load shader %s\n", shader->shader_fn); + failed = 1; + break; + } + else + pclog("Shader %s loaded\n", shader->shader_fn); + failed = + !compile_shader(GL_VERTEX_SHADER, "#define VERTEX\n#define PARAMETER_UNIFORM\n", shader->shader_program, &pass->program.vertex_shader) || + !compile_shader(GL_FRAGMENT_SHADER, "#define FRAGMENT\n#define PARAMETER_UNIFORM\n", shader->shader_program, &pass->program.fragment_shader); + if (failed) + break; + + if (!create_program(&pass->program)) + { + failed = 1; + break; + } + pass->frame_count_mod = shader->frame_count_mod; + pass->fbo.mipmap_input = shader->mipmap_input; + + glw->glGenVertexArrays(1, (GLuint *)&pass->vertex_array); + find_uniforms(gshader, i); + setup_scale(shader, pass); + if (i == p->num_shaders-1) /* last pass may or may not be an fbo depending on scale */ + { + if (num_shader == glsl->num_shaders-1) + { + pass->fbo.id = -1; + + for (j = 0; j < 2; ++j) + { + if (pass->scale.mode[j] != SCALE_SOURCE || pass->scale.value[j] != 1) + { + setup_fbo(shader, &pass->fbo); + break; + } + } + } + else + { + /* check if next shaders' first pass wants the input mipmapped (will this ever happen?) */ + pass->fbo.texture.mipmap = glsl->shaders[num_shader+1].num_passes > 0 && glsl->shaders[num_shader+1].passes[0].fbo.mipmap_input; + /* check if next shader wants the output of this pass to be filtered */ + if (glsl->shaders[num_shader+1].num_passes > 0 && glsl->shaders[num_shader+1].input_filter_linear >= 0) + shader->filter_linear = glsl->shaders[num_shader+1].input_filter_linear; + setup_fbo(shader, &pass->fbo); + } + } + else + { + /* check if next pass wants the input mipmapped, if so we need to generate mipmaps of this pass */ + pass->fbo.texture.mipmap = (i+1) < p->num_shaders && p->shaders[i+1].mipmap_input; + setup_fbo(shader, &pass->fbo); + } + if (pass->fbo.srgb) glsl->srgb = 1; + pass->active = 1; + } + if (!failed) + { + if (gshader->has_prev) + { + struct shader scene_shader_conf; + memset(&scene_shader_conf, 0, sizeof(struct shader)); + for (i = 0; i < MAX_PREV; ++i) + { + setup_fbo(&scene_shader_conf, &gshader->prev[i].fbo); + } + + } + } + } + + glslp_free(p); + + return glsl; + } + return 0; +} + +static glsl_t* load_shaders(int num, char shaders[MAX_USER_SHADERS][512]) +{ + int i; + glsl_t* glsl; + + glsl = malloc(sizeof(glsl_t)); + memset(glsl, 0, sizeof(glsl_t)); + + glsl->num_shaders = num; + int failed = 0; + for (i = num-1; i >= 0; --i) + { + const char* f = shaders[i]; + if (f && strlen(f)) + { + if (!load_glslp(glsl, i, f)) + { + failed = 1; + break; + } + } + + } + if (failed) + { + delete_glsl(glsl); + memset(glsl, 0, sizeof(glsl_t)); + } + return glsl; +} + +static void read_shader_config() +{ + char s[512]; + int i, j; + for (i = 0; i < active_shader->num_shaders; ++i) + { + struct glsl_shader* shader = &active_shader->shaders[i]; + char* name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); +// shader->shader_refresh_rate = config_get_float(CFG_MACHINE, s, "shader_refresh_rate", -1); + for (j = 0; j < shader->num_parameters; ++j) + { + struct shader_parameter* param = &shader->parameters[j]; + param->value = config_get_float(CFG_MACHINE, s, param->id, param->default_value); + } + } +} + +int gl3_init(SDL_Window* window, sdl_render_driver requested_render_driver, SDL_Rect screen) +{ + int i, j; + + strcpy(current_render_driver_name, requested_render_driver.name); + + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); +#ifdef __APPLE__ + // without an explicit request for the core profile 3.0 macOS falls back to default ancient 2.1 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#endif + + context = SDL_GL_CreateContext(window); + + if (!context) + { + pclog("Could not create GL context.\n"); + return FALSE; + } + + SDL_GL_SetSwapInterval(video_vsync ? 1 : 0); + + pclog("OpenGL information: [%s] %s (%s)\n", glGetString(GL_VENDOR), glGetString(GL_RENDERER), glGetString(GL_VERSION)); + glsl_version[0] = glsl_version[1] = -1; + glGetIntegerv(GL_MAJOR_VERSION, &glsl_version[0]); + glGetIntegerv(GL_MINOR_VERSION, &glsl_version[1]); + if (glsl_version[0] < 3) + { + pclog("OpenGL 3.0 is not available."); + return SDL_FALSE; + } + pclog("Using OpenGL %s\n", glGetString(GL_VERSION)); + pclog("Using Shading Language %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION)); + + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size); + pclog("Max texture size: %dx%d\n", max_texture_size, max_texture_size); + + //SDL_GL_MakeCurrent(window, context); + + glw = glw_init(); + + glEnable(GL_TEXTURE_2D); + + scene_texture.data = NULL; + scene_texture.width = screen.w; + scene_texture.height = screen.h; + scene_texture.internal_format = GL_RGBA8; + scene_texture.format = GL_RGBA; + scene_texture.type = GL_UNSIGNED_INT_8_8_8_8_REV; + scene_texture.wrap_mode = GL_CLAMP_TO_BORDER; + scene_texture.min_filter = scene_texture.mag_filter = video_scale_mode ? GL_LINEAR : GL_NEAREST; + scene_texture.mipmap = 0; + + create_texture(&scene_texture); + + /* load shader */ +// const char* shaders[1]; +// shaders[0] = gl3_shader_file; +// +// active_shader = load_shaders(1, shaders); + +// const char* shaders[3]; +// shaders[0] = "/home/phantasy/git/glsl-shaders/ntsc/ntsc-320px.glslp"; +// shaders[1] = "/home/phantasy/git/glsl-shaders/motionblur/motionblur-simple.glslp"; +// shaders[2] = "/home/phantasy/git/glsl-shaders/crt/crt-lottes-multipass.glslp"; +// +// active_shader = load_shaders(3, shaders); + int num_shaders = 0; + for (i = 0; i < MAX_USER_SHADERS; ++i) + { + if (strlen(gl3_shader_file[i])) + ++num_shaders; + else + break; + } + active_shader = load_shaders(num_shaders, gl3_shader_file); + + create_scene_shader(); + + /* read config */ + read_shader_config(); + + /* buffers */ + + GLfloat vertex[] = { + -1.0f, -1.0f, + -1.0f, 1.0f, + 1.0f, -1.0f, + 1.0f, 1.0f + }; + + GLfloat inv_vertex[] = { + -1.0f, 1.0f, + -1.0f, -1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f + }; + + GLfloat tex_coords[] = { + 0.0f, 0.0f, + 0.0f, 1.0f, + 1.0f, 0.0f, + 1.0f, 1.0f + }; + + + GLfloat colors[] = { + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f, + 1.0f, 1.0f, 1.0f, 1.0f + }; + + + /* set the scene shader buffers */ + { + glw->glBindVertexArray(active_shader->scene.vertex_array); + + struct shader_vbo* vbo = &active_shader->scene.vbo; + + glw->glGenBuffers(1, (GLuint *)&vbo->vertex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(inv_vertex), inv_vertex, GL_STATIC_DRAW); + glw->glVertexAttribPointer(active_shader->scene.uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), (GLvoid*)0); + + glw->glGenBuffers(1, (GLuint *)&vbo->tex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw->glVertexAttribPointer(active_shader->scene.uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2*sizeof(GLfloat), (GLvoid*)0); + } + + /* set buffers for all passes */ + for (j = 0; j < active_shader->num_shaders; ++j) + { + struct glsl_shader* shader = &active_shader->shaders[j]; + for (i = 0; i < shader->num_passes; ++i) + { + struct shader_uniforms* u = &shader->passes[i].uniforms; + + glw->glBindVertexArray(shader->passes[i].vertex_array); + + struct shader_vbo* vbo = &shader->passes[i].vbo; + + glw->glGenBuffers(1, (GLuint *)&vbo->vertex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + + glw->glVertexAttribPointer(u->vertex_coord, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), (GLvoid*)0); + + glw->glGenBuffers(1, (GLuint *)&vbo->tex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw->glVertexAttribPointer(u->tex_coord, 2, GL_FLOAT, GL_TRUE, 2*sizeof(GLfloat), (GLvoid*)0); + + if (u->color) + { + glw->glGenBuffers(1, (GLuint *)&vbo->color); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->color); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); + glw->glVertexAttribPointer(u->color, 4, GL_FLOAT, GL_FALSE, 4*sizeof(GLfloat), (GLvoid*)0); + } + } + } + + for (i = 0; i < active_shader->num_shaders; ++i) + { + struct glsl_shader* shader = &active_shader->shaders[i]; + if (shader->has_prev) + { + struct shader_pass* prev_pass = &shader->prev_scene; + create_default_shader_tex(prev_pass); + + struct shader_vbo* vbo = &prev_pass->vbo; + + glw->glBindVertexArray(prev_pass->vertex_array); + + glw->glGenBuffers(1, (GLuint *)&vbo->vertex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw->glVertexAttribPointer(prev_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), (GLvoid*)0); + + glw->glGenBuffers(1, (GLuint *)&vbo->tex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw->glVertexAttribPointer(prev_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2*sizeof(GLfloat), (GLvoid*)0); + + for (j = 0; j < MAX_PREV; ++j) + { + struct shader_prev* prev = &shader->prev[j]; + struct shader_vbo* prev_vbo = &prev->vbo; + + glw->glGenBuffers(1, (GLuint *)&prev_vbo->vertex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, prev_vbo->vertex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + + glw->glGenBuffers(1, (GLuint *)&prev_vbo->tex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, prev_vbo->tex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + } + } + } + + /* create final pass */ + if (active_shader->num_shaders == 0 || active_shader->shaders[active_shader->num_shaders-1].passes[active_shader->shaders[active_shader->num_shaders-1].num_passes-1].fbo.id >= 0) + { + struct shader_pass* final_pass = &active_shader->final_pass; + create_default_shader_tex(final_pass); + + glw->glBindVertexArray(final_pass->vertex_array); + + struct shader_vbo* vbo = &final_pass->vbo; + + glw->glGenBuffers(1, (GLuint *)&vbo->vertex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw->glVertexAttribPointer(final_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), (GLvoid*)0); + + glw->glGenBuffers(1, (GLuint *)&vbo->tex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glw->glVertexAttribPointer(final_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2*sizeof(GLfloat), (GLvoid*)0); + } + + { + struct shader_pass* color_pass = &active_shader->fs_color; + create_default_shader_color(color_pass); + + glw->glBindVertexArray(color_pass->vertex_array); + + struct shader_vbo* vbo = &color_pass->vbo; + + glw->glGenBuffers(1, (GLuint *)&vbo->vertex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glw->glVertexAttribPointer(color_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), (GLvoid*)0); + + glw->glGenBuffers(1, (GLuint *)&vbo->color); + glw->glBindBuffer(GL_ARRAY_BUFFER, vbo->color); + glw->glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_DYNAMIC_DRAW); + glw->glVertexAttribPointer(color_pass->uniforms.color, 4, GL_FLOAT, GL_TRUE, 4*sizeof(GLfloat), (GLvoid*)0); + + } +#ifdef SDL2_SHADER_DEBUG + struct shader_pass* debug_pass = &active_shader->debug; + create_default_shader(debug_pass); + + glBindVertexArray(debug_pass->vertex_array); + + struct shader_vbo* vbo = &debug_pass->vbo; + + glGenBuffers(1, &vbo->vertex_coord); + glBindBuffer(GL_ARRAY_BUFFER, vbo->vertex_coord); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); + glVertexAttribPointer(debug_pass->uniforms.vertex_coord, 2, GL_FLOAT, GL_FALSE, 2*sizeof(GLfloat), (GLvoid*)0); + + glGenBuffers(1, &vbo->tex_coord); + glBindBuffer(GL_ARRAY_BUFFER, vbo->tex_coord); + glBufferData(GL_ARRAY_BUFFER, sizeof(tex_coords), tex_coords, GL_DYNAMIC_DRAW); + glVertexAttribPointer(debug_pass->uniforms.tex_coord, 2, GL_FLOAT, GL_TRUE, 2*sizeof(GLfloat), (GLvoid*)0); +#endif + + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + glw->glBindVertexArray(0); + + return SDL_TRUE; +} + +void gl3_close() +{ + if (context) + { + delete_texture(&scene_texture); + + if (active_shader) + { + delete_glsl(active_shader); + free(active_shader); + } + active_shader = NULL; + + SDL_GL_DeleteContext(context); + context = NULL; + } + glw_free(glw); +} + +void gl3_update(SDL_Window* window, SDL_Rect updated_rect, BITMAP* screen) +{ + if (!context) + return; + glBindTexture(GL_TEXTURE_2D, scene_texture.id); + glPixelStorei(GL_UNPACK_ROW_LENGTH, screen->w); + glTexSubImage2D(GL_TEXTURE_2D, 0, updated_rect.x, updated_rect.y, updated_rect.w, updated_rect.h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &((uint32_t*) screen->dat)[updated_rect.y * screen->w + updated_rect.x]); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glBindTexture(GL_TEXTURE_2D, 0); +} + +struct render_data { + int pass; + struct glsl_shader* shader; + struct shader_pass* shader_pass; + GLfloat* output_size; + struct shader_pass* orig_pass; + GLint texture; + int frame_count; +}; + +static void render_pass(struct render_data* data) +{ + int i; + GLuint texture_unit = 0; + +// pclog("pass %d: %gx%g, %gx%g -> %gx%g, %gx%g, %gx%g\n", num_pass, pass->state.input_size[0], pass->state.input_size[1], pass->state.input_texture_size[0], pass->state.input_texture_size[1], pass->state.output_size[0], pass->state.output_size[1], pass->state.output_texture_size[0], pass->state.output_texture_size[1], output_size[0], output_size[1]); + + glw->glBindVertexArray(data->shader_pass->vertex_array); + + GLint p = data->shader_pass->program.id; + struct shader_uniforms* u = &data->shader_pass->uniforms; + + glw->glUseProgram(p); + + if (data->texture) + { + glw->glActiveTexture(GL_TEXTURE0 + texture_unit); + glBindTexture(GL_TEXTURE_2D, data->texture); + glw->glUniform1i(u->texture, texture_unit); + texture_unit++; + } + + if (u->color >= 0) glw->glEnableVertexAttribArray(u->color); + + if (u->mvp_matrix >= 0) glw->glUniformMatrix4fv(u->mvp_matrix, 1, 0, matrix); + if (u->frame_direction >= 0) glw->glUniform1i(u->frame_direction, 1); + + int framecnt = data->frame_count; + if (data->shader_pass->frame_count_mod > 0) + framecnt = framecnt%data->shader_pass->frame_count_mod; + if (u->frame_count >= 0) glw->glUniform1i(u->frame_count, framecnt); + + if (u->input_size >= 0) glw->glUniform2fv(u->input_size, 1, data->shader_pass->state.input_size); + if (u->texture_size >= 0) glw->glUniform2fv(u->texture_size, 1, data->shader_pass->state.input_texture_size); + if (u->output_size >= 0) glw->glUniform2fv(u->output_size, 1, data->output_size); + + if (data->shader) + { + /* parameters */ + for (i = 0; i < data->shader->num_parameters; ++i) + if (u->parameters[i] >= 0) glw->glUniform1f(u->parameters[i], data->shader->parameters[i].value); + + if (data->pass > 0) + { + struct shader_pass* passes = data->shader->passes; + struct shader_pass* orig = data->orig_pass; + if (u->orig.texture >= 0) + { + glw->glActiveTexture(GL_TEXTURE0 + texture_unit); + glBindTexture(GL_TEXTURE_2D, orig->fbo.texture.id); + glw->glUniform1i(u->orig.texture, texture_unit); + texture_unit++; + } + if (u->orig.input_size >= 0) glw->glUniform2fv(u->orig.input_size, 1, orig->state.input_size); + if (u->orig.texture_size >= 0) glw->glUniform2fv(u->orig.texture_size, 1, orig->state.input_texture_size); + + for (i = 0; i < data->pass; ++i) + { + if (u->pass[i].texture >= 0) + { + glw->glActiveTexture(GL_TEXTURE0 + texture_unit); + glBindTexture(GL_TEXTURE_2D, passes[i].fbo.texture.id); + glw->glUniform1i(u->pass[i].texture, texture_unit); + texture_unit++; + } + if (u->pass[i].texture_size >= 0) glw->glUniform2fv(u->pass[i].texture_size, 1, passes[i].state.input_texture_size); + if (u->pass[i].input_size >= 0) glw->glUniform2fv(u->pass[i].input_size, 1, passes[i].state.input_size); + + if (u->prev_pass[i].texture >= 0) + { + glw->glActiveTexture(GL_TEXTURE0 + texture_unit); + glBindTexture(GL_TEXTURE_2D, passes[i].fbo.texture.id); + glw->glUniform1i(u->prev_pass[i].texture, texture_unit); + texture_unit++; + } + if (u->prev_pass[i].texture_size >= 0) glw->glUniform2fv(u->prev_pass[i].texture_size, 1, passes[i].state.input_texture_size); + if (u->prev_pass[i].input_size >= 0) glw->glUniform2fv(u->prev_pass[i].input_size, 1, passes[i].state.input_size); + + } + } + + if (data->shader->has_prev) + { + /* loop through each previous frame */ + for (i = 0; i < MAX_PREV; ++i) + { + if (u->prev[i].texture >= 0) + { + glw->glActiveTexture(GL_TEXTURE0 + texture_unit); + glBindTexture(GL_TEXTURE_2D, data->shader->prev[i].fbo.texture.id); + glw->glUniform1i(u->prev[i].texture, texture_unit); + texture_unit++; + } + if (u->prev[i].tex_coord >= 0) + { + glw->glBindBuffer(GL_ARRAY_BUFFER, data->shader->prev[i].vbo.tex_coord); + glw->glVertexAttribPointer(u->prev[i].tex_coord, 2, GL_FLOAT, GL_TRUE, 2*sizeof(GLfloat), (GLvoid*)0); + glw->glEnableVertexAttribArray(u->prev[i].tex_coord); + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + } + } + } + + for (i = 0; i < data->shader->num_lut_textures; ++i) + { + if (u->lut_textures[i] >= 0) + { + glw->glActiveTexture(GL_TEXTURE0 + texture_unit); + glBindTexture(GL_TEXTURE_2D, data->shader->lut_textures[i].texture.id); + glw->glUniform1i(u->lut_textures[i], texture_unit); + texture_unit++; + } + + } + } + + glw->glEnableVertexAttribArray(u->vertex_coord); + glw->glEnableVertexAttribArray(u->tex_coord); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glw->glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + + glw->glDisableVertexAttribArray(data->shader_pass->uniforms.vertex_coord); + glw->glDisableVertexAttribArray(data->shader_pass->uniforms.tex_coord); + if (data->shader_pass->uniforms.color >= 0) glw->glDisableVertexAttribArray(data->shader_pass->uniforms.color); + + if (data->shader && data->shader->has_prev) + { + for (i = 0; i < MAX_PREV; ++i) + { + if (u->prev[i].tex_coord >= 0) + glw->glDisableVertexAttribArray(u->prev[i].tex_coord); + + } + } + + glw->glBindVertexArray(0); + + + glw->glUseProgram(0); +} + +void gl3_present(SDL_Window* window, SDL_Rect video_rect, SDL_Rect window_rect, SDL_Rect screen) +{ + if (!context) + return; + + int s, i, j; + + Uint32 ticks = SDL_GetTicks(); + + GLfloat orig_output_size[] = { + window_rect.w, window_rect.h + }; + + if (active_shader->srgb) glEnable(GL_FRAMEBUFFER_SRGB); + + struct render_data data; + + /* render scene to texture */ + { + struct shader_pass* pass = &active_shader->scene; + + SDL_Rect rect; + rect.x = rect.y = 0; + rect.w = video_rect.w*gl3_input_scale; + rect.h = video_rect.h*gl3_input_scale; + sdl_scale(gl3_input_stretch, rect, &rect, video_rect.w, video_rect.h); + + pass->state.input_size[0] = pass->state.output_size[0] = rect.w; + pass->state.input_size[1] = pass->state.output_size[1] = rect.h; + + pass->state.input_texture_size[0] = pass->state.output_texture_size[0] = next_pow2(pass->state.output_size[0]); + pass->state.input_texture_size[1] = pass->state.output_texture_size[1] = next_pow2(pass->state.output_size[1]); + + recreate_fbo(&active_shader->scene.fbo, pass->state.output_texture_size[0], pass->state.output_texture_size[1]); + + glw->glBindFramebuffer(GL_FRAMEBUFFER, active_shader->scene.fbo.id); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0]/(GLfloat)pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1]/(GLfloat)pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + // create input tex coords + minx = video_rect.x/(float)screen.w; + miny = video_rect.y/(float)screen.h; + maxx = (video_rect.x+video_rect.w)/(float)screen.w; + maxy = (video_rect.y+video_rect.h)/(float)screen.h; + + GLfloat tex_coords[] = { + minx, miny, + minx, maxy, + maxx, miny, + maxx, maxy + }; + + glw->glBindVertexArray(pass->vertex_array); + + glw->glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw->glBufferSubData(GL_ARRAY_BUFFER, 0, 8*sizeof(GLfloat), tex_coords); + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -1; + data.shader_pass = &active_shader->scene; + data.texture = scene_texture.id; + data.output_size = orig_output_size; + render_pass(&data); + + glw->glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + struct shader_pass* orig = &active_shader->scene; + struct shader_pass* input = &active_shader->scene; + + for (s = 0; s < active_shader->num_shaders; ++s) + { + struct glsl_shader* shader = &active_shader->shaders[s]; + +// float refresh_rate = shader->shader_refresh_rate; +// if (refresh_rate < 0) +// refresh_rate = gl3_shader_refresh_rate; + float refresh_rate = gl3_shader_refresh_rate; + if (refresh_rate == 0) + refresh_rate = video_refresh_rate; + int frame_count = ticks/(1000.0f/refresh_rate); + + /* loop through each pass */ + for (i = 0; i < shader->num_passes; ++i) + { + struct shader_pass* pass = &shader->passes[i]; + + memcpy(pass->state.input_size, input->state.output_size, 2*sizeof(GLfloat)); + memcpy(pass->state.input_texture_size, input->state.output_texture_size, 2*sizeof(GLfloat)); + + for (j = 0; j < 2; ++j) + { + if (pass->scale.mode[j] == SCALE_VIEWPORT) + pass->state.output_size[j] = orig_output_size[j]*pass->scale.value[j]; + else if (pass->scale.mode[j] == SCALE_ABSOLUTE) + pass->state.output_size[j] = pass->scale.value[j]; + else + pass->state.output_size[j] = pass->state.input_size[j]*pass->scale.value[j]; + + pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); + } + + if (pass->fbo.id >= 0) + { + recreate_fbo(&pass->fbo, pass->state.output_texture_size[0], pass->state.output_texture_size[1]); + + glw->glBindFramebuffer(GL_FRAMEBUFFER, pass->fbo.id); + glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + } + else + glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0]/(GLfloat)pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1]/(GLfloat)pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + glw->glBindVertexArray(pass->vertex_array); + + glw->glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw->glBufferSubData(GL_ARRAY_BUFFER, 0, 8*sizeof(GLfloat), input->state.tex_coords); + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.shader = shader; + data.pass = i; + data.shader_pass = pass; + data.texture = input->fbo.texture.id; + data.output_size = orig_output_size; + data.orig_pass = orig; + data.frame_count = frame_count; + + render_pass(&data); + + glw->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + if (pass->fbo.texture.mipmap) + { + glw->glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, pass->fbo.texture.id); + glw->glGenerateMipmap(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, 0); + + + } + + input = pass; + } + + if (shader->has_prev && (ticks-shader->last_prev_update) >= (1000.f/refresh_rate)) + { + shader->last_prev_update = ticks; + + /* shift array */ + memmove(&shader->prev[1], &shader->prev[0], MAX_PREV*sizeof(struct shader_prev)); + memcpy(&shader->prev[0], &shader->prev[MAX_PREV], sizeof(struct shader_prev)); + + struct shader_pass* pass = orig; + struct shader_pass* prev_pass = &shader->prev_scene; + struct shader_prev* prev = &shader->prev[0]; + + memcpy(&prev_pass->state, &pass->state, sizeof(struct shader_state)); + + recreate_fbo(&prev->fbo, prev_pass->state.output_texture_size[0], prev_pass->state.output_texture_size[1]); + + memcpy(&prev_pass->fbo, &prev->fbo, sizeof(struct shader_fbo)); + + glw->glBindFramebuffer(GL_FRAMEBUFFER, prev->fbo.id); + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glViewport(0, 0, pass->state.output_size[0], pass->state.output_size[1]); + + glw->glBindVertexArray(prev_pass->vertex_array); + + glw->glBindBuffer(GL_ARRAY_BUFFER, prev->vbo.tex_coord); + glw->glBufferSubData(GL_ARRAY_BUFFER, 0, 8*sizeof(GLfloat), pass->state.tex_coords); + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + + glw->glBindBuffer(GL_ARRAY_BUFFER, prev_pass->vbo.tex_coord); + glw->glBufferSubData(GL_ARRAY_BUFFER, 0, 8*sizeof(GLfloat), pass->state.tex_coords); + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.shader = shader; + data.pass = -10; + data.shader_pass = prev_pass; + data.texture = pass->fbo.texture.id; + data.output_size = orig_output_size; + + render_pass(&data); + + glw->glBindFramebuffer(GL_FRAMEBUFFER, 0); + } + + orig = input; + } + + if (active_shader->final_pass.active) + { + struct shader_pass* pass = &active_shader->final_pass; + + memcpy(pass->state.input_size, input->state.output_size, 2*sizeof(GLfloat)); + memcpy(pass->state.input_texture_size, input->state.output_texture_size, 2*sizeof(GLfloat)); + + for (j = 0; j < 2; ++j) + { + if (pass->scale.mode[j] == SCALE_VIEWPORT) + pass->state.output_size[j] = orig_output_size[j]*pass->scale.value[j]; + else if (pass->scale.mode[j] == SCALE_ABSOLUTE) + pass->state.output_size[j] = pass->scale.value[j]; + else + pass->state.output_size[j] = pass->state.input_size[j]*pass->scale.value[j]; + + pass->state.output_texture_size[j] = next_pow2(pass->state.output_size[j]); + } + + glViewport(window_rect.x, window_rect.y, window_rect.w, window_rect.h); + + glClearColor(0, 0, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + + GLfloat minx = 0; + GLfloat miny = 0; + GLfloat maxx = pass->state.output_size[0]/(GLfloat)pass->state.output_texture_size[0]; + GLfloat maxy = pass->state.output_size[1]/(GLfloat)pass->state.output_texture_size[1]; + + pass->state.tex_coords[0] = minx; + pass->state.tex_coords[1] = miny; + pass->state.tex_coords[2] = minx; + pass->state.tex_coords[3] = maxy; + pass->state.tex_coords[4] = maxx; + pass->state.tex_coords[5] = miny; + pass->state.tex_coords[6] = maxx; + pass->state.tex_coords[7] = maxy; + + glw->glBindVertexArray(pass->vertex_array); + + glw->glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.tex_coord); + glw->glBufferSubData(GL_ARRAY_BUFFER, 0, 8*sizeof(GLfloat), input->state.tex_coords); + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -2; + data.shader_pass = pass; + data.texture = input->fbo.texture.id; + data.output_size = orig_output_size; + data.orig_pass = orig; + + render_pass(&data); + } + + if (!take_screenshot) + { + if (video_focus_dim && !(SDL_GetWindowFlags(window)&SDL_WINDOW_INPUT_FOCUS)) + { + struct shader_pass* pass = &active_shader->fs_color; + GLfloat r = 0; + GLfloat g = 0; + GLfloat b = 0; + GLfloat a = 0x80/(float)0xff; + + GLfloat colors[] = { + r, g, b, a, + r, g, b, a, + r, g, b, a, + r, g, b, a + }; + + glw->glBindVertexArray(pass->vertex_array); + + glw->glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); + glw->glBufferSubData(GL_ARRAY_BUFFER, 0, 16*sizeof(GLfloat), colors); + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -3; + data.shader_pass = pass; + data.texture = 0; + data.output_size = orig_output_size; + data.orig_pass = orig; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + render_pass(&data); + glDisable(GL_BLEND); + } + if (flash.enabled) + { + struct shader_pass* pass = &active_shader->fs_color; + GLfloat r = (flash.color[0]&0xff)/(float)0xff; + GLfloat g = (flash.color[1]&0xff)/(float)0xff; + GLfloat b = (flash.color[2]&0xff)/(float)0xff; + GLfloat a = (flash.color[3]&0xff)/(float)0xff; + + GLfloat colors[] = { + r, g, b, a, + r, g, b, a, + r, g, b, a, + r, g, b, a + }; + + glw->glBindVertexArray(pass->vertex_array); + + glw->glBindBuffer(GL_ARRAY_BUFFER, pass->vbo.color); + glw->glBufferSubData(GL_ARRAY_BUFFER, 0, 16*sizeof(GLfloat), colors); + glw->glBindBuffer(GL_ARRAY_BUFFER, 0); + + memset(&data, 0, sizeof(struct render_data)); + data.pass = -3; + data.shader_pass = pass; + data.texture = 0; + data.output_size = orig_output_size; + data.orig_pass = orig; + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable(GL_BLEND); + render_pass(&data); + glDisable(GL_BLEND); + } + } + else + { + take_screenshot = 0; + + int width = window_rect.w; + int height = window_rect.h; + + SDL_GetWindowSize(window, &width, &height); + + unsigned char* rgba = (unsigned char*)malloc(width*height*4); + + glFinish(); + glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, rgba); + + int x, y; + unsigned char* rgb = (unsigned char*)malloc(width*height*3); + + for (x = 0; x < width; ++x) + { + for (y = 0; y < height; ++y) + { + rgb[(y*width+x)*3+0] = rgba[((height-y-1)*width+x)*4+0]; + rgb[(y*width+x)*3+1] = rgba[((height-y-1)*width+x)*4+1]; + rgb[(y*width+x)*3+2] = rgba[((height-y-1)*width+x)*4+2]; + } + } + + screenshot_taken(rgb, width, height); + + free(rgb); + free(rgba); + } + + // DEBUG: render FBO +#ifdef SDL2_SHADER_DEBUG +// GLint texture = scene_texture.id; + GLint texture = active_shader->lut_textures[0].texture.id; +// GLint texture = active_shader->scene.fbo.texture; + + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + + glViewport(0, 0, orig_output_size[0], orig_output_size[1]); + + struct shader_pass* pass = &active_shader->debug; + + render_pass(-999, pass, orig_output_size, texture); +#endif + + glDisable(GL_FRAMEBUFFER_SRGB); + + SDL_GL_SwapWindow(window); + +} + +sdl_renderer_t* gl3_renderer_create() +{ + sdl_renderer_t* renderer = malloc(sizeof(sdl_renderer_t)); + renderer->init = gl3_init; + renderer->close = gl3_close; + renderer->update = gl3_update; + renderer->present = gl3_present; + renderer->always_update = 1; + return renderer; +} + +void gl3_renderer_close(sdl_renderer_t* renderer) +{ + free(renderer); +} + +static int available = -1; + +int gl3_renderer_available(struct sdl_render_driver* driver) +{ + if (available < 0) + { + available = 0; + + // GL SetAttribute should be done *before* window creation for the attributes to apply on + // context creation (seems to depend on OpenGL impl. but it souldn't hurt other platforms + // to do it here (earlier than before) + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); + +#ifdef __APPLE__ + // without an explicit request for the core profile 3.0 macOS falls back to default ancient 2.1 + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); +#endif + + SDL_Window* window = SDL_CreateWindow("GL3 test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1, 1, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + if (window) + { + SDL_GLContext context = SDL_GL_CreateContext(window); + if (context) + { + int version = -1; + glGetIntegerv(GL_MAJOR_VERSION, &version); + + SDL_GL_DeleteContext(context); + + available = version >= 3; + } + SDL_DestroyWindow(window); + } + + } + return available; +} diff --git a/src/wx-sdl2-video-gl3.h b/src/wx-sdl2-video-gl3.h new file mode 100644 index 0000000..c4b1411 --- /dev/null +++ b/src/wx-sdl2-video-gl3.h @@ -0,0 +1,3 @@ +sdl_renderer_t* gl3_renderer_create(); +void gl3_renderer_close(sdl_renderer_t* renderer); +int gl3_renderer_available(struct sdl_render_driver* driver); diff --git a/src/wx-sdl2-video-renderer.c b/src/wx-sdl2-video-renderer.c new file mode 100644 index 0000000..c06d64c --- /dev/null +++ b/src/wx-sdl2-video-renderer.c @@ -0,0 +1,180 @@ +#include +#include +#include +#include +#include "video.h" +#include "wx-utils.h" +#include "wx-sdl2-video.h" +#include "wx-sdl2-video-renderer.h" + +static SDL_Texture* texture = NULL; +static SDL_Renderer* renderer = NULL; + +extern int video_scale_mode; +extern int video_vsync; +extern int video_focus_dim; +extern int take_screenshot; +extern void screenshot_taken(unsigned char* rgb, int width, int height); + +int sdl_video_renderer_init(SDL_Window* window, sdl_render_driver requested_render_driver, SDL_Rect screen) +{ + SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, video_scale_mode ? "1" : "0"); + const char* driver = requested_render_driver.sdl_id; + if (!driver) driver = "0"; + SDL_SetHint(SDL_HINT_RENDER_DRIVER, driver); + + int flags = SDL_RENDERER_ACCELERATED; + if (video_vsync) { + flags |= SDL_RENDERER_PRESENTVSYNC; + } + renderer = SDL_CreateRenderer(window, -1, flags); + + if (!renderer) + { + char message[200]; + sprintf(message, + "SDL window could not be created! Error: %s\n", + SDL_GetError()); + wx_messagebox(0, message, "SDL Error", WX_MB_OK); + return SDL_FALSE; + } + + SDL_RendererInfo rendererInfo; + SDL_GetRendererInfo(renderer, &rendererInfo); + sdl_render_driver* d = sdl_get_render_driver_by_name_ptr(rendererInfo.name); + if (!d) + strcpy(current_render_driver_name, "Unknown"); + else + strcpy(current_render_driver_name, d->name); + + texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + screen.w, screen.h); + + return SDL_TRUE; + +} + +void sdl_video_renderer_close() +{ + if (texture) + { + SDL_DestroyTexture(texture); + texture = NULL; + } + if (renderer) + { + SDL_DestroyRenderer(renderer); + renderer = NULL; + } +} + +void sdl_video_renderer_update(SDL_Window* window, SDL_Rect updated_rect, BITMAP* screen) +{ + SDL_UpdateTexture(texture, &updated_rect, &((uint32_t*) screen->dat)[updated_rect.y * screen->w + updated_rect.x], screen->w * 4); +} + +void sdl_video_renderer_present(SDL_Window* window, SDL_Rect texture_rect, SDL_Rect window_rect, SDL_Rect screen) +{ + SDL_RenderClear(renderer); + SDL_RenderCopy(renderer, texture, &texture_rect, &window_rect); + int sshot = take_screenshot; + if (!sshot) + { + if (video_focus_dim && !(SDL_GetWindowFlags(window)&SDL_WINDOW_INPUT_FOCUS)) { + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0x80); + SDL_RenderFillRect(renderer, NULL); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); + } + if (flash.enabled) + { + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND); + SDL_SetRenderDrawColor(renderer, flash.color[0], flash.color[1], flash.color[2], flash.color[3]); + SDL_RenderFillRect(renderer, NULL); + SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff); + SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); + } + } + SDL_RenderPresent(renderer); + + if (sshot) + { + take_screenshot = 0; + + int width = window_rect.w; + int height = window_rect.h; + + SDL_GetWindowSize(window, &width, &height); + + /* seems to work without rendering to texture first */ +// SDL_Texture* tex = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_TARGET, width, height); +// +// SDL_SetRenderTarget(renderer, tex); +// SDL_RenderClear(renderer); +// SDL_RenderCopy(renderer, texture, &texture_rect, &window_rect); +// SDL_RenderPresent(renderer); + + unsigned char* rgba = (unsigned char*)malloc(width*height*4); + int res = SDL_RenderReadPixels(renderer, NULL, SDL_PIXELFORMAT_ABGR8888, rgba, width*4); + +// SDL_SetRenderTarget(renderer, NULL); +// SDL_DestroyTexture(tex); + + if (!res) + { + int x, y; + unsigned char* rgb = (unsigned char*)malloc(width*height*3); + + for (x = 0; x < width; ++x) + { + for (y = 0; y < height; ++y) + { + rgb[(y*width+x)*3+0] = rgba[(y*width+x)*4+0]; + rgb[(y*width+x)*3+1] = rgba[(y*width+x)*4+1]; + rgb[(y*width+x)*3+2] = rgba[(y*width+x)*4+2]; + } + } + + screenshot_taken(rgb, width, height); + + free(rgb); + } + else + screenshot_taken(0, 0, 0); + + free(rgba); + } + +} + +sdl_renderer_t* sdl2_renderer_create() +{ + sdl_renderer_t* renderer = malloc(sizeof(sdl_renderer_t)); + renderer->init = sdl_video_renderer_init; + renderer->close = sdl_video_renderer_close; + renderer->update = sdl_video_renderer_update; + renderer->present = sdl_video_renderer_present; + renderer->always_update = 0; + return renderer; +} + +void sdl2_renderer_close(sdl_renderer_t* renderer) +{ + free(renderer); +} + +int sdl2_renderer_available(struct sdl_render_driver* driver) +{ + int i; + SDL_RendererInfo renderInfo; + for (i = 0; i < SDL_GetNumRenderDrivers(); ++i) + { + SDL_GetRenderDriverInfo(i, &renderInfo); + if (!strcmp(driver->sdl_id, renderInfo.name)) + return 1; + } + return 0; + +} diff --git a/src/wx-sdl2-video-renderer.h b/src/wx-sdl2-video-renderer.h new file mode 100644 index 0000000..08f7488 --- /dev/null +++ b/src/wx-sdl2-video-renderer.h @@ -0,0 +1,3 @@ +sdl_renderer_t* sdl2_renderer_create(); +void sdl2_renderer_close(sdl_renderer_t* renderer); +int sdl2_renderer_available(struct sdl_render_driver* driver); diff --git a/src/wx-sdl2-video.c b/src/wx-sdl2-video.c new file mode 100644 index 0000000..f6551b0 --- /dev/null +++ b/src/wx-sdl2-video.c @@ -0,0 +1,332 @@ +#include +#include +#include +#include +#include +#include "wx-sdl2.h" +#include "video.h" +#include "wx-sdl2-video.h" + +#include "wx-sdl2-video-gl3.h" +#include "wx-sdl2-video-renderer.h" + +void video_blit_complete(); + +BITMAP *screen; +static BITMAP *screen_copy = NULL; +static SDL_Rect screen_rect; +static SDL_Rect updated_rect; +static SDL_Rect updated_rect_copy; +static SDL_Rect blit_rect; +static SDL_Rect texture_rect; +static int updated = 0; + +static SDL_mutex* blitMutex = NULL; + +static void sdl_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); + +int video_scale_mode = 1; +int video_vsync = 0; +int video_focus_dim = 0; +int video_fullscreen_mode = 0; +int video_alternative_update_lock = 0; + +static sdl_render_driver sdl_render_drivers[] = { + { RENDERER_AUTO, "auto", "Auto", 0, sdl2_renderer_create, sdl2_renderer_close, sdl2_renderer_available }, + { RENDERER_DIRECT3D, "direct3d", "Direct3D", 0, sdl2_renderer_create, sdl2_renderer_close, sdl2_renderer_available }, + { RENDERER_OPENGL, "opengl", "OpenGL", 0, sdl2_renderer_create, sdl2_renderer_close, sdl2_renderer_available }, + { RENDERER_OPENGLES2, "opengles2", "OpenGL ES 2", 0, sdl2_renderer_create, sdl2_renderer_close, sdl2_renderer_available }, + { RENDERER_OPENGLES, "opengles", "OpenGL ES", 0, sdl2_renderer_create, sdl2_renderer_close, sdl2_renderer_available }, + { RENDERER_SOFTWARE, "software", "Software", 0, sdl2_renderer_create, sdl2_renderer_close, sdl2_renderer_available }, + { RENDERER_GL3, "gl3", "OpenGL 3.0", SDL_WINDOW_OPENGL, gl3_renderer_create, gl3_renderer_close, gl3_renderer_available } +}; + +sdl_render_driver requested_render_driver; + +char current_render_driver_name[50]; +static sdl_renderer_t* renderer = NULL; + +void hline(BITMAP *b, int x1, int y, int x2, int col) +{ + if (y < 0 || y >= buffer32->h) + return; + + for (; x1 < x2; x1++) + ((uint32_t *)b->line[y])[x1] = col; +} + +void destroy_bitmap(BITMAP *b) +{ + free(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; +} + +sdl_render_driver* sdl_get_render_drivers(int* num) +{ + if (num) + *num = SDL_arraysize(sdl_render_drivers); + return sdl_render_drivers; +} + +sdl_render_driver sdl_get_render_driver_by_name(const char* name, int def) +{ + int i; + for (i = 0; i < SDL_arraysize(sdl_render_drivers); ++i) + { + if (!strcmp(sdl_render_drivers[i].sdl_id, name)) + { + return sdl_render_drivers[i]; + } + } + return sdl_render_drivers[def]; +} + +sdl_render_driver* sdl_get_render_driver_by_name_ptr(const char* name) +{ + int i; + for (i = 0; i < SDL_arraysize(sdl_render_drivers); ++i) + { + if (!strcmp(sdl_render_drivers[i].sdl_id, name)) + { + return &sdl_render_drivers[i]; + } + } + return 0; +} + +sdl_render_driver sdl_get_render_driver_by_id(int id, int def) +{ + int i; + for (i = 0; i < SDL_arraysize(sdl_render_drivers); ++i) + { + if (sdl_render_drivers[i].id == id) + { + return sdl_render_drivers[i]; + } + } + return sdl_render_drivers[def]; +} + + +void sdl_scale(int scale, SDL_Rect src, SDL_Rect* dst, int w, int h) +{ + double t, b, l, r; + int ratio_w, ratio_h; + switch (scale) + { + case FULLSCR_SCALE_43: + t = 0; + b = src.h; + l = (src.w / 2) - ((src.h * 4) / (3 * 2)); + r = (src.w / 2) + ((src.h * 4) / (3 * 2)); + if (l < 0) + { + l = 0; + r = src.w; + t = (src.h / 2) + - ((src.w * 3) / (4 * 2)); + b = (src.h / 2) + + ((src.w * 3) / (4 * 2)); + } + break; + case FULLSCR_SCALE_SQ: + t = 0; + b = src.h; + l = (src.w / 2) - ((src.h * w) / (h * 2)); + r = (src.w / 2) + ((src.h * w) / (h * 2)); + if (l < 0) + { + l = 0; + r = src.w; + t = (src.h / 2) + - ((src.w * h) / (w * 2)); + b = (src.h / 2) + + ((src.w * h) / (w * 2)); + } + break; + case FULLSCR_SCALE_INT: + ratio_w = src.w / w; + ratio_h = src.h / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + l = (src.w / 2) - ((w * ratio_w) / 2); + r = (src.w / 2) + ((w * ratio_w) / 2); + t = (src.h / 2) - ((h * ratio_w) / 2); + b = (src.h / 2) + ((h * ratio_w) / 2); + break; + case FULLSCR_SCALE_FULL: + default: + l = 0; + t = 0; + r = src.w; + b = src.h; + break; + } + + dst->x = l; + dst->y = t; + dst->w = r - l; + dst->h = b - t; +} + +static void set_updated_size(int x, int y, int w, int h) +{ + if (updated) + { + updated_rect.x = x < updated_rect.x ? x : updated_rect.x; + updated_rect.y = y < updated_rect.y ? y : updated_rect.y; + updated_rect.w = w > updated_rect.w ? w : updated_rect.w; + updated_rect.h = h > updated_rect.h ? h : updated_rect.h; + } + else + { + updated_rect.x = x; + updated_rect.y = y; + updated_rect.w = w; + updated_rect.h = h; + updated = 1; + } +} + +static void sdl_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + if (y1 == y2) + { + video_blit_complete(); + return; /*Nothing to do*/ + } + + int yy; + SDL_LockMutex(blitMutex); + for (yy = y1; yy < y2; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer32->h) + memcpy(screen->dat + (yy * screen->w * 4), + &(((uint32_t *) buffer32->line[y + yy])[x]), w * 4); + } + set_updated_size(0, y1, w, y2 - y1); +// set_updated_size(0, 0, w, h); + blit_rect.w = w; + blit_rect.h = h; + SDL_UnlockMutex(blitMutex); + video_blit_complete(); +} + +int sdl_is_fullscreen(SDL_Window* window) { + int flags = SDL_GetWindowFlags(window); + return (flags&SDL_WINDOW_FULLSCREEN) || (flags&SDL_WINDOW_FULLSCREEN_DESKTOP); +} + +int sdl_video_init() +{ + blitMutex = SDL_CreateMutex(); + updated = 0; + + video_blit_memtoscreen_func = sdl_blit_memtoscreen; + requested_render_driver = sdl_get_render_driver_by_id(RENDERER_AUTO, RENDERER_AUTO); + + screen_rect.w = screen_rect.h = 2048; + + screen = create_bitmap(screen_rect.w, screen_rect.h); + + return SDL_TRUE; +} + +void sdl_video_close() +{ + requested_render_driver.renderer_close(renderer); + renderer = NULL; + destroy_bitmap(screen); + screen = NULL; + SDL_DestroyMutex(blitMutex); +} + +int sdl_renderer_init(SDL_Window* window) +{ + if (video_alternative_update_lock) + screen_copy = create_bitmap(screen_rect.w, screen_rect.h); + else + screen_copy = NULL; + + renderer = requested_render_driver.renderer_create(); + return renderer->init(window, requested_render_driver, screen_rect); +} + +void sdl_renderer_close() +{ + if (renderer) + renderer->close(); + renderer = NULL; + + if (screen_copy) + destroy_bitmap(screen_copy); + screen_copy = NULL; +} + +int sdl_renderer_update(SDL_Window* window) +{ + int render = 0; + SDL_LockMutex(blitMutex); + if (updated) + { + updated = 0; + if (screen_copy) + { + memcpy(&updated_rect_copy, &updated_rect, sizeof(updated_rect)); + memcpy(screen_copy->dat + (updated_rect.y * screen_copy->w * 4), screen->dat + (updated_rect.y * screen->w * 4), updated_rect.h * screen->w * 4); + } + else + renderer->update(window, updated_rect, screen); + texture_rect.w = blit_rect.w; + texture_rect.h = blit_rect.h; + render = 1; + } + SDL_UnlockMutex(blitMutex); + if (screen_copy && render) + renderer->update(window, updated_rect_copy, screen_copy); + return render || renderer->always_update; +} + +void sdl_renderer_present(SDL_Window* window) +{ + if (flash.enabled) + { + int elapsed = SDL_GetTicks() - flash.start; + float a = flash.func(elapsed / (float)flash.time) * (flash.alpha&0xff); + flash.color[3] = (char)a; + if (elapsed >= flash.time) + flash.enabled = 0; + } + + SDL_Rect wr; + SDL_GetWindowSize(window, &wr.w, &wr.h); + sdl_scale(video_fullscreen_scale, wr, &wr, texture_rect.w, texture_rect.h); + renderer->present(window, texture_rect, wr, screen_rect); + +} + +void color_flash(FLASH_FUNC func, int time_ms, char r, char g, char b, char a) +{ + flash.func = func; + flash.color[0] = r; + flash.color[1] = g; + flash.color[2] = b; + flash.color[3] = 0; + flash.alpha = a; + flash.start = SDL_GetTicks(); + flash.time = time_ms; + flash.enabled = 1; +} diff --git a/src/wx-sdl2-video.h b/src/wx-sdl2-video.h new file mode 100644 index 0000000..a32d97d --- /dev/null +++ b/src/wx-sdl2-video.h @@ -0,0 +1,69 @@ +#define RENDERER_AUTO 0 +#define RENDERER_DIRECT3D 1 +#define RENDERER_OPENGL 2 +#define RENDERER_OPENGLES2 3 +#define RENDERER_OPENGLES 4 +#define RENDERER_SOFTWARE 5 +#define RENDERER_GL3 6 + +struct sdl_render_driver; + +typedef struct sdl_renderer_t { + int (*init)(SDL_Window* window, struct sdl_render_driver driver, SDL_Rect screen); + void (*close)(); + void (*update)(SDL_Window* window, SDL_Rect updated_rect, BITMAP* screen); + void (*present)(SDL_Window* window, SDL_Rect texture_rect, SDL_Rect window_rect, SDL_Rect screen); + int always_update; +} sdl_renderer_t; + +typedef struct sdl_render_driver { + int id; + const char* sdl_id; + const char* name; + int sdl_window_params; + sdl_renderer_t* (*renderer_create)(); + void (*renderer_close)(sdl_renderer_t* renderer); + int (*renderer_available)(struct sdl_render_driver* driver); +} sdl_render_driver; + +typedef float (*FLASH_FUNC)(float v); + +typedef struct flash_t { + int enabled; + int time; + char color[4]; + int start; + char alpha; + FLASH_FUNC func; +} flash_t; + +flash_t flash; + +#ifdef __cplusplus +extern "C" { +#endif +int sdl_video_init(); +void sdl_video_close(); +int sdl_renderer_init(SDL_Window* window); +void sdl_renderer_close(); +int sdl_renderer_update(SDL_Window* window); +void sdl_renderer_present(SDL_Window* window); +void sdl_scale(int scale, SDL_Rect src, SDL_Rect* dst, int w, int h); +int sdl_is_fullscreen(SDL_Window* window); + +sdl_render_driver* sdl_get_render_drivers(int* num_renderers); +sdl_render_driver sdl_get_render_driver_by_id(int id, int def); +sdl_render_driver sdl_get_render_driver_by_name(const char* name, int def); +sdl_render_driver* sdl_get_render_driver_by_name_ptr(const char* name); + +void color_flash(FLASH_FUNC func, int time_ms, char r, char g, char b, char a); + +#ifdef __cplusplus +} +#endif + +extern sdl_render_driver requested_render_driver; +extern char current_render_driver_name[50]; + +extern int custom_resolution_width; +extern int custom_resolution_height; diff --git a/src/wx-sdl2.c b/src/wx-sdl2.c new file mode 100644 index 0000000..984d731 --- /dev/null +++ b/src/wx-sdl2.c @@ -0,0 +1,1200 @@ +#include "wx-sdl2.h" + +#include +#include + +#ifdef __WINDOWS__ +#define BITMAP WINDOWS_BITMAP +#undef UNICODE +#include +#include +#undef BITMAP +#endif + + +#include +#include +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "cassette.h" +#include "cdrom-ioctl.h" +#include "cdrom-image.h" +#include "config.h" +#include "video.h" +#include "cpu.h" +#include "ide.h" +#include "model.h" +#include "mouse.h" +#include "nvr.h" +#include "plat-joystick.h" +#include "plat-midi.h" +#include "scsi_zip.h" +#include "sound.h" +#include "thread.h" +#include "disc.h" +#include "disc_img.h" +#include "mem.h" +#include "paths.h" + +#include "wx-sdl2-video.h" +#include "wx-utils.h" +#include "wx-common.h" +#include "wx-display.h" + +#if __APPLE__ +#define pause __pause +#include +#include +#include +#undef pause +#include +#include +#endif + +extern void creatediscimage_open(void *hwnd); + +#define ID_IS(s) wParam == wx_xrcid(s) +#define ID_RANGE(a, b) wParam >= wx_xrcid(a) && wParam <= wx_xrcid(b) + +#define IDM_CDROM_REAL 1500 + +#define MIN_SND_BUF 50 + +uint64_t timer_freq; + + +int gfx_present[GFX_MAX]; + +SDL_mutex* ghMutex; +SDL_mutex* mainMutex; +SDL_cond* mainCond; + +SDL_Thread* mainthreadh = NULL; + +SDL_TimerID onesectimer; + +int running = 0; + +int drawits = 0; + +int romspresent[ROM_MAX]; +int quited = 0; + +SDL_Rect oldclip; + +void* ghwnd = 0; + +void* menu; + +emulation_state_t emulation_state = EMULATION_STOPPED; +int pause = 0; + +int window_doreset = 0; +int window_dosetresize = 0; +int renderer_doreset = 0; +int window_dofullscreen = 0; +int window_dowindowed = 0; +int window_doremember = 0; +int window_doinputgrab = 0; +int window_doinputrelease = 0; +int window_dotogglefullscreen = 0; + +int video_scale = 1; + +int video_width = 640; +int video_height = 480; + +char menuitem[60]; + +extern int config_selection_open(void* hwnd, int inited); +extern int shader_manager_open(void* hwnd); + +extern void sdl_set_window_title(const char* title); + +extern float gl3_shader_refresh_rate; +extern float gl3_input_scale; +extern int gl3_input_stretch; +extern char gl3_shader_file[20][512]; + +char screenshot_format[10]; +int screenshot_flash = 1; +int take_screenshot = 0; + +void warning(const char *format, ...) +{ + char buf[1024]; + va_list ap; + + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + + wx_messagebox(ghwnd, buf, "PCem", WX_MB_OK); +} + +void updatewindowsize(int x, int y) +{ + video_width = x; + video_height = y; + + display_resize(x, y); +} + +unsigned int get_ticks() +{ + return SDL_GetTicks(); +} + +void delay_ms(unsigned int ms) +{ + SDL_Delay(ms); +} + +void startblit() +{ + SDL_LockMutex(ghMutex); +} + +void endblit() +{ + SDL_UnlockMutex(ghMutex); +} + +void enter_fullscreen() +{ + window_dofullscreen = window_doinputgrab = 1; +} + +void leave_fullscreen() +{ + window_dowindowed = window_doinputrelease = 1; +} + +void toggle_fullscreen() +{ + window_dotogglefullscreen = 1; +} + +uint64_t main_time; + +int mainthread(void* param) +{ + SDL_SetThreadPriority(SDL_THREAD_PRIORITY_HIGH); + + int frames = 0; + uint32_t old_time, new_time; + + drawits = 0; + old_time = SDL_GetTicks(); + running = 1; + while (running) + { + new_time = SDL_GetTicks(); + 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 + SDL_Delay(1); + } + + SDL_LockMutex(mainMutex); + SDL_CondSignal(mainCond); + SDL_UnlockMutex(mainMutex); + + return TRUE; +} + +void stop_emulation_now(void) +{ + /*Deduct a sufficiently large number of cycles that no instructions will + run before the main thread is terminated*/ + cycles -= 99999999; + wx_stop_emulation_now(ghwnd); +} + +int dir_exists(char* path) +{ + return wx_dir_exists(path); +} + +void get_pcem_path(char *s, int size) +{ +#ifdef __linux + wx_get_home_directory(s); + strcat(s, ".pcem/"); +#elif defined(__APPLE__) + /*TODO: Use CoreFoundation functions to get proper directory, in case + the Application Support directory is different (I.E., with signing)*/ + wx_get_home_directory(s); + strcat(s, "Library/Application Support/PCem/"); + + struct stat st = {0}; + + // create ~/Library/Application Support/PCem/ + // if it doesn't exist + if (stat(s, &st) == -1) + { + mkdir(s, 0700); + } +#else + char* path = SDL_GetBasePath(); + strcpy(s, path); +#endif +} + +void get_pcem_base_path(char *s, int size) +{ + char* path = SDL_GetBasePath(); + strcpy(s, path); +} + +void set_window_title(const char *s) +{ + sdl_set_window_title(s); +} + +float flash_func(float x) +{ + return 1 - pow(x, 4); +} + +float flash_failed_func(float x) +{ + return fabs(sin(x*3.1415926*2)); +} + +void screenshot_taken(unsigned char* rgb, int width, int height) +{ + char name[512]; + char date[128]; + strcpy(name, "Screenshot from "); + wx_date_format(date, "%Y-%m-%d %H-%M-%S"); + strcat(name, date); + if (wx_image_save(screenshots_path, name, screenshot_format, rgb, width, height, 0)) + { + pclog("Screenshot saved\n"); + if (screenshot_flash) + color_flash(flash_func, 500, 0xff, 0xff, 0xff, 0xff); + } + else + { + pclog("Screenshot was not saved\n"); + if (screenshot_flash) + color_flash(flash_failed_func, 500, 0xff, 0, 0, 0xff); + } +} + +uint64_t timer_read() +{ + return SDL_GetPerformanceCounter(); +} + +Uint32 timer_onesec(Uint32 interval, void* param) +{ + onesec(); + return interval; +} + +void sdl_loadconfig() +{ + vid_resize = config_get_int(CFG_MACHINE, NULL, "vid_resize", 0); + video_fullscreen_scale = config_get_int(CFG_MACHINE, NULL, "video_fullscreen_scale", 0); + video_fullscreen_first = config_get_int(CFG_MACHINE, NULL, "video_fullscreen_first", 1); + + strcpy(screenshot_format, config_get_string(CFG_MACHINE, "SDL2", "screenshot_format", IMAGE_PNG)); + screenshot_flash = config_get_int(CFG_MACHINE, "SDL2", "screenshot_flash", 1); + + custom_resolution_width = config_get_int(CFG_MACHINE, "SDL2", "custom_width", custom_resolution_width); + custom_resolution_height = config_get_int(CFG_MACHINE, "SDL2", "custom_height", custom_resolution_height); + + video_fullscreen = config_get_int(CFG_MACHINE, "SDL2", "fullscreen", video_fullscreen); + video_fullscreen_mode = config_get_int(CFG_MACHINE, "SDL2", "fullscreen_mode", video_fullscreen_mode); + video_scale = config_get_int(CFG_MACHINE, "SDL2", "scale", video_scale); + video_scale_mode = config_get_int(CFG_MACHINE, "SDL2", "scale_mode", video_scale_mode); + video_vsync = config_get_int(CFG_MACHINE, "SDL2", "vsync", video_vsync); + video_focus_dim = config_get_int(CFG_MACHINE, "SDL2", "focus_dim", video_focus_dim); + video_alternative_update_lock = config_get_int(CFG_MACHINE, "SDL2", "alternative_update_lock", video_alternative_update_lock); + requested_render_driver = sdl_get_render_driver_by_name(config_get_string(CFG_MACHINE, "SDL2", "render_driver", ""), RENDERER_SOFTWARE); + + gl3_input_scale = config_get_float(CFG_MACHINE, "GL3", "input_scale", gl3_input_scale); + gl3_input_stretch = config_get_int(CFG_MACHINE, "GL3", "input_stretch", gl3_input_stretch); + gl3_shader_refresh_rate = config_get_float(CFG_MACHINE, "GL3", "shader_refresh_rate", gl3_shader_refresh_rate); + + memset(&gl3_shader_file, 0, sizeof(gl3_shader_file)); + int num_shaders = config_get_int(CFG_MACHINE, "GL3 Shaders", "shaders", 0); + char s[20]; + int i; + for (i = 0; i < num_shaders; ++i) + { + sprintf(s, "shader%d", i); + strncpy(gl3_shader_file[i], config_get_string(CFG_MACHINE, "GL3 Shaders", s, ""), 511); + gl3_shader_file[i][511] = 0; + } +} + +void sdl_saveconfig() +{ + config_set_int(CFG_MACHINE, NULL, "vid_resize", vid_resize); + config_set_int(CFG_MACHINE, NULL, "video_fullscreen_scale", video_fullscreen_scale); + config_set_int(CFG_MACHINE, NULL, "video_fullscreen_first", video_fullscreen_first); + + config_set_string(CFG_MACHINE, "SDL2", "screenshot_format", screenshot_format); + config_set_int(CFG_MACHINE, "SDL2", "screenshot_flash", screenshot_flash); + + config_set_int(CFG_MACHINE, "SDL2", "custom_width", custom_resolution_width); + config_set_int(CFG_MACHINE, "SDL2", "custom_height", custom_resolution_height); + + config_set_int(CFG_MACHINE, "SDL2", "fullscreen", video_fullscreen); + config_set_int(CFG_MACHINE, "SDL2", "fullscreen_mode", video_fullscreen_mode); + config_set_int(CFG_MACHINE, "SDL2", "scale", video_scale); + config_set_int(CFG_MACHINE, "SDL2", "scale_mode", video_scale_mode); + config_set_int(CFG_MACHINE, "SDL2", "vsync", video_vsync); + config_set_int(CFG_MACHINE, "SDL2", "focus_dim", video_focus_dim); + config_set_int(CFG_MACHINE, "SDL2", "alternative_update_lock", video_alternative_update_lock); + config_set_string(CFG_MACHINE, "SDL2", "render_driver", (char*)requested_render_driver.sdl_id); + + config_set_float(CFG_MACHINE, "GL3", "input_scale", gl3_input_scale); + config_set_int(CFG_MACHINE, "GL3", "input_stretch", gl3_input_stretch); + config_set_float(CFG_MACHINE, "GL3", "shader_refresh_rate", gl3_shader_refresh_rate); + + char s[20]; + int i; + for (i = 0; i < 20; ++i) + { + sprintf(s, "shader%d", i); + if (strlen(gl3_shader_file[i])) + config_set_string(CFG_MACHINE, "GL3 Shaders", s, gl3_shader_file[i]); + else + break; + } + config_set_int(CFG_MACHINE, "GL3 Shaders", "shaders", i); +} + +void update_cdrom_menu(void* hmenu) +{ + if (cdrom_drive == CDROM_IMAGE) + wx_checkmenuitem(menu, WX_ID("IDM_CDROM_IMAGE"), WX_MB_CHECKED); + else if (cdrom_drive > 0) + wx_checkmenuitem(menu, IDM_CDROM_REAL+cdrom_drive, WX_MB_CHECKED); + else + wx_checkmenuitem(menu, WX_ID("IDM_CDROM_EMPTY"), WX_MB_CHECKED); +} + +void wx_initmenu() +{ + menu = wx_getmenu(ghwnd); + + void* cdrom_submenu = wx_getsubmenu(menu, WX_ID("IDM_CDROM")); + +#ifdef __WINDOWS__ + char s[32]; + int c; + /* 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 (GetDriveTypeA(s)==DRIVE_CDROM) + { + sprintf(s, "Host CD/DVD Drive (%c:)", c); + wx_appendmenu(cdrom_submenu, IDM_CDROM_REAL+c, s, wxITEM_RADIO); + } + } +#elif __linux__ + wx_appendmenu(cdrom_submenu, IDM_CDROM_REAL+1, "Host CD/DVD Drive (/dev/cdrom)", wxITEM_RADIO); +#elif __APPLE__ + int c; + + for (c = 1; c < 99; c++) + { + char s[80]; + int fd; + + sprintf(s, "disk%i", c); + fd = opendev(s, O_RDONLY, 0, NULL); + if (fd > 0) + { + char name[255]; + + close(fd); + + sprintf(name, "Host CD/DVD Drive (/dev/disk%i)", c); + wx_appendmenu(cdrom_submenu, IDM_CDROM_REAL+c, name, wxITEM_RADIO); + } + } +#endif +} + +int wx_setupmenu(void* data) +{ + int c; + update_cdrom_menu(menu); + sprintf(menuitem, "IDM_VID_RESOLUTION[%d]", vid_resize); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + wx_enablemenuitem(menu, wx_xrcid("IDM_VID_SCALE_MENU"), !vid_resize); + sprintf(menuitem, "IDM_VID_FS[%d]", video_fullscreen_scale); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + wx_checkmenuitem(menu, WX_ID("IDM_VID_FULLSCREEN"), video_fullscreen); + wx_checkmenuitem(menu, WX_ID("IDM_VID_REMEMBER"), + window_remember ? WX_MB_CHECKED : WX_MB_UNCHECKED); + wx_checkmenuitem(menu, WX_ID("IDM_BPB_DISABLE"), bpb_disable ? WX_MB_CHECKED : WX_MB_UNCHECKED); + + sprintf(menuitem, "IDM_SND_BUF[%d]", (int)(log(sound_buf_len/MIN_SND_BUF)/log(2))); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + + sprintf(menuitem, "IDM_SND_GAIN[%d]", (int)(sound_gain / 2)); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + + sprintf(menuitem, "IDM_VID_SCALE_MODE[%d]", video_scale_mode); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + sprintf(menuitem, "IDM_VID_SCALE[%d]", video_scale); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + sprintf(menuitem, "IDM_VID_FS_MODE[%d]", video_fullscreen_mode); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + wx_checkmenuitem(menu, WX_ID("IDM_VID_VSYNC"), video_vsync); + wx_checkmenuitem(menu, WX_ID("IDM_VID_LOST_FOCUS_DIM"), video_focus_dim); + wx_checkmenuitem(menu, WX_ID("IDM_VID_ALTERNATIVE_UPDATE_LOCK"), video_alternative_update_lock); + + int format = 0; + if (!strcmp(screenshot_format, IMAGE_TIFF)) + format = 1; + else if (!strcmp(screenshot_format, IMAGE_BMP)) + format = 2; + else if (!strcmp(screenshot_format, IMAGE_JPG)) + format = 3; + sprintf(menuitem, "IDM_SCREENSHOT_FORMAT[%d]", format); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + wx_checkmenuitem(menu, WX_ID("IDM_SCREENSHOT_FLASH"), screenshot_flash); + + int num_renderers; + sdl_render_driver* drivers = sdl_get_render_drivers(&num_renderers); + for (c = 1; c < num_renderers; ++c) + { + sprintf(menuitem, "IDM_VID_RENDER_DRIVER[%d]", drivers[c].id); + wx_enablemenuitem(menu, WX_ID(menuitem), drivers[c].renderer_available(&drivers[c])); + } + sprintf(menuitem, "IDM_VID_RENDER_DRIVER[%d]", requested_render_driver.id); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + +// wx_enablemenuitem(menu, WX_ID("IDM_VID_SDL2"), requested_render_driver.id != RENDERER_GL3); + wx_enablemenuitem(menu, WX_ID("IDM_VID_GL3"), requested_render_driver.id == RENDERER_GL3); + + sprintf(menuitem, "IDM_VID_GL3_INPUT_STRETCH[%d]", gl3_input_stretch); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + sprintf(menuitem, "IDM_VID_GL3_INPUT_SCALE[%d]", (int)((gl3_input_scale-0.5)*2)); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + sprintf(menuitem, "IDM_VID_GL3_SHADER_REFRESH_RATE[%g]", gl3_shader_refresh_rate); + wx_checkmenuitem(menu, WX_ID(menuitem), WX_MB_CHECKED); + + return 1; +} + +void sdl_onconfigloaded() +{ + if (ghwnd) + wx_callback(ghwnd, wx_setupmenu, 0); + + /* create directories */ + if (!wx_dir_exists(configs_path)) + wx_create_directory(configs_path); + if (!wx_dir_exists(nvr_path)) + wx_create_directory(nvr_path); + if (!wx_dir_exists(logs_path)) + wx_create_directory(logs_path); + if (!wx_dir_exists(screenshots_path)) + wx_create_directory(screenshots_path); +} + +extern void wx_loadconfig(); +extern void wx_saveconfig(); + +int pc_main(int argc, char** argv) +{ + paths_init(); + +#ifdef __linux__ + char s[1024]; + /* create directories if they don't exist */ + if (!wx_setup(pcem_path)) + return FALSE; + + /* set up default paths */ + sprintf(s, "%s%s%c%s", pcem_path, "roms/", get_path_separator(), "/usr/share/pcem/roms/"); + set_default_roms_paths(s); + append_filename(s, pcem_path, "nvr/", 511); + set_default_nvr_path(s); + append_filename(s, pcem_path, "configs/", 511); + set_default_configs_path(s); + append_filename(s, pcem_path, "screenshots/", 511); + set_default_screenshots_path(s); + append_filename(s, pcem_path, "logs/", 511); + set_default_logs_path(s); +#endif + + add_config_callback(sdl_loadconfig, sdl_saveconfig, sdl_onconfigloaded); + add_config_callback(wx_loadconfig, wx_saveconfig, 0); + + initpc(argc, argv); + resetpchard(); + + sound_init(); + +#ifdef __linux__ + /* check if cfg exists, and if not create it */ + append_filename(s, pcem_path, "pcem.cfg", 511); + if (!wx_file_exists(s)) + saveconfig(NULL); +#endif + +#ifndef __APPLE__ + display_init(); +#endif + sdl_video_init(); + joystick_init(); + + return TRUE; +} + +int wx_load_config(void* hwnd) +{ + if (!config_override) + { + if (!config_selection_open(NULL, 0)) + return FALSE; + } + + return TRUE; +} + +int wx_start(void* hwnd) +{ + int c, d; + ghwnd = hwnd; + +#ifdef __APPLE__ + /* OSX requires SDL to be initialized after wxWidgets. */ + display_init(); +#endif + + readflash = 0; + + wx_initmenu(); + wx_setupmenu(0); + + 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) + { + wx_messagebox(hwnd, + "No ROMs present!\nYou must have at least one romset to use PCem.", + "PCem fatal error", WX_MB_OK); + return 0; + } + + romset = d; + for (c = 0; c < GFX_MAX; c++) + gfx_present[c] = video_card_available(video_old_to_new(c)); + + return TRUE; +} + +int resume_emulation() +{ + if (emulation_state == EMULATION_PAUSED) + { + emulation_state = EMULATION_RUNNING; + pause = 0; + return TRUE; + } + return FALSE; +} + +int start_emulation(void* params) +{ + if (resume_emulation()) + return TRUE; + int c; + pclog("Starting emulation...\n"); + loadconfig(NULL); + + emulation_state = EMULATION_RUNNING; + pause = 0; + + ghMutex = SDL_CreateMutex(); + mainMutex = SDL_CreateMutex(); + mainCond = SDL_CreateCond(); + + if (!loadbios()) + { + if (romset != -1) + wx_messagebox(ghwnd, + "Configured romset not available.\nDefaulting to available romset.", + "PCem error", WX_MB_OK); + for (c = 0; c < ROM_MAX; c++) + { + if (romspresent[c]) + { + romset = c; + model = model_getmodel(romset); + break; + } + } + } + + if (!video_card_available(video_old_to_new(gfxcard))) + { + if (romset != -1) + wx_messagebox(ghwnd, + "Configured video BIOS not available.\nDefaulting to available romset.", + "PCem error", WX_MB_OK); + for (c = GFX_MAX - 1; c >= 0; c--) + { + if (gfx_present[c]) + { + gfxcard = c; + break; + } + } + } + + + loadbios(); + resetpchard(); + midi_init(); + + display_start(params); + mainthreadh = SDL_CreateThread(mainthread, "Main Thread", NULL); + + onesectimer = SDL_AddTimer(1000, timer_onesec, NULL); + + updatewindowsize(640, 480); + + timer_freq = SDL_GetPerformanceFrequency(); + + if (show_machine_on_start) + wx_show_status(ghwnd); + + return TRUE; +} + +int pause_emulation() +{ + pclog("Emulation paused.\n"); + emulation_state = EMULATION_PAUSED; + pause = 1; + return TRUE; +} + +int stop_emulation() +{ + emulation_state = EMULATION_STOPPED; + pclog("Stopping emulation...\n"); + SDL_LockMutex(mainMutex); + running = 0; + SDL_CondWaitTimeout(mainCond, mainMutex, 10 * 1000); + SDL_UnlockMutex(mainMutex); + + SDL_DestroyCond(mainCond); + SDL_DestroyMutex(mainMutex); + + startblit(); + display_stop(); + +#if SDL_VERSION_ATLEAST(2, 0, 2) + SDL_DetachThread(mainthreadh); +#endif + mainthreadh = NULL; + SDL_RemoveTimer(onesectimer); + savenvr(); + saveconfig(NULL); + + endblit(); + SDL_DestroyMutex(ghMutex); + + device_close_all(); + midi_close(); + + pclog("Emulation stopped.\n"); + + wx_close_status(ghwnd); + + return TRUE; +} + +void reset_emulation() +{ + pause_emulation(); + SDL_Delay(100); + resetpchard(); + resume_emulation(); +} + +int wx_stop() +{ + pclog("Shutting down...\n"); + closepc(); + display_close(); + sdl_video_close(); + + printf("Shut down successfully!\n"); + return TRUE; +} + +char openfilestring[260]; +int getfile(void* hwnd, char *f, char *fn) +{ + int ret = wx_filedialog(hwnd, "Open", fn, f, 0, 1, openfilestring); +#ifdef __APPLE__ + /* wxWidgets on OSX may mess up the SDL-window somehow, so just in case we reset it here */ + window_doreset = 1; +#endif + return ret; +} + +int getsfile(void* hwnd, char *f, char *fn, char *dir, char *ext) +{ + int ret = wx_filedialog(hwnd, "Save", dir, f, ext, 0, openfilestring); +#ifdef __APPLE__ + window_doreset = 1; +#endif + return ret; +} + +int getfilewithcaption(void* hwnd, char *f, char *fn, char *caption) +{ + int ret = wx_filedialog(hwnd, caption, fn, f, 0, 1, openfilestring); +#ifdef __APPLE__ + /* wxWidgets on OSX may mess up the SDL-window somehow, so just in case we reset it here */ + window_doreset = 1; +#endif + return ret; +} + +void atapi_close(void) +{ + switch (cdrom_drive) + { + case CDROM_IMAGE: + image_close(); + break; + default: + ioctl_close(); + break; + } +} + +int custom_resolution_callback(void* window, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + switch (message) + { + case WX_INITDIALOG: + { + wx_sendmessage(wx_getdlgitem(window, wx_xrcid("IDC_WIDTH")), WX_UDM_SETPOS, 0, custom_resolution_width); + wx_sendmessage(wx_getdlgitem(window, wx_xrcid("IDC_HEIGHT")), WX_UDM_SETPOS, 0, custom_resolution_height); + return TRUE; + } + case WX_COMMAND: + { + if (wParam == wxID_OK) + { + custom_resolution_width = wx_sendmessage(wx_getdlgitem(window, wx_xrcid("IDC_WIDTH")), WX_UDM_GETPOS, 0, 0); + custom_resolution_height = wx_sendmessage(wx_getdlgitem(window, wx_xrcid("IDC_HEIGHT")), WX_UDM_GETPOS, 0, 0); + wx_enddialog(window, 1); + return TRUE; + } + else if (wParam == wxID_CANCEL) + { + wx_enddialog(window, 0); + return TRUE; + } + + } + } + return 0; +} + +int wx_handle_command(void* hwnd, int wParam, int checked) +{ + void* hmenu; + char temp_image_path[1024]; + int new_cdrom_drive; + hmenu = wx_getmenu(hwnd); + + if (ID_IS("IDM_STATUS")) + { + wx_show_status(hwnd); + } + else if (ID_IS("IDM_FILE_RESET")) + { + pause = 1; + SDL_Delay(100); + savenvr(); + resetpc(); + pause = 0; + } + else if (ID_IS("IDM_FILE_HRESET")) + { + pause = 1; + SDL_Delay(100); + savenvr(); + resetpchard(); + pause = 0; + } + else if (ID_IS("IDM_FILE_RESET_CAD")) + { + pause = 1; + SDL_Delay(100); + savenvr(); + resetpc_cad(); + pause = 0; + } + else if (ID_IS("IDM_FILE_EXIT")) + { +// wx_exit(hwnd, 0); + wx_stop_emulation(hwnd); + } + else if (ID_IS("IDM_DISC_A")) + { + if (!getfile(hwnd, + "Disc image (*.img;*.ima;*.fdi)|*.img;*.ima;*.fdi|All files (*.*)|*.*", + discfns[0])) + { + disc_close(0); + disc_load(0, openfilestring); + saveconfig(NULL); + } + } + else if (ID_IS("IDM_DISC_B")) + { + if (!getfile(hwnd, + "Disc image (*.img;*.ima;*.fdi)|*.img;*.ima;*.fdi|All files (*.*)|*.*", + discfns[1])) + { + disc_close(1); + disc_load(1, openfilestring); + saveconfig(NULL); + } + } + else if (ID_IS("IDM_EJECT_A")) + { + disc_close(0); + saveconfig(NULL); + } + else if (ID_IS("IDM_EJECT_B")) + { + disc_close(1); + saveconfig(NULL); + } + else if (ID_IS("IDM_BPB_DISABLE")) + { + bpb_disable = !bpb_disable; + wx_checkmenuitem(hmenu, wParam, bpb_disable); + saveconfig(NULL); + } + else if (ID_IS("IDM_DISC_CREATE")) + { + creatediscimage_open(hwnd); + } + else if (ID_IS("IDM_DISC_ZIP")) + { + char zip_fn[256] = ""; + + if (!getfile(hwnd, + "Disc image (*.img)|*.img|All files (*.*)|*.*", + zip_fn)) + { + zip_load(openfilestring); + } + } + else if (ID_IS("IDM_EJECT_ZIP")) + { + zip_eject(); + } + else if (ID_IS("IDM_CASSETTE_LOAD")) + { + if (!getfile(hwnd, + "Tape image (*.pzxi;*.pzx)|*.pzxi;*.pzx|All files (*.*)|*.*", + cassettefn)) + { + cassette_eject(); + cassette_load(openfilestring); + saveconfig(NULL); + } + } + else if (ID_IS("IDM_CASSETTE_EJECT")) + { + cassette_eject(); + saveconfig(NULL); + } + else if (ID_IS("IDM_MACHINE_TOGGLE")) + { + if (emulation_state != EMULATION_STOPPED) + wx_togglewindow(hwnd); + } + else if (ID_RANGE("IDM_VID_RESOLUTION[start]", "IDM_VID_RESOLUTION[end]")) + { + vid_resize = wParam - wx_xrcid("IDM_VID_RESOLUTION[start]"); + wx_checkmenuitem(hmenu, wParam, WX_MB_CHECKED); + window_dosetresize = 1; + wx_enablemenuitem(hmenu, wx_xrcid("IDM_VID_SCALE_MENU"), !vid_resize); + saveconfig(NULL); + } + else if (ID_IS("IDM_VID_RESOLUTION_CUSTOM")) + { + if (wx_dialogbox(hwnd, "CustomResolutionDlg", custom_resolution_callback)) + { + if (vid_resize != 2) + { + vid_resize = 2; + wx_checkmenuitem(hmenu, wx_xrcid("IDM_VID_RESOLUTION[2]"), WX_MB_CHECKED); + wx_enablemenuitem(hmenu, wx_xrcid("IDM_VID_SCALE_MENU"), !vid_resize); + } + window_dosetresize = 1; + } + } + else if (ID_IS("IDM_SCREENSHOT")) + { + take_screenshot = 1; + } + else if (ID_RANGE("IDM_SCREENSHOT_FORMAT[start]", "IDM_SCREENSHOT_FORMAT[end]")) + { + int format = wParam - wx_xrcid("IDM_SCREENSHOT_FORMAT[start]"); + if (format == 0) + strcpy(screenshot_format, IMAGE_PNG); + else if (format == 1) + strcpy(screenshot_format, IMAGE_TIFF); + else if (format == 2) + strcpy(screenshot_format, IMAGE_BMP); + else if (format == 3) + strcpy(screenshot_format, IMAGE_JPG); + saveconfig(NULL); + wx_checkmenuitem(hmenu, wParam, WX_MB_CHECKED); + } + else if (ID_IS("IDM_SCREENSHOT_FLASH")) + { + screenshot_flash = !screenshot_flash; + wx_checkmenuitem(hmenu, wParam, screenshot_flash); + saveconfig(NULL); + } + else if (ID_IS("IDM_VID_REMEMBER")) + { + window_remember = !window_remember; + wx_checkmenuitem(hmenu, WX_ID("IDM_VID_REMEMBER"), + window_remember ? WX_MB_CHECKED : WX_MB_UNCHECKED); + window_doremember = 1; + saveconfig(NULL); + } + else if (ID_IS("IDM_VID_FULLSCREEN")) + { + if (video_fullscreen_first) + { + video_fullscreen_first = 0; + wx_messagebox(hwnd, + "Use CTRL + ALT + PAGE DOWN to return to windowed mode", + "PCem", WX_MB_OK); + } + video_fullscreen = !video_fullscreen; + wx_checkmenuitem(hmenu, wParam, video_fullscreen); + saveconfig(NULL); + } + else if (ID_IS("IDM_VID_FULLSCREEN_TOGGLE")) + { + toggle_fullscreen(); + } + else if (ID_RANGE("IDM_VID_FS[start]", "IDM_VID_FS[end]")) + { + video_fullscreen_scale = wParam - wx_xrcid("IDM_VID_FS[start]"); + display_resize(video_width, video_height); + wx_checkmenuitem(hmenu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_RANGE("IDM_VID_SCALE_MODE[start]", "IDM_VID_SCALE_MODE[end]")) + { + video_scale_mode = wParam - wx_xrcid("IDM_VID_SCALE_MODE[start]"); + renderer_doreset = 1; + wx_checkmenuitem(hmenu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_RANGE("IDM_VID_SCALE[start]", "IDM_VID_SCALE[end]")) + { + video_scale = wParam - wx_xrcid("IDM_VID_SCALE[start]"); + wx_checkmenuitem(hmenu, wParam, WX_MB_CHECKED); + display_resize(video_width, video_height); + saveconfig(NULL); + } + else if (ID_RANGE("IDM_VID_FS_MODE[start]", "IDM_VID_FS_MODE[end]")) + { + video_fullscreen_mode = wParam - wx_xrcid("IDM_VID_FS_MODE[start]"); + wx_checkmenuitem(hmenu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_RANGE("IDM_VID_RENDER_DRIVER[start]", "IDM_VID_RENDER_DRIVER[end]")) + { + requested_render_driver = sdl_get_render_driver_by_id(wParam - wx_xrcid("IDM_VID_RENDER_DRIVER[start]"), RENDERER_AUTO); + window_doreset = 1; + + /* update enabled menu-items */ +// wx_enablemenuitem(menu, WX_ID("IDM_VID_SDL2"), requested_render_driver.id != RENDERER_GL3); + wx_enablemenuitem(menu, WX_ID("IDM_VID_GL3"), requested_render_driver.id == RENDERER_GL3); + + wx_checkmenuitem(hmenu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_IS("IDM_VID_VSYNC")) + { + video_vsync = !video_vsync; + wx_checkmenuitem(menu, wParam, video_vsync); + renderer_doreset = 1; + saveconfig(NULL); + } + else if (ID_IS("IDM_VID_LOST_FOCUS_DIM")) + { + video_focus_dim = !video_focus_dim; + wx_checkmenuitem(menu, wParam, video_focus_dim); + saveconfig(NULL); + } + else if (ID_IS("IDM_VID_ALTERNATIVE_UPDATE_LOCK")) + { + video_alternative_update_lock = !video_alternative_update_lock; + wx_checkmenuitem(menu, wParam, video_alternative_update_lock); + renderer_doreset = 1; + saveconfig(NULL); + } + else if (ID_RANGE("IDM_VID_GL3_INPUT_STRETCH[start]", "IDM_VID_GL3_INPUT_STRETCH[end]")) + { + gl3_input_stretch = wParam - wx_xrcid("IDM_VID_GL3_INPUT_STRETCH[start]"); + wx_checkmenuitem(menu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_RANGE("IDM_VID_GL3_INPUT_SCALE[start]", "IDM_VID_GL3_INPUT_SCALE[end]")) + { + int input_scale = wParam - wx_xrcid("IDM_VID_GL3_INPUT_SCALE[start]"); + gl3_input_scale = input_scale/2.0f+0.5f; + wx_checkmenuitem(menu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_RANGE("IDM_VID_GL3_SHADER_REFRESH_RATE[start]", "IDM_VID_GL3_SHADER_REFRESH_RATE[end]")) + { + gl3_shader_refresh_rate = wParam - wx_xrcid("IDM_VID_GL3_SHADER_REFRESH_RATE[start]"); + wx_checkmenuitem(menu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_IS("IDM_VID_GL3_SHADER_MANAGER")) + { + if (shader_manager_open(hwnd)) + { + renderer_doreset = 1; + saveconfig(NULL); + } +// if (!getfile(hwnd, "GLSL Shaders (*.glslp;*.glsl)|*.glslp;*.glsl|All files (*.*)|*.*", gl3_shader_file)) +// { +// strncpy(gl3_shader_file, openfilestring, 511); +// gl3_shader_file[511] = 0; +// renderer_doreset = 1; +// saveconfig(NULL); +// } + + } + else if (ID_RANGE("IDM_SND_BUF[start]", "IDM_SND_BUF[end]")) + { + sound_buf_len = MIN_SND_BUF*1<<(wParam - wx_xrcid("IDM_SND_BUF[start]")); + wx_checkmenuitem(menu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_RANGE("IDM_SND_GAIN[start]", "IDM_SND_GAIN[end]")) + { + sound_gain = 2 * (wParam - wx_xrcid("IDM_SND_GAIN[start]")); + wx_checkmenuitem(menu, wParam, WX_MB_CHECKED); + saveconfig(NULL); + } + else if (ID_IS("IDM_CDROM_EMPTY")) + { + if (cdrom_drive == 0) + { + update_cdrom_menu(hmenu); + /* Switch from empty to empty. Do nothing. */ + return 0; + } + atapi->exit(); + atapi_close(); + ioctl_set_drive(0); + old_cdrom_drive = cdrom_drive; + cdrom_drive = 0; + saveconfig(NULL); + update_cdrom_menu(hmenu); + } + else if (ID_IS("IDM_CDROM_IMAGE") || ID_IS("IDM_CDROM_IMAGE_LOAD")) + { + if (!getfile(hwnd, + "CD-ROM image (*.iso;*.cue)|*.iso;*.cue|All files (*.*)|*.*", + image_path)) + { + old_cdrom_drive = cdrom_drive; + strcpy(temp_image_path, openfilestring); + if ((strcmp(image_path, temp_image_path) == 0) + && (cdrom_drive == CDROM_IMAGE)) + { + /* Switching from ISO to the same ISO. Do nothing. */ + update_cdrom_menu(hmenu); + return 0; + } + atapi->exit(); + atapi_close(); + image_open(temp_image_path); + cdrom_drive = CDROM_IMAGE; + saveconfig(NULL); + update_cdrom_menu(hmenu); + } else + update_cdrom_menu(hmenu); + } + else if (wParam >= IDM_CDROM_REAL && wParam < IDM_CDROM_REAL+100) + { + new_cdrom_drive = wParam-IDM_CDROM_REAL; + if (cdrom_drive == new_cdrom_drive) + { + /* Switching to the same drive. Do nothing. */ + update_cdrom_menu(hmenu); + return 0; + } + old_cdrom_drive = cdrom_drive; + atapi->exit(); + atapi_close(); + ioctl_set_drive(new_cdrom_drive); + cdrom_drive = new_cdrom_drive; + saveconfig(NULL); + update_cdrom_menu(hmenu); + } + return 0; +} diff --git a/src/wx-sdl2.h b/src/wx-sdl2.h new file mode 100644 index 0000000..233ceab --- /dev/null +++ b/src/wx-sdl2.h @@ -0,0 +1,19 @@ +#ifdef __cplusplus +extern "C" { +#endif + +void leave_fullscreen(); +int getfile(void* hwnd, char *f, char *fn); +int getsfile(void* hwnd, char *f, char *fn, char *dir, char *ext); +int getfilewithcaption(void* hwnd, char *f, char *fn, char *caption); +void screenshot_taken(unsigned char* rgb, int width, int height); + +#ifdef __cplusplus +} +#endif + +extern char openfilestring[260]; + +extern int pause; + +extern int take_screenshot; diff --git a/src/wx-shader_man.c b/src/wx-shader_man.c new file mode 100644 index 0000000..6d277d7 --- /dev/null +++ b/src/wx-shader_man.c @@ -0,0 +1,228 @@ +#include +#include +#include "wx-utils.h" +#include "wx-display.h" +#include "wx-glslp-parser.h" +#include "wx-shaderconfig.h" +#include "config.h" + +#define MAX_USER_SHADERS 20 + +extern char *get_filename(char *s); + +extern char gl3_shader_file[MAX_USER_SHADERS][512]; +static char shaders[MAX_USER_SHADERS][512]; + +void read_shader_config(glslp_t* shader) +{ + char s[512]; + int i; + char* name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); + for (i = 0; i < shader->num_parameters; ++i) + { + struct parameter* param = &shader->parameters[i]; + param->value = config_get_float(CFG_MACHINE, s, param->id, param->default_value); + } +} + +void write_shader_config(glslp_t* shader) +{ + char s[512]; + int i; + char* name = shader->name; + sprintf(s, "GL3 Shaders - %s", name); + for (i = 0; i < shader->num_parameters; ++i) + { + struct parameter* param = &shader->parameters[i]; + config_set_float(CFG_MACHINE, s, param->id, param->value); + } +} + +static void add_shader(int p, const char* s) +{ + memmove(&shaders[p+1], &shaders[p], (MAX_USER_SHADERS-p-2)*512); + strcpy(shaders[p], s); +} + +static int shader_list_update(void* hdlg) +{ + int c; + void* h; + int num = 0; + + h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + wx_sendmessage(h, WX_LB_RESETCONTENT, 0, 0); + + for (c = 0; c < MAX_USER_SHADERS; c++) + { + if (strlen(shaders[c])) + { + char* p = get_filename(shaders[c]); + wx_sendmessage(h, WX_LB_INSERTSTRING, c, (LONG_PARAM)p); + ++num; + } + } + return num; +} + +static void set_shaders() +{ + int i, j, available; + char s[128]; + char name[64]; + for (i = 0; i < MAX_USER_SHADERS; ++i) + { + if (strlen(gl3_shader_file[i])) + { + available = 0; + for (j = 0; j < MAX_USER_SHADERS; ++j) + { + if (!strcmp(gl3_shader_file[i], shaders[j])) + { + available = 1; + continue; + } + } + if (!available) + { + get_glslp_name(gl3_shader_file[i], name, sizeof(name)); + sprintf(s, "GL3 Shaders - %s", name); + config_free_section(CFG_MACHINE, s); + } + } + } + memcpy(&gl3_shader_file, &shaders, sizeof(gl3_shader_file)); + +} + +static int shader_manager_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) +{ + char s[512]; + switch (message) + { + case WX_INITDIALOG: + { + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + memcpy(&shaders, &gl3_shader_file, sizeof(gl3_shader_file)); + int len = shader_list_update(hdlg); + if (len) + wx_sendmessage(h, WX_LB_SETCURSEL, len-1, 0); + return TRUE; + } + case WX_COMMAND: + { + if (wParam == wxID_OK) + { + set_shaders(); + wx_enddialog(hdlg, 1); + return TRUE; + } + else if (wParam == wxID_CANCEL) + { + wx_enddialog(hdlg, 0); + return TRUE; + } + else if (wParam == WX_ID("IDC_APPLY")) + { + set_shaders(); + renderer_doreset = 1; + return TRUE; + } + else if (wParam == WX_ID("IDC_ADD")) + { + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + int c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + int count = wx_sendmessage(h, WX_LB_GETCOUNT, 0, 0); + if (count >= MAX_USER_SHADERS) + { + wx_simple_messagebox("Error", "Can't add more shaders."); + return FALSE; + } + + int ret = !wx_filedialog(hdlg, "Open", shaders[c], "GLSL Shaders (*.glslp;*.glsl)|*.glslp;*.glsl|All files (*.*)|*.*", 0, 1, s); + + if (ret) + { + add_shader(c+1, s); + shader_list_update(hdlg); + wx_sendmessage(h, WX_LB_SETCURSEL, c+1, 0); + } + + return TRUE; + } + else if (wParam == WX_ID("IDC_CONFIG")) + { + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + int c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + if (c >= 0) + { + glslp_t* glsl = glslp_parse(shaders[c]); + if (glsl) + { + read_shader_config(glsl); + shaderconfig_open(hdlg, glsl); + write_shader_config(glsl); + glslp_free(glsl); + return TRUE; + } + } + return FALSE; + } + else if (wParam == WX_ID("IDC_REMOVE")) + { + void* h; + int c; + h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + if (c >= 0) + { + memmove(&shaders[c], &shaders[c+1], (MAX_USER_SHADERS-c-1)*512); + int len = shader_list_update(hdlg); + if (len > 0) + { + if (c > 0) + c--; + wx_sendmessage(h, WX_LB_SETCURSEL, c, 0); + } + } + } + else if (wParam == WX_ID("IDC_MOVE_UP")) + { + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + int c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + if (c > 0) + { + strcpy(s, shaders[c-1]); + strcpy(shaders[c-1], shaders[c]); + strcpy(shaders[c], s); + shader_list_update(hdlg); + wx_sendmessage(h, WX_LB_SETCURSEL, c-1, 0); + } + } + else if (wParam == WX_ID("IDC_MOVE_DOWN")) + { + void* h = wx_getdlgitem(hdlg, WX_ID("IDC_LIST")); + int c = wx_sendmessage(h, WX_LB_GETCURSEL, 0, 0); + if (c < MAX_USER_SHADERS-1) + { + if (strlen(shaders[c+1])) + { + strcpy(s, shaders[c+1]); + strcpy(shaders[c+1], shaders[c]); + strcpy(shaders[c], s); + shader_list_update(hdlg); + wx_sendmessage(h, WX_LB_SETCURSEL, c+1, 0); + } + } + } + } + break; + } + return FALSE; +} + +int shader_manager_open(void* hwnd) +{ + return wx_dialogbox(hwnd, "ShaderManagerDlg", shader_manager_dlgproc); +} diff --git a/src/wx-shaderconfig.cc b/src/wx-shaderconfig.cc new file mode 100644 index 0000000..d56096d --- /dev/null +++ b/src/wx-shaderconfig.cc @@ -0,0 +1,146 @@ +#include "wx-utils.h" +#include + +#include "wx-dialogbox.h" + +#ifndef WX_PRECOMP +#include +#endif + +#include +#include + +#include "wx-glslp-parser.h" +#include "wx-shaderconfig.h" + +extern "C" +{ + #include "config.h" + void saveconfig(char*); + void resetpchard(); + int deviceconfig_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam); + void write_shader_config(glslp_t* shader); + struct glslp_t* current_glsl; + int confirm(); +} +#define IDC_CONFIG_BASE 1000 +#define ID_APPLY 500 +#define ID_RESET 501 +extern int renderer_doreset; + +static int shaderconfig_dlgproc(void* hdlg, int message, INT_PARAM wParam, LONG_PARAM lParam) { + int i; + switch (message) { + case WX_INITDIALOG: { + return TRUE; + } + case WX_COMMAND: + switch (wParam) { + case ID_APPLY: { + for (i = 0; i < current_glsl->num_parameters; ++i) + { + struct parameter* p = ¤t_glsl->parameters[i]; + wxSpinCtrlDouble* h = (wxSpinCtrlDouble*)wx_getdlgitem(hdlg, IDC_CONFIG_BASE+i); + p->value = (float)h->GetValue(); + } + write_shader_config(current_glsl); + renderer_doreset = 1; + return TRUE; + } + case wxID_OK: { + for (i = 0; i < current_glsl->num_parameters; ++i) + { + struct parameter* p = ¤t_glsl->parameters[i]; + wxSpinCtrlDouble* h = (wxSpinCtrlDouble*)wx_getdlgitem(hdlg, IDC_CONFIG_BASE+i); + p->value = (float)h->GetValue(); + } + write_shader_config(current_glsl); + renderer_doreset = 1; + wx_enddialog(hdlg, 0); + return TRUE; + } + case wxID_CANCEL: + wx_enddialog(hdlg, 0); + return TRUE; + case ID_RESET: { + for (i = 0; i < current_glsl->num_parameters; ++i) + { + struct parameter* p = ¤t_glsl->parameters[i]; + wxSpinCtrlDouble* h = (wxSpinCtrlDouble*)wx_getdlgitem(hdlg, IDC_CONFIG_BASE+i); + h->SetValue(p->default_value); + } + return TRUE; + } + } + } + return TRUE; +} + + + +void shaderconfig_open(void* hwnd, struct glslp_t* glsl) { + int i; + current_glsl = glsl; + + PCemDialogBox dialog((wxWindow*) hwnd, shaderconfig_dlgproc); +// dialog.SetWindowStyle(wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER); + + dialog.SetTitle("Shader Configuration"); + + wxBoxSizer* root = new wxBoxSizer(wxVERTICAL); + dialog.SetSizer(root); + + wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); + root->Add(sizer, 0, wxALL, 5); + + wxPanel* panel = new wxPanel(&dialog, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL | wxBORDER_SUNKEN); + sizer->Add(panel); + + wxBoxSizer* panelSizer = new wxBoxSizer(wxVERTICAL); + panel->SetSizer(panelSizer); + + wxScrolledWindow* win = new wxScrolledWindow(panel, wxID_ANY, wxDefaultPosition, wxSize(300, 350), wxHSCROLL|wxVSCROLL); + win->SetScrollRate( 5, 5 ); + panelSizer->Add(win, 1, wxEXPAND | wxALL, 5); + + wxBoxSizer* winSizer = new wxBoxSizer(wxVERTICAL); + win->SetSizer(winSizer); + + if (glsl->num_parameters > 0) + { + wxPanel* scrollPanel = new wxPanel(win); + winSizer->Add(scrollPanel); + + wxBoxSizer* scollPanelSizer = new wxBoxSizer(wxVERTICAL); + scrollPanel->SetSizer(scollPanelSizer); + + for (i = 0; i < glsl->num_parameters; ++i) + { + struct parameter* p = &glsl->parameters[i]; + scollPanelSizer->Add(new wxStaticText(scrollPanel, wxID_ANY, p->description), 0, wxALL); + wxSpinCtrlDouble* spin = new wxSpinCtrlDouble(scrollPanel, IDC_CONFIG_BASE+i); + spin->SetRange(p->min, p->max); + spin->SetIncrement(p->step); + spin->SetValue(p->value); + spin->SetDigits(2); + + scollPanelSizer->Add(spin, 0, wxALL); + } + } + else + winSizer->Add(new wxStaticText(win, wxID_ANY, "No configuration available."), 0, wxALL); + + wxBoxSizer* buttonSizer = new wxBoxSizer(wxHORIZONTAL); + + buttonSizer->Add(new wxButton(&dialog, ID_APPLY, "Apply")); + buttonSizer->Add(new wxButton(&dialog, wxID_OK)); + buttonSizer->Add(new wxButton(&dialog, wxID_CANCEL)); + buttonSizer->Add(new wxButton(&dialog, ID_RESET, "Reset")); + + sizer->Add(buttonSizer); + + dialog.Fit(); + dialog.OnInit(); + dialog.ShowModal(); + dialog.Destroy(); +} diff --git a/src/wx-shaderconfig.h b/src/wx-shaderconfig.h new file mode 100644 index 0000000..279409c --- /dev/null +++ b/src/wx-shaderconfig.h @@ -0,0 +1,13 @@ +#ifndef SRC_WX_SHADERCONFIG_H_ +#define SRC_WX_SHADERCONFIG_H_ + +#ifdef __cplusplus +extern "C" { +#endif +void shaderconfig_open(void* hwnd, struct glslp_t* glsl); +#ifdef __cplusplus +} +#endif + + +#endif /* SRC_WX_SHADERCONFIG_H_ */ diff --git a/src/wx-status.cc b/src/wx-status.cc new file mode 100644 index 0000000..eb00e0d --- /dev/null +++ b/src/wx-status.cc @@ -0,0 +1,351 @@ +#include "wx-status.h" +#include "wx-common.h" +#include "wx-utils.h" +#include +#include +#include + +extern "C" { + int get_status(char*, char*); + int fps; + int updatestatus; + drive_info_t* get_machine_info(char*, int*); +} + +int show_machine_on_start = 0; +int confirm_on_stop_emulation = 1; +int confirm_on_reset_machine = 1; +int show_status = 0; +int show_speed_history = 0; +int show_disc_activity = 1; +int show_machine_info = 1; +int show_mount_paths = 0; + +#define ACTIVITY_TEXT wxT("Activity") + +#define MAX(a, b) (a > b ? a : b) + +#define render_disc_activity(x, y) do { \ +if (show_disc_activity) \ +{ \ + int w = 8; \ + int h = 8; \ + if (info.readflash) { \ + dc.SetBrush(wxBrush(wxColour(0,255,0))); \ + } else { \ + dc.SetBrush(wxBrush(wxColour(0,100,0))); \ + } \ + dc.DrawRectangle(x+bitmap.GetWidth()-w, y, w, h); \ +}} while (0) + +StatusTimer::StatusTimer(StatusPane* pane) +{ + this->pane = pane; +} + +void StatusTimer::Notify() +{ + pane->Refresh(); +} + +void StatusTimer::Start() +{ + wxTimer::Start(10); +} + +BEGIN_EVENT_TABLE(StatusPane, wxPanel) EVT_PAINT(StatusPane::PaintEvent) +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(StatusFrame, wxFrame) END_EVENT_TABLE() + +StatusPane::StatusPane(wxFrame* parent) : + wxPanel(parent) +{ +#ifndef __WXOSX_MAC__ + SetDoubleBuffered(true); +#endif + machineInfoText[0] = statusMachineText[0] = statusDeviceText[0] = 0; + lastSpeedUpdate = 0; + memset(speedHistory, -1, sizeof(speedHistory)); + + bitmapFDD[0] = wxXmlResource::Get()->LoadBitmap("BITMAP_FLOPPY"); + bitmapFDD[1] = bitmapFDD[0].ConvertToDisabled(); + bitmapHDD[0] = wxXmlResource::Get()->LoadBitmap("BITMAP_HARDDISK"); + bitmapHDD[1] = bitmapHDD[0].ConvertToDisabled(); + bitmapCDROM[0] = wxXmlResource::Get()->LoadBitmap("BITMAP_CDROM"); + bitmapCDROM[1] = bitmapCDROM[0].ConvertToDisabled(); +} + +StatusPane::~StatusPane() { +} + +void StatusPane::PaintEvent(wxPaintEvent& evt) +{ + wxPaintDC dc(this); + Render(dc); +} + +void StatusPane::PaintNow() +{ + wxClientDC dc(this); + Render(dc); +} + +void StatusPane::Render(wxDC& dc) +{ + wxSize cSize = GetParent()->GetClientSize(); + + int width = 0; + int height = 0; + wxLongLong millis = wxGetUTCTimeMillis(); + + dc.SetBackground(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK)); + dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + dc.Clear(); + + // draw model/cpu etc + if (show_machine_info) { + int num_info; + drive_info_t* drive_info = get_machine_info(machineInfoText, &num_info); + wxSize size = dc.GetMultiLineTextExtent(machineInfoText); + dc.DrawText(machineInfoText, 5, height+5); + + width = MAX(width, width+5+size.x); + height = MAX(height, height+5+size.y); + + int x = cSize.x-5; + + for (int i = 0; i < num_info; ++i) + { + drive_info_t info = show_mount_paths ? drive_info[i] : drive_info[num_info-i-1]; + wxBitmap bitmap; + if (info.type == DRIVE_TYPE_FDD) + bitmap = info.enabled ? bitmapFDD[0] : bitmapFDD[1]; + else if (info.type == DRIVE_TYPE_CDROM) + bitmap = info.enabled ? bitmapCDROM[0] : bitmapCDROM[1]; + else + bitmap = info.enabled ? bitmapHDD[0] : bitmapHDD[1]; + if (show_mount_paths) + { + x = 5; + dc.DrawBitmap(bitmap, x, height+5); + render_disc_activity(x, height+5); + x += bitmap.GetWidth()+5; + + std::ostringstream ss; + ss << info.drive_letter << ":" << " " << info.fn; + std::string s = ss.str(); + size = dc.GetTextExtent(s); + dc.DrawText(s, x, height+5+(bitmap.GetHeight()-size.y)/2); + width = MAX(width, x+size.x); + height = height+5+MAX(bitmap.GetHeight(), size.y); + } else { + x -= bitmap.GetWidth(); + dc.DrawBitmap(bitmap, x, 5); + render_disc_activity(x, 5); + x -= 5; + height = MAX(height, 5+bitmap.GetHeight()); + } + } + } + + if (emulation_state != EMULATION_STOPPED) + { + // draw status text + if (show_status) { + if (updatestatus) { + updatestatus = 0; + get_status(statusMachineText, statusDeviceText); + } + if (statusMachineText) { + int statusX = 5; + int statusY = height+5; + wxSize size = dc.GetMultiLineTextExtent(statusMachineText); + dc.DrawText(statusMachineText, statusX, statusY); + width = MAX(width, statusX+size.GetWidth()); + height = MAX(height, statusY+size.GetHeight()); + if (statusDeviceText) { + wxSize dSize = dc.GetMultiLineTextExtent(statusDeviceText); + dc.DrawText(statusDeviceText, statusX+ceil((size.GetWidth()+50)/100.0)*100, statusY); + width = MAX(width, statusX+ceil((size.GetWidth()+50)/100.0)*100+ceil((dSize.GetWidth()+50)/100.0)*100); + height = MAX(height, statusY+dSize.GetHeight()); + } + } + } + + if (emulation_state == EMULATION_RUNNING && (millis-lastSpeedUpdate > 500)) { + lastSpeedUpdate = millis; + memmove(speedHistory+1, speedHistory, SPEED_HISTORY_LENGTH-2); + speedHistory[0] = fps; + } + // draw speed history + if (show_speed_history) { + int speedGraphBorder = 5; + int speedGraphX = 5; + int speedGraphY = height+5; + int speedGraphWidth = MAX(2*SPEED_HISTORY_LENGTH, width-5); + double lineLength = (double)(speedGraphWidth-2)/(SPEED_HISTORY_LENGTH-1); + int speedGraphHeight = 125; + dc.SetBrush(wxBrush(wxColour(255, 255, 255))); + dc.DrawRectangle(speedGraphX, speedGraphY, speedGraphWidth, speedGraphHeight+speedGraphBorder*2); + dc.SetPen(wxPen(wxColour(200, 200, 200))); + dc.DrawLine(speedGraphX, speedGraphY+speedGraphBorder+speedGraphHeight-0, speedGraphX+speedGraphWidth, speedGraphY+speedGraphHeight+speedGraphBorder-0); // 0 + dc.DrawLine(speedGraphX, speedGraphY+speedGraphBorder+speedGraphHeight-50, speedGraphX+speedGraphWidth, speedGraphY+speedGraphHeight+speedGraphBorder-50); // 50 + dc.DrawLine(speedGraphX, speedGraphY+speedGraphBorder+speedGraphHeight-100, speedGraphX+speedGraphWidth, speedGraphY+speedGraphHeight+speedGraphBorder-100); // 100 + dc.DrawLine(speedGraphX, speedGraphY+speedGraphBorder+speedGraphHeight-125, speedGraphX+speedGraphWidth, speedGraphY+speedGraphHeight+speedGraphBorder-125); // 125 + dc.SetPen(wxPen(wxColour(0, 0, 0))); + for (int i = 0; i < SPEED_HISTORY_LENGTH-1; ++i) { + int v0 = speedHistory[i]; + int v1 = speedHistory[i+1]; + if (v0 >= 0 && v1 >= 0) { + dc.DrawLine(speedGraphX+speedGraphWidth-i*lineLength-1, speedGraphY+speedGraphHeight+speedGraphBorder-v0, + speedGraphX+speedGraphWidth-(i+1)*lineLength-1, speedGraphY+speedGraphHeight+speedGraphBorder-v1); + } + } + dc.SetBrush(wxBrush(wxColour(255, 255, 255), wxBrushStyle(wxBRUSHSTYLE_TRANSPARENT))); + dc.DrawRectangle(speedGraphX, speedGraphY, speedGraphWidth, speedGraphHeight+speedGraphBorder*2); + + width = MAX(width, (speedGraphX+speedGraphWidth)); + height = MAX(height, speedGraphY+speedGraphHeight+speedGraphBorder*2); + } + } + + width += 5; + height += 5; + width = width < DEFAULT_WINDOW_WIDTH ? DEFAULT_WINDOW_WIDTH : width; + height = height < DEFAULT_WINDOW_HEIGHT ? DEFAULT_WINDOW_HEIGHT : height; + if (cSize.GetWidth() != width || cSize.GetHeight() != height) { + GetParent()->SetClientSize(width, height); + } +} + +extern "C" +{ + int window_remember; + void wx_handle_command(void*, int, int); + + void resume_emulation(); + void pause_emulation(); + int stop_emulation_confirm(); + void reset_emulation(); + + void hdconf_open(void* hwnd); + void config_open(void* hwnd); +} + +int wx_window_x = 0; +int wx_window_y = 0; + +StatusFrame::StatusFrame(wxWindow* parent) : + wxFrame(parent, STATUS_WINDOW_ID, "PCem Machine", wxPoint(0, 0), wxSize(DEFAULT_WINDOW_WIDTH, 200), wxCAPTION | wxCLOSE_BOX) +{ + SetMenuBar(wxXmlResource::Get()->LoadMenuBar(wxT("status_menu"))); + SetToolBar(wxXmlResource::Get()->LoadToolBar(this, wxT("tool_bar"))); + + this->statusPane = new StatusPane(this); + wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(statusPane, 1, wxEXPAND); + SetSizer(sizer); + + Bind(wxEVT_MENU, &StatusFrame::OnCommand, this); + Bind(wxEVT_MOVE, &StatusFrame::OnMoveWindow, this); + + statusTimer = new StatusTimer(statusPane); + statusTimer->Start(); + + if (window_remember) + SetPosition(wxPoint(wx_window_x, wx_window_y)); + else + CenterOnScreen(); + + UpdateToolbar(); + GetMenuBar()->FindItem(XRCID("IDM_SHOW_STATUS"))->Check(show_status); + GetMenuBar()->FindItem(XRCID("IDM_SPEED_HISTORY"))->Check(show_speed_history); + GetMenuBar()->FindItem(XRCID("IDM_DISC_ACTIVITY"))->Check(show_disc_activity); + GetMenuBar()->FindItem(XRCID("IDM_MACHINE_MOUNT_PATHS"))->Check(show_mount_paths); + GetMenuBar()->FindItem(XRCID("IDM_SHOW_MACHINE_ON_START"))->Check(show_machine_on_start); +} + +StatusFrame::~StatusFrame() +{ + statusTimer->Stop(); + delete statusTimer; +} + +void StatusFrame::UpdateToolbar() +{ + GetToolBar()->EnableTool(XRCID("TOOLBAR_RUN"), emulation_state != EMULATION_RUNNING); + GetToolBar()->EnableTool(XRCID("TOOLBAR_PAUSE"), emulation_state != EMULATION_PAUSED); +} + +void StatusFrame::OnCommand(wxCommandEvent& event) +{ + if (event.GetId() == XRCID("TOOLBAR_RUN")) + { + resume_emulation(); + UpdateToolbar(); + } + else if (event.GetId() == XRCID("TOOLBAR_PAUSE")) + { + pause_emulation(); + UpdateToolbar(); + } + else if (event.GetId() == XRCID("TOOLBAR_RESET")) + { + int ret = wxID_OK; + if (confirm_on_reset_machine) + { + wxDialog dlg; + wxXmlResource::Get()->LoadDialog(&dlg, this, "ConfirmRememberDlg"); + dlg.FindWindow("IDC_CONFIRM_LABEL")->SetLabel("Reset machine?"); + dlg.FindWindow("IDC_CONFIRM_REMEMBER")->SetLabel("Do not ask again"); + dlg.Fit(); + ret = dlg.ShowModal(); + if (ret == wxID_OK) + confirm_on_reset_machine = !((wxCheckBox*)dlg.FindWindow("IDC_CONFIRM_REMEMBER"))->IsChecked(); + } + if (ret == wxID_OK) + { + reset_emulation(); + UpdateToolbar(); + } + } + else if (event.GetId() == XRCID("TOOLBAR_STOP")) + wx_stop_emulation(GetParent()); + else if (event.GetId() == XRCID("IDM_SHOW_STATUS")) + show_status = event.IsChecked(); + else if (event.GetId() == XRCID("IDM_SPEED_HISTORY")) + show_speed_history = event.IsChecked(); + else if (event.GetId() == XRCID("IDM_DISC_ACTIVITY")) + show_disc_activity = event.IsChecked(); + else if (event.GetId() == XRCID("IDM_MACHINE_MOUNT_PATHS")) + show_mount_paths = event.IsChecked(); + else if (event.GetId() == XRCID("IDM_SHOW_MACHINE_ON_START")) + show_machine_on_start = event.IsChecked(); +// else if (event.GetId() == XRCID("IDM_HDCONF")) +// hdconf_open(this); + else if (event.GetId() == XRCID("IDM_CONFIG")) + config_open(this); + else if (event.GetId() == XRCID("IDM_RESET_CONFIRMATION_DIALOGS")) + { + confirm_on_reset_machine = 1; + confirm_on_stop_emulation = 1; + wxMessageBox("Confirmation dialogs has been reset.", "PCem"); + } + else if (event.GetId() == XRCID("IDM_ABOUT")) + { + wxDialog dlg; + wxXmlResource::Get()->LoadDialog(&dlg, this, "AboutDlg"); + dlg.Fit(); + dlg.ShowModal(); + } + +} + +void StatusFrame::OnMoveWindow(wxMoveEvent& event) +{ + if (window_remember) { + wx_window_x = GetScreenPosition().x; + wx_window_y = GetScreenPosition().y; + } +} diff --git a/src/wx-status.h b/src/wx-status.h new file mode 100644 index 0000000..fd89f92 --- /dev/null +++ b/src/wx-status.h @@ -0,0 +1,70 @@ +#ifndef SRC_WX_STATUS_H_ +#define SRC_WX_STATUS_H_ + +#include +#include + +#define DEFAULT_WINDOW_WIDTH 350 +#define DEFAULT_WINDOW_HEIGHT 25 + +#define SPEED_HISTORY_LENGTH 240 + +class StatusPane; + +class StatusTimer : public wxTimer +{ +public: + StatusTimer(StatusPane* pane); + virtual ~StatusTimer() {}; + + void Notify(); + void Start(); +private: + StatusPane* pane; +}; + +class StatusPane : public wxPanel +{ + +public: + StatusPane(wxFrame* parent); + virtual ~StatusPane(); + + void PaintEvent(wxPaintEvent& evt); + void PaintNow(); + void Render( wxDC& dc ); + +private: + char machineInfoText[4096]; + char statusMachineText[4096]; + char statusDeviceText[4096]; + wxLongLong lastSpeedUpdate; + char speedHistory[SPEED_HISTORY_LENGTH]; + + wxBitmap bitmapFDD[2]; + wxBitmap bitmapCDROM[2]; + wxBitmap bitmapHDD[2]; + + DECLARE_EVENT_TABLE() +}; + +#define STATUS_WINDOW_ID 1000 + +class StatusFrame : public wxFrame { +public: + StatusFrame(wxWindow* parent); + virtual ~StatusFrame(); + void OnQuit(); +private: + void OnCommand(wxCommandEvent &event); + void OnMoveWindow(wxMoveEvent& event); + StatusPane* statusPane; + StatusTimer* statusTimer; + + void UpdateToolbar(); + + DECLARE_EVENT_TABLE() + +}; + +#endif /* SRC_WX_STATUS_H_ */ diff --git a/src/wx-thread.c b/src/wx-thread.c new file mode 100644 index 0000000..c3797f6 --- /dev/null +++ b/src/wx-thread.c @@ -0,0 +1,259 @@ +#include +#include +#include +#ifdef __APPLE__ +#include +#endif +#include "thread.h" +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#include +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); +} + +typedef struct win_mutex_t +{ + HANDLE handle; +} win_mutex_t; + +mutex_t *thread_create_mutex(void) +{ + win_mutex_t *mutex = malloc(sizeof(win_mutex_t)); + + mutex->handle = CreateSemaphore(NULL, 1, 1, NULL); + + return mutex; + +} + +void thread_lock_mutex(mutex_t *_mutex) +{ + win_mutex_t *mutex = (win_mutex_t *)_mutex; + + WaitForSingleObject(mutex->handle, INFINITE); +} + +void thread_unlock_mutex(mutex_t *_mutex) +{ + win_mutex_t *mutex = (win_mutex_t *)_mutex; + + ReleaseSemaphore(mutex->handle, 1, NULL); +} + +void thread_destroy_mutex(mutex_t *_mutex) +{ + win_mutex_t *mutex = (win_mutex_t *)_mutex; + + CloseHandle(mutex->handle); + + free(mutex); +} +#else +#include +#include + +typedef struct event_pthread_t +{ + pthread_cond_t cond; + pthread_mutex_t mutex; + int state; +} 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, (void*)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); + event->state = 0; + + return (event_t *)event; +} + +void thread_set_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_mutex_lock(&event->mutex); + event->state = 1; + pthread_cond_broadcast(&event->cond); + pthread_mutex_unlock(&event->mutex); +} + +void thread_reset_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_mutex_lock(&event->mutex); + event->state = 0; + pthread_mutex_unlock(&event->mutex); +} + +int thread_wait_event(event_t *handle, int timeout) +{ + event_pthread_t *event = (event_pthread_t *)handle; + struct timespec abstime; + +#ifdef __linux__ + clock_gettime(CLOCK_REALTIME, &abstime); +#else + struct timeval now; + gettimeofday(&now, 0); + abstime.tv_sec = now.tv_sec; + abstime.tv_nsec = now.tv_usec*1000UL; +#endif + 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); + if (timeout == -1) + { + while (!event->state) + pthread_cond_wait(&event->cond, &event->mutex); + } + else if (!event->state) + 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); +} + + +typedef struct pt_mutex_t +{ + pthread_mutex_t mutex; +} pt_mutex_t; + +mutex_t *thread_create_mutex(void) +{ + pt_mutex_t *mutex = malloc(sizeof(pt_mutex_t)); + + pthread_mutex_init(&mutex->mutex, NULL); + + return mutex; + +} + +void thread_lock_mutex(mutex_t *_mutex) +{ + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + pthread_mutex_lock(&mutex->mutex); +} + +void thread_unlock_mutex(mutex_t *_mutex) +{ + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + pthread_mutex_unlock(&mutex->mutex); +} + +void thread_destroy_mutex(mutex_t *_mutex) +{ + pt_mutex_t *mutex = (pt_mutex_t *)_mutex; + + pthread_mutex_destroy(&mutex->mutex); + + free(mutex); +} +#endif diff --git a/src/wx-utils.cc b/src/wx-utils.cc new file mode 100644 index 0000000..2facbea --- /dev/null +++ b/src/wx-utils.cc @@ -0,0 +1,829 @@ +#include "wx-utils.h" + +#include +#ifndef WX_PRECOMP +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wx-dialogbox.h" +#include "wx-app.h" +#include "wx-common.h" +#include "wx-status.h" + +extern "C" +{ +#include "thread.h" +} + +int confirm() +{ + if (emulation_state != EMULATION_STOPPED) { + return wx_messagebox(NULL, "This will reset PCem!\nOkay to continue?", "PCem", WX_MB_OKCANCEL) == WX_IDOK; + } + return 1; +} + +int wx_messagebox(void* window, const char* message, const char* title = NULL, int style = 5) +{ + return wxMessageBox(message, title, style | wxCENTRE | wxSTAY_ON_TOP, (wxWindow*) window); +} + +void wx_simple_messagebox(const char* title, const char *format, ...) +{ + char message[2048]; + va_list ap; + va_start(ap, format); + vsnprintf(message, 2047, format, ap); + message[2047] = 0; + va_end(ap); + wx_messagebox(0, message, title, WX_MB_OK); +} + + +int wx_textentrydialog(void* window, const char* message, const char* title, const char* value, unsigned int min_length, unsigned int max_length, LONG_PARAM result) +{ + while (1) + { + wxTextEntryDialog dlg((wxWindow*)window, message, title, value); + if (max_length > 0) + dlg.SetMaxLength(max_length); + if (dlg.ShowModal() == wxID_OK) + { + wxString value = dlg.GetValue(); + if (value.Length() >= min_length) + { + strcpy((char*)result, value.mb_str()); + return TRUE; + } + } + else + return FALSE; + } + return FALSE; +} + +void wx_setwindowtitle(void* window, char* s) +{ + ((wxFrame*) window)->SetTitle(s); +} + +int wx_xrcid(const char* s) +{ + return XRCID(s); +} + +int wx_filedialog(void* window, const char* title, const char* path, + const char* extensions, const char* extension, int open, char* file) +{ + wxFileDialog dlg((wxWindow*) window, title, "", path, extensions, + open ? (wxFD_OPEN | wxFD_FILE_MUST_EXIST) : (wxFD_SAVE | wxFD_OVERWRITE_PROMPT)); + if (dlg.ShowModal() == wxID_OK) + { + wxString p = dlg.GetPath(); + wxFileName f(p); + if (!open && !f.HasExt() && extension) + { + wxString e = extension; + if (!p.EndsWith(".")) + p += "."; + p += extension; + strcpy(file, p.mb_str()); + } + else + strcpy(file, p.mb_str()); + return 0; + } + return 1; +} + +void wx_checkmenuitem(void* menu, int id, int checked) +{ + wxMenuItem* item = NULL; + if (((wxObject*)menu)->GetClassInfo()->IsKindOf(CLASSINFO(wxMenuBar))) + item = ((wxMenuBar*) menu)->FindItem(id); + else + item = ((wxMenu*) menu)->FindItem(id); + + if (item) + item->Check(checked); +#ifndef RELEASE_BUILD + else + std::cout << "Menu item not found: " << id << std::endl; +#endif +} + +void wx_enablemenuitem(void* menu, int id, int enable) +{ + wxMenuItem* item = NULL; + if (((wxObject*)menu)->GetClassInfo()->IsKindOf(CLASSINFO(wxMenuBar))) + item = ((wxMenuBar*) menu)->FindItem(id); + else + item = ((wxMenu*) menu)->FindItem(id); + + if (item) + item->Enable(enable); +#ifndef RELEASE_BUILD + else + std::cout << "Menu item not found: " << id << std::endl; +#endif +} + +void* wx_getsubmenu(void* menu, int id) +{ + wxMenuItem* m = ((wxMenu*) menu)->FindItem(id); + if (m) + return m->GetSubMenu(); + + return 0; +} + +void* wx_getnativemenu(void* menu) +{ +#ifdef _WIN32 + return ((wxMenu*)menu)->GetHMenu(); +#endif + return 0; +} + +void* wx_getnativewindow(void* window) +{ +#ifdef _WIN32 + return ((wxWindow*)window)->GetHWND(); +#endif + return 0; +} + +#ifdef _WIN32 +void wx_winsendmessage(void* window, int msg, INT_PARAM wParam, LONG_PARAM lParam) +{ + WinSendMessageEvent* event = new WinSendMessageEvent(wx_getnativewindow(window), msg, wParam, lParam); + wxQueueEvent((wxWindow*)window, event); +} +#endif + +void wx_appendmenu(void* sub_menu, int id, const char* title, enum wxItemKind type) +{ + ((wxMenu*) sub_menu)->Append(id, title, wxEmptyString, type); +} + + +void wx_enabletoolbaritem(void* toolbar, int id, int enable) +{ + ((wxToolBar*) toolbar)->EnableTool(id, enable); +} + +void* wx_getmenu(void* window) +{ + return ((Frame*) window)->GetMenu(); +} + +void* wx_getmenubar(void* window) +{ + return ((wxFrame*) window)->GetMenuBar(); +} + +void* wx_gettoolbar(void* window) +{ + return ((wxFrame*) window)->GetToolBar(); +} + +void* wx_getdlgitem(void* window, int id) +{ + return ((wxWindow*) window)->FindWindow(id); +} + +void wx_setdlgitemtext(void* window, int id, char* str) +{ + wxWindow* w = ((wxWindow*) window)->FindWindow(id); + if (w->GetClassInfo()->IsKindOf(CLASSINFO(wxTextCtrl))) + ((wxTextCtrl*) w)->SetValue(str); + else + ((wxStaticText*) w)->SetLabel(str); +} + +void wx_enablewindow(void* window, int enabled) +{ + ((wxWindow*) window)->Enable(enabled); +} + +void wx_showwindow(void* window, int show) +{ + wxCommandEvent* event = new wxCommandEvent(WX_SHOW_WINDOW_EVENT, wxID_ANY); + event->SetEventObject((wxWindow*)window); + event->SetInt(show); + wxQueueEvent((wxWindow*)window, event); +} + +int wx_iswindowvisible(void* window) +{ + return ((wxWindow*) window)->IsShown(); +} + +void wx_togglewindow(void* window) +{ + wx_showwindow(window, -1); +} + +void wx_callback(void* window, WX_CALLBACK callback, void* data) +{ + CallbackEvent* event = new CallbackEvent(callback, data); + wxQueueEvent((wxWindow*)window, event); +} + +void wx_enddialog(void* window, int ret_code) +{ + ((wxDialog*) window)->EndModal(ret_code); +} + +int wx_dlgdirlist(void* window, const char* path, int id, int static_path, int file_type) +{ + wxWindow* w = ((wxWindow*) window)->FindWindow(id); + if (w->GetClassInfo()->IsKindOf(CLASSINFO(wxListBox))) + { + wxListBox* list = (wxListBox*)w; + list->Clear(); + wxArrayString items; + wxString f = wxFindFirstFile(path); + while (!f.empty()) + { + wxFileName file(f); + items.Add(file.GetName()); + f = wxFindNextFile(); + } + items.Sort(); + list->Set(items); + return TRUE; + } + return FALSE; +} + +int wx_dlgdirselectex(void* window, LONG_PARAM path, int count, int id) +{ + wxWindow* w = ((wxWindow*) window)->FindWindow(id); + if (w->GetClassInfo()->IsKindOf(CLASSINFO(wxListBox))) + { + wxListBox* list = (wxListBox*)w; + strcpy((char*)path, (list->GetStringSelection() + ".").GetData().AsChar()); + return TRUE; + } + return FALSE; +} + +int wx_sendmessage(void* window, int type, LONG_PARAM param1, LONG_PARAM param2) +{ + switch (type) + { + case WX_CB_ADDSTRING: + ((wxComboBox*) window)->Append((char*) param2); + break; + case WX_CB_SETCURSEL: + if (param1 >= 0 && param1 < (int)((wxComboBox*) window)->GetCount()) + ((wxComboBox*) window)->Select(param1); + break; + case WX_CB_GETCURSEL: + return ((wxComboBox*) window)->GetCurrentSelection(); + break; + case WX_CB_GETLBTEXT: + strcpy((char*) param2, ((wxComboBox*) window)->GetString(param1).mb_str()); + break; + case WX_CB_RESETCONTENT: + { +#ifndef __WXOSX_MAC__ + ((wxComboBox*) window)->SetValue(""); + ((wxComboBox*) window)->Clear(); +#else + /* Clear() does not work on OSX */ + wxComboBox* cb = (wxComboBox*) window; + int count = cb->GetCount(); + while (count--) + cb->Delete(0); +#endif + break; + } + case WX_BM_SETCHECK: + ((wxCheckBox*) window)->SetValue(param1); + break; + case WX_BM_GETCHECK: + return ((wxCheckBox*) window)->GetValue(); + break; + case WX_WM_SETTEXT: + { + if (((wxWindow*) window)->GetClassInfo()->IsKindOf(CLASSINFO(wxTextCtrl))) + ((wxTextCtrl*) window)->SetValue((char*) param2); + else + ((wxStaticText*) window)->SetLabel((char*) param2); + } + break; + case WX_WM_GETTEXT: + if (((wxWindow*) window)->GetClassInfo()->IsKindOf(CLASSINFO(wxTextCtrl))) + strcpy((char*) param2, ((wxTextCtrl*) window)->GetValue().mb_str()); + else + strcpy((char*) param2, ((wxStaticText*) window)->GetLabel().mb_str()); + break; + case WX_UDM_SETPOS: + ((wxSpinCtrl*) window)->SetValue(param2); + break; + case WX_UDM_GETPOS: + return ((wxSpinCtrl*) window)->GetValue(); + case WX_UDM_SETRANGE: + { + int min = (param2 >> 16) & 0xffff; + int max = param2 & 0xffff; + ((wxSpinCtrl*) window)->SetRange(min, max); + break; + } + case WX_UDM_SETINCR: + { + /* SetIncrement-method may not exist on all platforms */ +#ifdef __WXGTK__ + ((wxSpinCtrl*) window)->SetIncrement(param2); +#endif + break; + } + case WX_LB_GETCOUNT: + { + return ((wxListBox*) window)->GetCount(); + } + case WX_LB_GETCURSEL: + { + return ((wxListBox*) window)->GetSelection(); + } + case WX_LB_SETCURSEL: + { + ((wxListBox*) window)->SetSelection(param1); + break; + } + case WX_LB_GETTEXT: + { + strcpy((char*) param2, ((wxListBox*) window)->GetString(param1).mb_str()); + break; + } + case WX_LB_INSERTSTRING: + { + ((wxListBox*) window)->Insert((char*) param2, param1); + break; + } + case WX_LB_DELETESTRING: + { + ((wxListBox*) window)->Delete(param1); + break; + } + case WX_LB_RESETCONTENT: + { + ((wxListBox*) window)->Clear(); + break; + } + case WX_CHB_SETPAGETEXT: + { + ((wxChoicebook*)window)->SetPageText(param1, (char *)param2); + break; + } + case WX_CHB_ADDPAGE: + { + ((wxChoicebook*)window)->AddPage((wxWindow *)param1, (char *)param2); + break; + } + case WX_CHB_REMOVEPAGE: + { + ((wxChoicebook*)window)->RemovePage(param1); + break; + } + case WX_CHB_GETPAGECOUNT: + { + return ((wxChoicebook*)window)->GetPageCount(); + } + case WX_REPARENT: + { + ((wxWindow *)window)->Reparent((wxWindow *)param1); + break; + } + case WX_WM_ENABLE: + { + ((wxWindow*)window)->Enable((bool)param2); + break; + } + case WX_WM_SHOW: + { + ((wxWindow*)window)->Show((bool)param2); + break; + } + case WX_WM_LAYOUT: + { + ((wxWindow*)window)->Layout(); + break; + } + } + + ((wxWindow*)window)->Fit(); + + return 0; +} + +int wx_dialogbox(void* window, const char* name, int (*callback)(void* window, int message, INT_PARAM param1, LONG_PARAM param2)) +{ + PCemDialogBox dlg((wxWindow*) window, name, callback); + dlg.OnInit(); + dlg.Fit(); + int ret = dlg.ShowModal(); + dlg.Destroy(); + return ret; +} + +void wx_exit(void* window, int value) +{ + wxCommandEvent* event = new wxCommandEvent(WX_EXIT_EVENT, wxID_ANY); + event->SetEventObject((wxWindow*)window); + event->SetInt(value); + wxQueueEvent((wxWindow*)window, event); +} + +void wx_stop_emulation(void* window) +{ + wxCommandEvent* event = new wxCommandEvent(WX_STOP_EMULATION_EVENT, wxID_ANY); + event->SetEventObject((wxWindow*)window); + wxQueueEvent((wxWindow*)window, event); +} + +void wx_stop_emulation_now(void* window) +{ + wxCommandEvent* event = new wxCommandEvent(WX_STOP_EMULATION_NOW_EVENT, wxID_ANY); + event->SetEventObject((wxWindow*)window); + wxQueueEvent((wxWindow*)window, event); +} + +int wx_yield() +{ + return wxYield(); +} + +/* Timer stuff */ + +class PCemTimer : public wxTimer +{ +public: + PCemTimer(void (*fn)()) + { + this->fn = fn; + } + virtual ~PCemTimer() {}; + + void Notify() + { + fn(); + } +private: + void (*fn)(); +}; + +void* wx_createtimer(void (*fn)()) +{ + return new PCemTimer(fn); +} + +void wx_starttimer(void* timer, int milliseconds, int once) +{ + wxTimer* t = (wxTimer*)timer; + t->Start(milliseconds, once); +} + +void wx_stoptimer(void* timer) +{ + wxTimer* t = (wxTimer*)timer; + t->Stop(); +} + +void wx_destroytimer(void* timer) +{ + wx_stoptimer(timer); + delete (wxTimer*)timer; +} + +void wx_popupmenu(void* window, void* menu, int* x, int* y) +{ + PopupMenuEvent* event = new PopupMenuEvent((wxWindow*)window, (wxMenu*)menu, x, y); + wxQueueEvent((wxWindow*)window, event); +} + +void* wx_create_status_frame(void* window) +{ + StatusFrame* frame = new StatusFrame((wxWindow*)window); + return frame; +} + +void wx_destroy_status_frame(void* window) +{ + StatusFrame* frame = (StatusFrame*)window; + delete frame; +} + +void wx_setwindowposition(void* window, int x, int y) +{ + ((wxFrame*) window)->SetPosition(wxPoint(x, y)); +} + +void wx_setwindowsize(void* window, int width, int height) +{ + ((wxFrame*) window)->SetSize(wxSize(width, height)); +} + +void wx_show_status(void* window) +{ + wxWindow* status = ((wxWindow*)window)->FindWindowById(STATUS_WINDOW_ID); + if (!status) + { + StatusFrame* statusFrame = new StatusFrame((wxWindow*) window); + statusFrame->Show(); + } +} + +void wx_close_status(void* window) +{ + wxWindow* status = ((wxWindow*)window)->FindWindowById(STATUS_WINDOW_ID); + if (status) + { + status->Close(); + } +} + +void wx_get_home_directory(char* path) +{ + wxString home = wxFileName::GetHomeDir(); + if (!home.EndsWith(wxFileName::GetPathSeparator())) { + home.Append(wxFileName::GetPathSeparator()); + } + strcpy(path, home.mb_str()); +} + +int wx_create_directory(char* path) +{ + return wxFileName::Mkdir(path); +} + +int wx_setup(char* path) +{ + wxFileName p(path); + if (!p.DirExists()) + { + if (!p.Mkdir()) + return FALSE; + wxFileName configs(p); + configs.AppendDir("configs"); + if (!configs.DirExists() && !configs.Mkdir()) + return FALSE; + + wxFileName roms(p); + roms.AppendDir("roms"); + if (!roms.DirExists() && !roms.Mkdir()) + return FALSE; + + wxFileName nvr(p); + nvr.AppendDir("nvr"); + if (!nvr.DirExists() && !nvr.Mkdir()) + return FALSE; + + wxFileName screenshots(p); + screenshots.AppendDir("screenshots"); + if (!screenshots.DirExists() && !screenshots.Mkdir()) + return FALSE; + + wxFileName logs(p); + logs.AppendDir("logs"); + if (!logs.DirExists() && !logs.Mkdir()) + return FALSE; + } + + return TRUE; +} + +int wx_file_exists(char* path) +{ + wxFileName p(path); + return p.Exists(); +} + +int wx_dir_exists(char* path) +{ + wxFileName p(path); + return p.DirExists(); +} + +int wx_copy_file(char* from, char* to, int overwrite) +{ + return wxCopyFile(from, to, overwrite); +} + +int wx_image_save(const char* path, const char* name, const char* format, unsigned char* rgba, int width, int height, int alpha) +{ + int x, y; + wxLogNull logNull; + wxImage image(width, height); + if (alpha) + { + unsigned char* rgb = (unsigned char*)malloc(width*height*3); + unsigned char* a = (unsigned char*)malloc(width*height); + for (x = 0; x < width; ++x) + { + for (y = 0; y < height; ++y) + { + rgb[(y*width+x)*3+0] = rgba[(y*width+x)*4+0]; + rgb[(y*width+x)*3+1] = rgba[(y*width+x)*4+1]; + rgb[(y*width+x)*3+2] = rgba[(y*width+x)*4+2]; + a[y*width+x] = rgba[(y*width+x)*4+3]; + } + } + image.SetData(rgb); + image.SetAlpha(a); + } + else + image.SetData(rgba, true); + + wxImageHandler* h; + wxString ext; + + if (!strcmp(format, IMAGE_TIFF)) + { + h = new wxTIFFHandler(); + ext = "tif"; + } + else if (!strcmp(format, IMAGE_BMP)) + { + h = new wxBMPHandler(); + ext = "bmp"; + } + else if (!strcmp(format, IMAGE_JPG)) + { + h = new wxJPEGHandler(); + ext = "jpg"; + } + else + { + h = new wxPNGHandler(); + ext = "png"; + } + + int res = 0; + if (h) + { + wxString p(path); + if (!p.EndsWith("/")) + p = p.Append("/"); + p = p.Append(name).Append(".").Append(ext); + + wxFileOutputStream stream(p); + res = h->SaveFile(&image, stream, false); + delete h; + } + + return res; +} + +void* wx_image_load(const char* path) +{ + wxLogNull logNull; /* removes sRGB-warnings on Windows */ + wxImage* image = new wxImage(path); + if (image->IsOk()) + return image; + delete image; + return 0; +} + +void wx_image_free(void* image) +{ + delete (wxImage*)image; +} + +void wx_image_rescale(void* image, int width, int height) +{ + ((wxImage*)image)->Rescale(width, height); +} + +void wx_image_get_size(void* image, int* width, int* height) +{ + *width = ((wxImage*)image)->GetWidth(); + *height = ((wxImage*)image)->GetHeight(); +} + +unsigned char* wx_image_get_data(void* image) +{ + return ((wxImage*)image)->GetData(); +} + +unsigned char* wx_image_get_alpha(void* image) +{ + return ((wxImage*)image)->GetAlpha(); +} + +/* wxFileConfig */ + +void* wx_config_load(const char* path) +{ + if (!wxFileExists(path)) + return 0; + wxFileInputStream stream(path); + if (stream.IsOk()) + return new wxFileConfig(stream); + return 0; +} +int wx_config_get_string(void* config, const char* name, char* dst, int size, const char* defVal) +{ + wxFileConfig* c = ((wxFileConfig*)config); + wxString val; + bool res = c->Read(name, &val, wxString(defVal)); + strncpy(dst, val.GetData().AsChar(), size-1); + dst[size-1] = 0; + return res; +} +int wx_config_get_int(void* config, const char* name, int* dst, int defVal) +{ + wxFileConfig* c = ((wxFileConfig*)config); + return c->Read(name, dst, defVal); +} + +int wx_config_get_float(void* config, const char* name, float* dst, float defVal) +{ + wxFileConfig* c = ((wxFileConfig*)config); + return c->Read(name, dst, defVal); + +} + +int wx_config_get_bool(void* config, const char* name, int* dst, int defVal) +{ + wxFileConfig* c = ((wxFileConfig*)config); + wxString val; + bool res = 1; + if (c->Read(name, &val)) + { + val.LowerCase(); + if (val.StartsWith("true")) + *dst = 1; + else if (val.StartsWith("false")) + *dst = 0; + else + res = 0; + } + if (!res) + res = c->Read(name, (bool*)dst, (bool)defVal); + + return res; +} + +int wx_config_has_entry(void* config, const char* name) +{ + wxFileConfig* c = ((wxFileConfig*)config); + return c->HasEntry(name); +} + +void wx_config_free(void* config) +{ + delete (wxFileConfig*)config; +} + +typedef struct progress_data_t { + WX_CALLBACK callback; + void* data; + int active; + int result; +} progress_data_t; + +static void progress_callback(void* data) +{ + progress_data_t* d = (progress_data_t*) data; + d->result = d->callback(d->data); + d->active = 0; +} + +int wx_progressdialog(void* window, const char* title, const char* message, WX_CALLBACK callback, void* data, int range, volatile int *pos) +{ + struct progress_data_t pdata; + pdata.callback = callback; + pdata.data = data; + pdata.active = 1; + pdata.result = 0; + + thread_t* t = thread_create(progress_callback, &pdata); + + wxProgressDialog dlg(title, message, range, (wxWindow*)window, wxPD_APP_MODAL | wxPD_SMOOTH | wxPD_AUTO_HIDE); + while (pdata.active) + { + dlg.Update(*pos); + wxMilliSleep(50); + } + thread_kill(t); + + return pdata.result; +} + +void wx_date_format(char* s, const char* format) +{ + wxString res = wxDateTime::Now().Format(format); + strcpy(s, res.mb_str()); +} diff --git a/src/wx-utils.h b/src/wx-utils.h new file mode 100644 index 0000000..0b12970 --- /dev/null +++ b/src/wx-utils.h @@ -0,0 +1,174 @@ +#include + +#ifndef LONG_PARAM +#define LONG_PARAM wxIntPtr +#endif + +#ifndef INT_PARAM +#define INT_PARAM wxInt32 +#endif + +typedef int (*WX_CALLBACK)(void* data); + +#ifdef __cplusplus +extern "C" { +#endif + int wx_messagebox(void* nothing, const char* message, const char* title, int style); + void wx_simple_messagebox(const char* title, const char *format, ...); + + int wx_xrcid(const char* s); + int wx_filedialog(void* window, const char* title, const char* path, const char* extensions, const char* extension, int open, char* file); + void wx_checkmenuitem(void* window, int id, int checked); + void wx_enablemenuitem(void* menu, int id, int enable); + void* wx_getmenu(void* window); + void* wx_getmenubar(void* window); + void wx_enabletoolbaritem(void* toolbar, int id, int enable); + void* wx_gettoolbar(void* window); + + void* wx_getsubmenu(void* window, int id); + void wx_appendmenu(void* sub_menu, int id, const char* title, enum wxItemKind type); + void* wx_getnativemenu(void* menu); + + int wx_textentrydialog(void* window, const char* message, const char* title, const char* value, unsigned int min_length, unsigned int max_length, LONG_PARAM result); + + int wx_dlgdirlist(void* window, const char* path, int id, int static_path, int file_type); + int wx_dlgdirselectex(void* window, LONG_PARAM path, int count, int id); + + void wx_setwindowtitle(void* window, char* s); + int wx_sendmessage(void* window, int type, LONG_PARAM param1, LONG_PARAM param2); + void* wx_getdlgitem(void* window, int id); + void wx_setdlgitemtext(void* window, int id, char* str); + void wx_enablewindow(void* window, int enabled); + void wx_showwindow(void* window, int show); + int wx_iswindowvisible(void* window); + void* wx_getnativewindow(void* window); + void wx_callback(void* window, WX_CALLBACK callback, void* data); + void wx_togglewindow(void* window); + int wx_progressdialog(void* window, const char* title, const char* message, WX_CALLBACK callback, void* data, int range, volatile int *pos); + + void wx_enddialog(void* window, int ret_code); + + int wx_dialogbox(void* window, const char* name, int(*callback)(void* window, int message, INT_PARAM param1, LONG_PARAM param2)); + + void wx_exit(void* window, int value); + void wx_stop_emulation(void* window); + void wx_stop_emulation_now(void* window); + + void* wx_createtimer(void (*fn)()); + void wx_starttimer(void* timer, int milliseconds, int once); + void wx_stoptimer(void* timer); + void wx_destroytimer(void* timer); + + void wx_popupmenu(void* window, void* menu, int* x, int* y); + + void* wx_create_status_frame(void* window); + void wx_destroy_status_frame(void* window); + + int wx_yield(); + + void wx_setwindowposition(void* window, int x, int y); + void wx_setwindowsize(void* window, int width, int height); + + void wx_show_status(void* window); + void wx_close_status(void* window); + + void wx_get_home_directory(char* path); + int wx_create_directory(char* path); + + int wx_setup(char* path); + int wx_file_exists(char* path); + int wx_dir_exists(char* path); + int wx_copy_file(char* from, char* to, int overwrite); + + void wx_date_format(char* s, const char* format); + + int wx_image_save(const char* path, const char* name, const char* format, unsigned char* rgba, int width, int height, int alpha); + + void* wx_image_load(const char* path); + void wx_image_rescale(void* image, int width, int height); + void wx_image_get_size(void* image, int* width, int* height); + unsigned char* wx_image_get_data(void* image); + unsigned char* wx_image_get_alpha(void* image); + void wx_image_free(void* image); + + void* wx_config_load(const char* path); + int wx_config_get_string(void* config, const char* name, char* dst, int size, const char* defVal); + int wx_config_get_int(void* config, const char* name, int* dst, int defVal); + int wx_config_get_float(void* config, const char* name, float* dst, float defVal); + int wx_config_get_bool(void* config, const char* name, int* dst, int defVal); + int wx_config_has_entry(void* config, const char* name); + void wx_config_free(void* config); + + int confirm(); + +#ifdef _WIN32 + void wx_winsendmessage(void* window, int msg, INT_PARAM wParam, LONG_PARAM lParam); +#endif +#ifdef __cplusplus +} +#endif + +extern int (*wx_keydown_func)(void* window, void* event, int keycode, int modifiers); +extern int (*wx_keyup_func)(void* window, void* event, int keycode, int modifiers); +extern void (*wx_idle_func)(void* window, void* event); + +#define WX_ID wx_xrcid + +#define WX_MB_CHECKED 1 +#define WX_MB_UNCHECKED 0 + +#define WX_INITDIALOG 1 +#define WX_COMMAND 2 + +#define WX_CB_ADDSTRING 1 +#define WX_CB_SETCURSEL 2 +#define WX_CB_GETCURSEL 3 +#define WX_CB_RESETCONTENT 4 +#define WX_CB_GETLBTEXT 5 + +#define WX_BM_SETCHECK 20 +#define WX_BM_GETCHECK 21 + +#define WX_WM_SETTEXT 40 +#define WX_WM_GETTEXT 41 + +#define WX_UDM_SETPOS 50 +#define WX_UDM_GETPOS 51 +#define WX_UDM_SETINCR 52 +#define WX_UDM_SETRANGE 53 + +#define WX_LB_GETCOUNT 60 +#define WX_LB_GETCURSEL 61 +#define WX_LB_GETTEXT 62 +#define WX_LB_DELETESTRING 63 +#define WX_LB_INSERTSTRING 64 +#define WX_LB_RESETCONTENT 65 +#define WX_LB_SETCURSEL 66 +#define WX_LBN_DBLCLK 67 + +#define WX_CHB_SETPAGETEXT 68 +#define WX_CHB_ADDPAGE 69 +#define WX_CHB_REMOVEPAGE 70 +#define WX_CHB_GETPAGECOUNT 71 + +#define WX_REPARENT 72 + +#define WX_WM_ENABLE 80 +#define WX_WM_SHOW 81 +#define WX_WM_LAYOUT 82 + +#define WX_MB_YES wxYES +#define WX_MB_OK wxOK +#define WX_MB_OKCANCEL wxOK|wxCANCEL +#define WX_MB_NODEFAULT wxYES_NO|wxNO_DEFAULT +#define WX_IDOK wxOK + +#define IMAGE_JPG "jpg" +#define IMAGE_PNG "png" +#define IMAGE_BMP "bmp" +#define IMAGE_TIFF "tiff" + +extern int has_been_inited; + +#define ID_IS(s) wParam == wx_xrcid(s) +#define ID_RANGE(a, b) wParam >= wx_xrcid(a) && wParam <= wx_xrcid(b) diff --git a/src/wx.rc b/src/wx.rc new file mode 100644 index 0000000..20db40e --- /dev/null +++ b/src/wx.rc @@ -0,0 +1 @@ +#include "wx/msw/wx.rc" \ No newline at end of file diff --git a/src/x86.h b/src/x86.h index dc60e05..f0f2238 100644 --- a/src/x86.h +++ b/src/x86.h @@ -1,23 +1,234 @@ -uint16_t oldcs; -extern uint32_t rmdat32; -int oldcpl; +#ifndef _X86_H_ +#define _X86_H_ + +#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; + +typedef struct +{ + uint32_t base; + uint32_t limit, limit_raw; + uint8_t access, access2; + uint16_t seg; + uint32_t limit_low, limit_high; + int checked; /*Non-zero if selector is known to be valid*/ +} x86seg; + +typedef union MMX_REG +{ + uint64_t q; + int64_t sq; + uint32_t l[2]; + int32_t sl[2]; + uint16_t w[4]; + int16_t sw[4]; + uint8_t b[8]; + int8_t sb[8]; + float f[2]; +} MMX_REG; + +struct +{ + x86reg regs[8]; + + uint8_t tag[8]; + + x86seg *ea_seg; + uint32_t eaaddr; + + int flags_op; + uint32_t flags_res; + uint32_t flags_op1, flags_op2; + + uint32_t pc; + uint32_t oldpc; + uint32_t op32; + + int TOP; + + union + { + struct + { + int8_t rm, mod, reg; + } rm_mod_reg; + uint32_t rm_mod_reg_data; + } rm_data; + + int8_t ssegs; + int8_t ismmx; + int8_t abrt; + int8_t smi_pending; + + int _cycles; + int cpu_recomp_ins; + + uint16_t npxs, npxc; + + double ST[8]; + + uint16_t MM_w4[8]; + + MMX_REG MM[8]; + + uint32_t old_fp_control, new_fp_control; +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ + uint16_t old_fp_control2, new_fp_control2; +#endif +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined __amd64__ + uint32_t trunc_fp_control; +#endif + x86seg seg_cs,seg_ds,seg_es,seg_ss,seg_fs,seg_gs; + + union + { + uint32_t l; + uint16_t w; + } CR0; + + uint16_t flags, eflags; + + uint32_t smbase; +} cpu_state; + +#define cpu_state_offset(MEMBER) ((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128) + +#define cycles cpu_state._cycles +extern int cycles_main; + +#define cr0 cpu_state.CR0.l +#define msw cpu_state.CR0.w + +/*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*/ +#define CS cpu_state.seg_cs.seg +#define DS cpu_state.seg_ds.seg +#define ES cpu_state.seg_es.seg +#define SS cpu_state.seg_ss.seg +#define FS cpu_state.seg_fs.seg +#define GS cpu_state.seg_gs.seg +#define cs cpu_state.seg_cs.base +#define ds cpu_state.seg_ds.base +#define es cpu_state.seg_es.base +#define ss cpu_state.seg_ss.base +//#define seg_fs _fs.base +#define gs cpu_state.seg_gs.base + +#define CPL ((cpu_state.seg_cs.access>>5)&3) + +#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 VIF_FLAG 0x0008 /*In EFLAGS*/ +#define VIP_FLAG 0x0010 /*In EFLAGS*/ + +#define WP_FLAG 0x10000 /*In CR0*/ + +#define CR4_VME (1 << 0) +#define CR4_PVI (1 << 1) +#define CR4_PSE (1 << 4) + +#define IOPL ((cpu_state.flags >> 12) & 3) + +#define IOPLp ((!(msw&1)) || (CPL<=IOPL)) + +extern x86seg gdt, ldt, idt, tr; + +extern uint32_t cr2, cr3, cr4; +extern uint32_t dr[8]; + +extern uint16_t sysenter_cs; +extern uint32_t sysenter_eip, sysenter_esp; + + +extern uint16_t cpu_cur_status; + +/*The flags below must match in both cpu_cur_status and block->status for a block + to be valid*/ +#define CPU_STATUS_USE32 (1 << 0) +#define CPU_STATUS_STACK32 (1 << 1) +#define CPU_STATUS_PMODE (1 << 2) +#define CPU_STATUS_V86 (1 << 3) +#define CPU_STATUS_SMM (1 << 4) +#define CPU_STATUS_FLAGS 0xff + +/*If the flags below are set in cpu_cur_status, they must be set in block->status. + Otherwise they are ignored*/ +#define CPU_STATUS_NOTFLATDS (1 << 8) +#define CPU_STATUS_NOTFLATSS (1 << 9) +#define CPU_STATUS_MASK 0xff00 + + +extern uint32_t rmdat; +#define fetchdat rmdat + +extern uint32_t easeg; +extern uint32_t *eal_r, *eal_w; + +extern int oldcpl; +extern uint32_t oldss; extern int nmi_enable; -int tempc; -int output; -int firstrepcycle; +extern int trap; -uint32_t easeg,ealimit,ealimitw; +extern uint32_t use32; +extern int stack32; -int skipnextprint; -int inhlt; +extern uint8_t znptable8[256]; +extern uint16_t *mod1add[2][8]; +extern uint32_t *mod1seg[8]; -uint8_t opcode; -int noint; +extern int cgate16, cgate32; +extern int cpl_override; -uint16_t lastcs,lastpc; -int timetolive,keyboardtimer; +extern int x86_was_reset; + +extern int insc; +extern int fpucount; +extern float mips,flops; #define setznp168 setznp16 @@ -30,12 +241,6 @@ int timetolive,keyboardtimer; #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; \ @@ -43,34 +248,12 @@ int stack32; if (mod!=3) fetcheal(); } -int optype; +extern 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 { @@ -83,25 +266,31 @@ enum ABRT_PF = 0xE }; +#define ABRT_MASK 0x7f +/*An 'expected' exception is one that would be expected to occur on every execution + of this code path; eg a GPF due to being in v86 mode. An 'unexpected' exception is + one that would be unlikely to occur on the next exception, eg a page fault may be + fixed up by the exception handler and the next execution would not hit it. + + This distinction is used by the dynarec; a block that hits an 'expected' exception + would be compiled, a block that hits an 'unexpected' exception would be rejected so + that we don't end up with an unnecessarily short block*/ +#define ABRT_EXPECTED 0x80 extern uint32_t abrt_error; void x86_doabrt(int x86_abrt); -extern uint8_t opcode2; +extern int codegen_flat_ds; +extern int codegen_flat_ss; -extern uint16_t rds; -extern uint32_t rmdat32; - -extern int inscounts[256]; +extern uint32_t pccache; +extern uint8_t *pccache2; void x86illegal(); void x86seg_reset(); void x86gpf(char *s, uint16_t error); - -extern uint16_t zero; - -extern int x86_was_reset; +void x86gpf_expected(char *s, uint16_t error); void resetx86(); void softresetx86(); @@ -111,3 +300,45 @@ void dumpregs(); void execx86(int cycs); void exec386(int cycs); void exec386_dynarec(int cycs); + +void pmodeint(int num, int soft); +int loadseg(uint16_t seg, x86seg *s); +void loadcs(uint16_t seg); +void loadcscall(uint16_t seg, uint32_t old_pc); +void loadcsjmp(uint16_t seg, uint32_t old_pc); +void pmoderetf(int is32, uint16_t off); +void pmodeiret(int is32); + +void x86_int(int num); +void x86_int_sw(int num); +int x86_int_sw_rm(int num); + +void sysenter(void); +void sysexit(void); + +int divl(uint32_t val); +int idivl(int32_t val); + +extern int cpu_end_block_after_ins; + +void x86_smi_trigger(void); +void x86_smi_enter(void); +void x86_smi_leave(void); + +void cyrix_load_seg_descriptor(uint32_t addr, x86seg *seg); +void cyrix_write_seg_descriptor(uint32_t addr, x86seg *seg); + +#define SMHR_VALID (1 << 0) +#define SMHR_ADDR_MASK (0xfffffffc) + +struct +{ + struct + { + uint32_t base; + uint64_t size; + } arr[8]; + uint32_t smhr; +} cyrix; + +#endif diff --git a/src/x86_flags.h b/src/x86_flags.h index 3fa9cc5..49170f3 100644 --- a/src/x86_flags.h +++ b/src/x86_flags.h @@ -1,3 +1,5 @@ +extern int tempc; + enum { FLAGS_UNKNOWN, @@ -26,6 +28,14 @@ enum FLAGS_SAR16, FLAGS_SAR32, + FLAGS_ROL8, + FLAGS_ROL16, + FLAGS_ROL32, + + FLAGS_ROR8, + FLAGS_ROR16, + FLAGS_ROR32, + FLAGS_INC8, FLAGS_INC16, FLAGS_INC32, @@ -33,6 +43,14 @@ enum FLAGS_DEC8, FLAGS_DEC16, FLAGS_DEC32, + + FLAGS_ADC8, + FLAGS_ADC16, + FLAGS_ADC32, + + FLAGS_SBC8, + FLAGS_SBC16, + FLAGS_SBC32 }; static inline int ZF_SET() @@ -63,10 +81,22 @@ static inline int ZF_SET() case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: + case FLAGS_ADC8: + case FLAGS_ADC16: + case FLAGS_ADC32: + case FLAGS_SBC8: + case FLAGS_SBC16: + case FLAGS_SBC32: return !cpu_state.flags_res; + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + case FLAGS_ROR8: + case FLAGS_ROR16: + case FLAGS_ROR32: case FLAGS_UNKNOWN: - return flags & Z_FLAG; + return cpu_state.flags & Z_FLAG; } return 0; } @@ -83,6 +113,8 @@ static inline int NF_SET() case FLAGS_SAR8: case FLAGS_INC8: case FLAGS_DEC8: + case FLAGS_ADC8: + case FLAGS_SBC8: return cpu_state.flags_res & 0x80; case FLAGS_ZN16: @@ -93,6 +125,8 @@ static inline int NF_SET() case FLAGS_SAR16: case FLAGS_INC16: case FLAGS_DEC16: + case FLAGS_ADC16: + case FLAGS_SBC16: return cpu_state.flags_res & 0x8000; case FLAGS_ZN32: @@ -103,10 +137,18 @@ static inline int NF_SET() case FLAGS_SAR32: case FLAGS_INC32: case FLAGS_DEC32: + case FLAGS_ADC32: + case FLAGS_SBC32: return cpu_state.flags_res & 0x80000000; + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + case FLAGS_ROR8: + case FLAGS_ROR16: + case FLAGS_ROR32: case FLAGS_UNKNOWN: - return flags & N_FLAG; + return cpu_state.flags & N_FLAG; } return 0; } @@ -139,10 +181,22 @@ static inline int PF_SET() case FLAGS_DEC8: case FLAGS_DEC16: case FLAGS_DEC32: + case FLAGS_ADC8: + case FLAGS_ADC16: + case FLAGS_ADC32: + case FLAGS_SBC8: + case FLAGS_SBC16: + case FLAGS_SBC32: return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + case FLAGS_ROR8: + case FLAGS_ROR16: + case FLAGS_ROR32: case FLAGS_UNKNOWN: - return flags & P_FLAG; + return cpu_state.flags & P_FLAG; } return 0; } @@ -159,22 +213,28 @@ static inline int VF_SET() case FLAGS_SAR32: return 0; + case FLAGS_ADC8: 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_ADC16: 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_ADC32: 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_SBC8: 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_SBC16: 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_SBC32: case FLAGS_SUB32: case FLAGS_DEC32: return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); @@ -192,9 +252,23 @@ static inline int VF_SET() 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_ROL8: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 7)) & 1; + case FLAGS_ROL16: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 15)) & 1; + case FLAGS_ROL32: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 31)) & 1; + + case FLAGS_ROR8: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x40; + case FLAGS_ROR16: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x4000; + case FLAGS_ROR32: + return (cpu_state.flags_res ^ (cpu_state.flags_res >> 1)) & 0x40000000; + case FLAGS_UNKNOWN: - return flags & V_FLAG; + return cpu_state.flags & V_FLAG; } return 0; } @@ -225,6 +299,16 @@ static inline int AF_SET() case FLAGS_INC32: return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; + case FLAGS_ADC8: + return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) || + ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xff); + case FLAGS_ADC16: + return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) || + ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xffff); + case FLAGS_ADC32: + return ((cpu_state.flags_res & 0xf) < (cpu_state.flags_op1 & 0xf)) || + ((cpu_state.flags_res & 0xf) == (cpu_state.flags_op1 & 0xf) && cpu_state.flags_op2 == 0xffffffff); + case FLAGS_SUB8: case FLAGS_SUB16: case FLAGS_SUB32: @@ -232,9 +316,21 @@ static inline int AF_SET() case FLAGS_DEC16: case FLAGS_DEC32: return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_SBC8: + case FLAGS_SBC16: + case FLAGS_SBC32: + return ((cpu_state.flags_op1 & 0xf) < (cpu_state.flags_op2 & 0xf)) || + ((cpu_state.flags_op1 & 0xf) == (cpu_state.flags_op2 & 0xf) && (cpu_state.flags_res & 0xf) != 0); + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + case FLAGS_ROR8: + case FLAGS_ROR16: + case FLAGS_ROR32: case FLAGS_UNKNOWN: - return flags & A_FLAG; + return cpu_state.flags & A_FLAG; } return 0; } @@ -244,23 +340,39 @@ static inline int CF_SET() switch (cpu_state.flags_op) { case FLAGS_ADD8: - return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100; + return ((cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100) ? 1 : 0; case FLAGS_ADD16: - return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000; + return ((cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000) ? 1 : 0; case FLAGS_ADD32: return (cpu_state.flags_res < cpu_state.flags_op1); + case FLAGS_ADC8: + return (cpu_state.flags_res < cpu_state.flags_op1) || + (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xff); + case FLAGS_ADC16: + return (cpu_state.flags_res < cpu_state.flags_op1) || + (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xffff); + case FLAGS_ADC32: + return (cpu_state.flags_res < cpu_state.flags_op1) || + (cpu_state.flags_res == cpu_state.flags_op1 && cpu_state.flags_op2 == 0xffffffff); + case FLAGS_SUB8: case FLAGS_SUB16: case FLAGS_SUB32: return (cpu_state.flags_op1 < cpu_state.flags_op2); - + + case FLAGS_SBC8: + case FLAGS_SBC16: + case FLAGS_SBC32: + return (cpu_state.flags_op1 < cpu_state.flags_op2) || + (cpu_state.flags_op1 == cpu_state.flags_op2 && cpu_state.flags_res != 0); + case FLAGS_SHL8: - return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; + return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80) ? 1 : 0; case FLAGS_SHL16: - return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000; + return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000) ? 1 : 0; case FLAGS_SHL32: - return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000; + return ((cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000) ? 1 : 0; case FLAGS_SHR8: case FLAGS_SHR16: @@ -278,6 +390,18 @@ static inline int CF_SET() case FLAGS_ZN16: case FLAGS_ZN32: return 0; + + case FLAGS_ROL8: + case FLAGS_ROL16: + case FLAGS_ROL32: + return cpu_state.flags_res & 1; + + case FLAGS_ROR8: + return (cpu_state.flags_res & 0x80) ? 1 : 0; + case FLAGS_ROR16: + return (cpu_state.flags_res & 0x8000) ? 1 :0; + case FLAGS_ROR32: + return (cpu_state.flags_res & 0x80000000) ? 1 : 0; case FLAGS_DEC8: case FLAGS_DEC16: @@ -286,7 +410,7 @@ static inline int CF_SET() case FLAGS_INC16: case FLAGS_INC32: case FLAGS_UNKNOWN: - return flags & C_FLAG; + return cpu_state.flags & C_FLAG; } return 0; } @@ -309,7 +433,7 @@ static inline void flags_rebuild() 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 = (cpu_state.flags & ~0x8d5) | tempf; cpu_state.flags_op = FLAGS_UNKNOWN; } } @@ -324,12 +448,21 @@ static inline void flags_rebuild_c() if (cpu_state.flags_op != FLAGS_UNKNOWN) { if (CF_SET()) - flags |= C_FLAG; + cpu_state.flags |= C_FLAG; else - flags &= ~C_FLAG; + cpu_state.flags &= ~C_FLAG; } } +static inline int flags_res_valid() +{ + if (cpu_state.flags_op == FLAGS_UNKNOWN || + (cpu_state.flags_op >= FLAGS_ROL8 && cpu_state.flags_op <= FLAGS_ROR32)) + return 0; + + return 1; +} + static inline void setznp8(uint8_t val) { cpu_state.flags_op = FLAGS_ZN8; @@ -352,6 +485,10 @@ static inline void setznp32(uint32_t val) cpu_state.flags_op1 = orig; \ cpu_state.flags_op2 = shift; +#define set_flags_rotate(op, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; + static inline void setadd8(uint8_t a, uint8_t b) { cpu_state.flags_op1 = a; @@ -447,67 +584,47 @@ static inline void setsub32nc(uint32_t a, uint32_t b) 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; + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b + tempc) & 0xff; + cpu_state.flags_op = FLAGS_ADC8; } 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; + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b + tempc) & 0xffff; + cpu_state.flags_op = FLAGS_ADC16; +} +static inline void setadc32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b + tempc; + cpu_state.flags_op = FLAGS_ADC32; } 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; + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - (b + tempc)) & 0xff; + cpu_state.flags_op = FLAGS_SBC8; } 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; + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - (b + tempc); + cpu_state.flags_op = FLAGS_SBC32; } +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); diff --git a/src/x86_ops.h b/src/x86_ops.h index 1aa5ae6..578b7cf 100644 --- a/src/x86_ops.h +++ b/src/x86_ops.h @@ -23,6 +23,9 @@ 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 *x86_dynarec_opcodes_REPE; +extern OpFn *x86_dynarec_opcodes_REPNE; +extern OpFn *x86_dynarec_opcodes_3DNOW; extern OpFn dynarec_ops_286[1024]; extern OpFn dynarec_ops_286_0f[1024]; @@ -31,9 +34,14 @@ extern OpFn dynarec_ops_386[1024]; extern OpFn dynarec_ops_386_0f[1024]; extern OpFn dynarec_ops_winchip_0f[1024]; +extern OpFn dynarec_ops_winchip2_0f[1024]; extern OpFn dynarec_ops_pentium_0f[1024]; extern OpFn dynarec_ops_pentiummmx_0f[1024]; +extern OpFn dynarec_ops_pentiumpro_0f[1024]; +extern OpFn dynarec_ops_pentium2_0f[1024]; + +extern OpFn dynarec_ops_c6x86_0f[1024]; extern OpFn dynarec_ops_c6x86mx_0f[1024]; extern OpFn dynarec_ops_fpu_d8_a16[32]; @@ -62,6 +70,11 @@ 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 dynarec_ops_REPE[1024]; +extern OpFn dynarec_ops_REPNE[1024]; + +extern OpFn dynarec_ops_3DNOW[256]; + extern OpFn *x86_opcodes; extern OpFn *x86_opcodes_0f; extern OpFn *x86_opcodes_d8_a16; @@ -80,6 +93,9 @@ 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 *x86_opcodes_REPE; +extern OpFn *x86_opcodes_REPNE; +extern OpFn *x86_opcodes_3DNOW; extern OpFn ops_286[1024]; extern OpFn ops_286_0f[1024]; @@ -88,10 +104,14 @@ extern OpFn ops_386[1024]; extern OpFn ops_386_0f[1024]; extern OpFn ops_winchip_0f[1024]; +extern OpFn ops_winchip2_0f[1024]; extern OpFn ops_pentium_0f[1024]; extern OpFn ops_pentiummmx_0f[1024]; +extern OpFn ops_pentiumpro_0f[1024]; +extern OpFn ops_pentium2_0f[1024]; +extern OpFn ops_c6x86_0f[1024]; extern OpFn ops_c6x86mx_0f[1024]; extern OpFn ops_fpu_d8_a16[32]; @@ -120,4 +140,9 @@ extern OpFn ops_fpu_686_db_a32[256]; extern OpFn ops_fpu_686_df_a16[256]; extern OpFn ops_fpu_686_df_a32[256]; +extern OpFn ops_REPE[1024]; +extern OpFn ops_REPNE[1024]; + +extern OpFn ops_3DNOW[256]; + #endif /*_X86_OPS_H*/ diff --git a/src/x86_ops_3dnow.h b/src/x86_ops_3dnow.h new file mode 100644 index 0000000..3ac36cb --- /dev/null +++ b/src/x86_ops_3dnow.h @@ -0,0 +1,346 @@ +#include + +static int opPREFETCH_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + + CLOCK_CYCLES(1); + return 0; +} +static int opPREFETCH_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + + CLOCK_CYCLES(1); + return 0; +} + +static int opFEMMS(uint32_t fetchdat) +{ + ILLEGAL_ON(!cpu_has_feature(CPU_FEATURE_MMX)); + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + x87_emms(); + CLOCK_CYCLES(1); + return 0; +} + +static int opPAVGUSB(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] + src.b[0] + 1) >> 1; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] + src.b[1] + 1) >> 1; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] + src.b[2] + 1) >> 1; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] + src.b[3] + 1) >> 1; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] + src.b[4] + 1) >> 1; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] + src.b[5] + 1) >> 1; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] + src.b[6] + 1) >> 1; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] + src.b[7] + 1) >> 1; + + return 0; +} +static int opPF2ID(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sl[0] = (int32_t)src.f[0]; + cpu_state.MM[cpu_reg].sl[1] = (int32_t)src.f[1]; + + return 0; +} +static int opPFACC(uint32_t fetchdat) +{ + MMX_REG src; + float tempf; + + MMX_GETSRC(); + + tempf = cpu_state.MM[cpu_reg].f[0] + cpu_state.MM[cpu_reg].f[1]; + cpu_state.MM[cpu_reg].f[1] = src.f[0] + src.f[1]; + cpu_state.MM[cpu_reg].f[0] = tempf; + + return 0; +} +static int opPFADD(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] += src.f[0]; + cpu_state.MM[cpu_reg].f[1] += src.f[1]; + + return 0; +} +static int opPFCMPEQ(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] == src.f[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] == src.f[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPFCMPGE(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] >= src.f[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] >= src.f[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPFCMPGT(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].f[0] > src.f[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].f[1] > src.f[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPFMAX(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + if (src.f[0] > cpu_state.MM[cpu_reg].f[0]) + cpu_state.MM[cpu_reg].f[0] = src.f[0]; + if (src.f[1] > cpu_state.MM[cpu_reg].f[1]) + cpu_state.MM[cpu_reg].f[1] = src.f[1]; + + return 0; +} +static int opPFMIN(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + if (src.f[0] < cpu_state.MM[cpu_reg].f[0]) + cpu_state.MM[cpu_reg].f[0] = src.f[0]; + if (src.f[1] < cpu_state.MM[cpu_reg].f[1]) + cpu_state.MM[cpu_reg].f[1] = src.f[1]; + + return 0; +} +static int opPFMUL(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] *= src.f[0]; + cpu_state.MM[cpu_reg].f[1] *= src.f[1]; + + return 0; +} +static int opPFRCP(uint32_t fetchdat) +{ + union + { + uint32_t i; + float f; + } src; + + if (cpu_mod == 3) + { + src.f = cpu_state.MM[cpu_rm].f[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_READ(cpu_state.ea_seg); + src.i = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + + cpu_state.MM[cpu_reg].f[0] = 1.0/src.f; + cpu_state.MM[cpu_reg].f[1] = cpu_state.MM[cpu_reg].f[0]; + + return 0; +} +/*Since opPFRCP() calculates a full precision reciprocal, treat the followup iterations as MOVs*/ +static int opPFRCPIT1(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] = src.f[0]; + cpu_state.MM[cpu_reg].f[1] = src.f[1]; + + return 0; +} +static int opPFRCPIT2(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] = src.f[0]; + cpu_state.MM[cpu_reg].f[1] = src.f[1]; + + return 0; +} +static int opPFRSQRT(uint32_t fetchdat) +{ + union + { + uint32_t i; + float f; + } src; + + if (cpu_mod == 3) + { + src.f = cpu_state.MM[cpu_rm].f[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_READ(cpu_state.ea_seg); + src.i = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + + cpu_state.MM[cpu_reg].f[0] = 1.0/sqrt(src.f); + cpu_state.MM[cpu_reg].f[1] = cpu_state.MM[cpu_reg].f[0]; + + return 0; +} +/*Since opPFRSQRT() calculates a full precision inverse square root, treat the followup iteration as a NOP*/ +static int opPFRSQIT1(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + UNUSED(src); + + return 0; +} +static int opPFSUB(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] -= src.f[0]; + cpu_state.MM[cpu_reg].f[1] -= src.f[1]; + + return 0; +} +static int opPFSUBR(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] = src.f[0] - cpu_state.MM[cpu_reg].f[0]; + cpu_state.MM[cpu_reg].f[1] = src.f[1] - cpu_state.MM[cpu_reg].f[1]; + + return 0; +} +static int opPI2FD(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].f[0] = (float)src.sl[0]; + cpu_state.MM[cpu_reg].f[1] = (float)src.sl[1]; + + return 0; +} +static int opPMULHRW(uint32_t fetchdat) +{ + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] = (((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)cpu_state.MM[cpu_rm].sw[0]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[1] = (((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)cpu_state.MM[cpu_rm].sw[1]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[2] = (((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)cpu_state.MM[cpu_rm].sw[2]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[3] = (((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)cpu_state.MM[cpu_rm].sw[3]) + 0x8000) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + SEG_CHECK_READ(cpu_state.ea_seg); + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] = ((int32_t)(cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)(cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)(cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + 0x8000) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)(cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) + 0x8000) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} + +OpFn OP_TABLE(3DNOW)[256] = +{ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPI2FD, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPF2ID, 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*/ opPFCMPGE, ILLEGAL, ILLEGAL, ILLEGAL, opPFMIN, ILLEGAL, opPFRCP, opPFRSQRT, ILLEGAL, ILLEGAL, opPFSUB, ILLEGAL, ILLEGAL, ILLEGAL, opPFADD, ILLEGAL, +/*a0*/ opPFCMPGT, ILLEGAL, ILLEGAL, ILLEGAL, opPFMAX, ILLEGAL, opPFRCPIT1, opPFRSQIT1, ILLEGAL, ILLEGAL, opPFSUBR, ILLEGAL, ILLEGAL, ILLEGAL, opPFACC, ILLEGAL, +/*b0*/ opPFCMPEQ, ILLEGAL, ILLEGAL, ILLEGAL, opPFMUL, ILLEGAL, opPFRCPIT2, opPMULHRW, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPAVGUSB, + +/*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, +}; + +static int op3DNOW_a16(uint32_t fetchdat) +{ + uint8_t opcode; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + opcode = fastreadb(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + return x86_opcodes_3DNOW[opcode](0); +} +static int op3DNOW_a32(uint32_t fetchdat) +{ + uint8_t opcode; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + opcode = fastreadb(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + return x86_opcodes_3DNOW[opcode](0); +} diff --git a/src/x86_ops_arith.h b/src/x86_ops_arith.h index 2417555..b9787e9 100644 --- a/src/x86_ops_arith.h +++ b/src/x86_ops_arith.h @@ -14,9 +14,11 @@ } \ else \ { \ - uint8_t dst = geteab(); if (cpu_state.abrt) return 1; \ + uint8_t dst; \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteab(); if (cpu_state.abrt) return 1; \ uint8_t src = getr8(cpu_reg); \ - seteab(operation); if (cpu_state.abrt) return 1; \ + seteab(operation); if (cpu_state.abrt) return 1; \ setflags ## 8 flagops; \ CLOCK_CYCLES(timing_mr); \ PREFETCH_RUN(timing_mr, 2, rmdat, 1,0,1,0, 0); \ @@ -38,7 +40,9 @@ } \ else \ { \ - uint8_t dst = geteab(); if (cpu_state.abrt) return 1; \ + uint8_t dst; \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteab(); if (cpu_state.abrt) return 1; \ uint8_t src = getr8(cpu_reg); \ seteab(operation); if (cpu_state.abrt) return 1; \ setflags ## 8 flagops; \ @@ -63,7 +67,9 @@ } \ else \ { \ - uint16_t dst = geteaw(); if (cpu_state.abrt) return 1; \ + uint16_t dst; \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ uint16_t src = cpu_state.regs[cpu_reg].w; \ seteaw(operation); if (cpu_state.abrt) return 1; \ setflags ## 16 flagops; \ @@ -87,7 +93,9 @@ } \ else \ { \ - uint16_t dst = geteaw(); if (cpu_state.abrt) return 1; \ + uint16_t dst; \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ uint16_t src = cpu_state.regs[cpu_reg].w; \ seteaw(operation); if (cpu_state.abrt) return 1; \ setflags ## 16 flagops; \ @@ -112,7 +120,9 @@ } \ else \ { \ - uint32_t dst = geteal(); if (cpu_state.abrt) return 1; \ + uint32_t dst; \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteal(); if (cpu_state.abrt) return 1; \ uint32_t src = cpu_state.regs[cpu_reg].l; \ seteal(operation); if (cpu_state.abrt) return 1; \ setflags ## 32 flagops; \ @@ -136,7 +146,9 @@ } \ else \ { \ - uint32_t dst = geteal(); if (cpu_state.abrt) return 1; \ + uint32_t dst; \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ + dst = geteal(); if (cpu_state.abrt) return 1; \ uint32_t src = cpu_state.regs[cpu_reg].l; \ seteal(operation); if (cpu_state.abrt) return 1; \ setflags ## 32 flagops; \ @@ -151,6 +163,8 @@ uint8_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = getr8(cpu_reg); \ src = geteab(); if (cpu_state.abrt) return 1; \ setflags ## 8 flagops; \ @@ -164,6 +178,8 @@ uint8_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = getr8(cpu_reg); \ src = geteab(); if (cpu_state.abrt) return 1; \ setflags ## 8 flagops; \ @@ -178,6 +194,8 @@ uint16_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = cpu_state.regs[cpu_reg].w; \ src = geteaw(); if (cpu_state.abrt) return 1; \ setflags ## 16 flagops; \ @@ -191,6 +209,8 @@ uint16_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = cpu_state.regs[cpu_reg].w; \ src = geteaw(); if (cpu_state.abrt) return 1; \ setflags ## 16 flagops; \ @@ -205,6 +225,8 @@ uint32_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = cpu_state.regs[cpu_reg].l; \ src = geteal(); if (cpu_state.abrt) return 1; \ setflags ## 32 flagops; \ @@ -218,6 +240,8 @@ uint32_t dst, src; \ if (gettempc) tempc = CF_SET() ? 1 : 0; \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ dst = cpu_state.regs[cpu_reg].l; \ src = geteal(); if (cpu_state.abrt) return 1; \ setflags ## 32 flagops; \ @@ -275,6 +299,8 @@ static int opCMP_b_rmw_a16(uint32_t fetchdat) { uint8_t dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteab(); if (cpu_state.abrt) return 1; setsub8(dst, getr8(cpu_reg)); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -286,6 +312,8 @@ static int opCMP_b_rmw_a32(uint32_t fetchdat) { uint8_t dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteab(); if (cpu_state.abrt) return 1; setsub8(dst, getr8(cpu_reg)); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -298,6 +326,8 @@ static int opCMP_w_rmw_a16(uint32_t fetchdat) { uint16_t dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; setsub16(dst, cpu_state.regs[cpu_reg].w); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -309,6 +339,8 @@ static int opCMP_w_rmw_a32(uint32_t fetchdat) { uint16_t dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; setsub16(dst, cpu_state.regs[cpu_reg].w); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -321,6 +353,8 @@ static int opCMP_l_rmw_a16(uint32_t fetchdat) { uint32_t dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; setsub32(dst, cpu_state.regs[cpu_reg].l); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -332,6 +366,8 @@ static int opCMP_l_rmw_a32(uint32_t fetchdat) { uint32_t dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; setsub32(dst, cpu_state.regs[cpu_reg].l); if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); @@ -344,7 +380,9 @@ static int opCMP_b_rm_a16(uint32_t fetchdat) { uint8_t src; fetch_ea_16(fetchdat); - src = geteab(); if (cpu_state.abrt) return 1; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteab(); if (cpu_state.abrt) return 1; setsub8(getr8(cpu_reg), src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); @@ -354,7 +392,9 @@ static int opCMP_b_rm_a32(uint32_t fetchdat) { uint8_t src; fetch_ea_32(fetchdat); - src = geteab(); if (cpu_state.abrt) return 1; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteab(); if (cpu_state.abrt) return 1; setsub8(getr8(cpu_reg), src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); @@ -365,7 +405,9 @@ static int opCMP_w_rm_a16(uint32_t fetchdat) { uint16_t src; fetch_ea_16(fetchdat); - src = geteaw(); if (cpu_state.abrt) return 1; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteaw(); if (cpu_state.abrt) return 1; setsub16(cpu_state.regs[cpu_reg].w, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); @@ -375,7 +417,9 @@ static int opCMP_w_rm_a32(uint32_t fetchdat) { uint16_t src; fetch_ea_32(fetchdat); - src = geteaw(); if (cpu_state.abrt) return 1; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteaw(); if (cpu_state.abrt) return 1; setsub16(cpu_state.regs[cpu_reg].w, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); @@ -386,7 +430,9 @@ static int opCMP_l_rm_a16(uint32_t fetchdat) { uint32_t src; fetch_ea_16(fetchdat); - src = geteal(); if (cpu_state.abrt) return 1; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteal(); if (cpu_state.abrt) return 1; setsub32(cpu_state.regs[cpu_reg].l, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); @@ -396,7 +442,9 @@ static int opCMP_l_rm_a32(uint32_t fetchdat) { uint32_t src; fetch_ea_32(fetchdat); - src = geteal(); if (cpu_state.abrt) return 1; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + src = geteal(); if (cpu_state.abrt) return 1; setsub32(cpu_state.regs[cpu_reg].l, src); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); @@ -434,6 +482,8 @@ static int opTEST_b_a16(uint32_t fetchdat) { uint8_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; temp2 = getr8(cpu_reg); setznp8(temp & temp2); @@ -446,6 +496,8 @@ static int opTEST_b_a32(uint32_t fetchdat) { uint8_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; temp2 = getr8(cpu_reg); setznp8(temp & temp2); @@ -459,6 +511,8 @@ static int opTEST_w_a16(uint32_t fetchdat) { uint16_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].w; setznp16(temp & temp2); @@ -471,6 +525,8 @@ static int opTEST_w_a32(uint32_t fetchdat) { uint16_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].w; setznp16(temp & temp2); @@ -484,6 +540,8 @@ static int opTEST_l_a16(uint32_t fetchdat) { uint32_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].l; setznp32(temp & temp2); @@ -496,6 +554,8 @@ static int opTEST_l_a32(uint32_t fetchdat) { uint32_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; temp2 = cpu_state.regs[cpu_reg].l; setznp32(temp & temp2); @@ -588,6 +648,8 @@ static int op80_a16(uint32_t fetchdat) uint8_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; ARITH_MULTI(b, 8); if ((rmdat & 0x38) == 0x38) @@ -602,6 +664,8 @@ static int op80_a32(uint32_t fetchdat) uint8_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; ARITH_MULTI(b, 8); if ((rmdat & 0x38) == 0x38) @@ -616,6 +680,8 @@ static int op81_w_a16(uint32_t fetchdat) uint16_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getword(); if (cpu_state.abrt) return 1; ARITH_MULTI(w, 16); if ((rmdat & 0x38) == 0x38) @@ -630,6 +696,8 @@ static int op81_w_a32(uint32_t fetchdat) uint16_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getword(); if (cpu_state.abrt) return 1; ARITH_MULTI(w, 16); if ((rmdat & 0x38) == 0x38) @@ -644,6 +712,8 @@ static int op81_l_a16(uint32_t fetchdat) uint32_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getlong(); if (cpu_state.abrt) return 1; ARITH_MULTI(l, 32); if ((rmdat & 0x38) == 0x38) @@ -658,6 +728,8 @@ static int op81_l_a32(uint32_t fetchdat) uint32_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getlong(); if (cpu_state.abrt) return 1; ARITH_MULTI(l, 32); if ((rmdat & 0x38) == 0x38) @@ -673,6 +745,8 @@ static int op83_w_a16(uint32_t fetchdat) uint16_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xff00; ARITH_MULTI(w, 16); @@ -688,6 +762,8 @@ static int op83_w_a32(uint32_t fetchdat) uint16_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xff00; ARITH_MULTI(w, 16); @@ -704,6 +780,8 @@ static int op83_l_a16(uint32_t fetchdat) uint32_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xffffff00; ARITH_MULTI(l, 32); @@ -719,6 +797,8 @@ static int op83_l_a32(uint32_t fetchdat) uint32_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); src = getbyte(); if (cpu_state.abrt) return 1; if (src & 0x80) src |= 0xffffff00; ARITH_MULTI(l, 32); diff --git a/src/x86_ops_atomic.h b/src/x86_ops_atomic.h index 0e0069c..06a33e2 100644 --- a/src/x86_ops_atomic.h +++ b/src/x86_ops_atomic.h @@ -8,6 +8,7 @@ static int opCMPXCHG_b_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; if (AL == temp) seteab(getr8(cpu_reg)); else AL = temp; @@ -26,6 +27,7 @@ static int opCMPXCHG_b_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; if (AL == temp) seteab(getr8(cpu_reg)); else AL = temp; @@ -45,6 +47,7 @@ static int opCMPXCHG_w_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w); else AX = temp; @@ -63,6 +66,7 @@ static int opCMPXCHG_w_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w); else AX = temp; @@ -82,6 +86,7 @@ static int opCMPXCHG_l_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l); else EAX = temp; @@ -100,6 +105,7 @@ static int opCMPXCHG_l_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l); else EAX = temp; @@ -119,6 +125,7 @@ static int opCMPXCHG8B_a16(uint32_t fetchdat) return 0; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; if (EAX == temp && EDX == temp_hi) @@ -134,9 +141,9 @@ static int opCMPXCHG8B_a16(uint32_t fetchdat) if (cpu_state.abrt) return 0; flags_rebuild(); if (temp == temp2 && temp_hi == temp2_hi) - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; else - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; cycles -= (cpu_mod == 3) ? 6 : 10; return 0; } @@ -150,6 +157,7 @@ static int opCMPXCHG8B_a32(uint32_t fetchdat) return 0; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; if (EAX == temp && EDX == temp_hi) @@ -165,9 +173,9 @@ static int opCMPXCHG8B_a32(uint32_t fetchdat) if (cpu_state.abrt) return 0; flags_rebuild(); if (temp == temp2 && temp_hi == temp2_hi) - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; else - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; cycles -= (cpu_mod == 3) ? 6 : 10; return 0; } @@ -182,6 +190,7 @@ static int opXADD_b_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; seteab(temp + getr8(cpu_reg)); if (cpu_state.abrt) return 1; setadd8(temp, getr8(cpu_reg)); @@ -199,6 +208,7 @@ static int opXADD_b_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; seteab(temp + getr8(cpu_reg)); if (cpu_state.abrt) return 1; setadd8(temp, getr8(cpu_reg)); @@ -217,6 +227,7 @@ static int opXADD_w_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp + cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; setadd16(temp, cpu_state.regs[cpu_reg].w); @@ -234,6 +245,7 @@ static int opXADD_w_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp + cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; setadd16(temp, cpu_state.regs[cpu_reg].w); @@ -252,6 +264,7 @@ static int opXADD_l_a16(uint32_t fetchdat) return 1; } fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp + cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; setadd32(temp, cpu_state.regs[cpu_reg].l); @@ -269,6 +282,7 @@ static int opXADD_l_a32(uint32_t fetchdat) return 1; } fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp + cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; setadd32(temp, cpu_state.regs[cpu_reg].l); diff --git a/src/x86_ops_bcd.h b/src/x86_ops_bcd.h index a7eaf03..2b41394 100644 --- a/src/x86_ops_bcd.h +++ b/src/x86_ops_bcd.h @@ -1,14 +1,14 @@ static int opAAA(uint32_t fetchdat) { flags_rebuild(); - if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { AL += 6; AH++; - flags |= (A_FLAG | C_FLAG); + cpu_state.flags |= (A_FLAG | C_FLAG); } else - flags &= ~(A_FLAG | C_FLAG); + cpu_state.flags &= ~(A_FLAG | C_FLAG); AL &= 0xF; CLOCK_CYCLES(is486 ? 3 : 4); PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0); @@ -42,14 +42,14 @@ static int opAAM(uint32_t fetchdat) static int opAAS(uint32_t fetchdat) { flags_rebuild(); - if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xF) > 9)) { AL -= 6; AH--; - flags |= (A_FLAG | C_FLAG); + cpu_state.flags |= (A_FLAG | C_FLAG); } else - flags &= ~(A_FLAG | C_FLAG); + cpu_state.flags &= ~(A_FLAG | C_FLAG); AL &= 0xF; CLOCK_CYCLES(is486 ? 3 : 4); PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0); @@ -61,23 +61,23 @@ static int opDAA(uint32_t fetchdat) uint16_t tempw; flags_rebuild(); - if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { int tempi = ((uint16_t)AL) + 6; AL += 6; - flags |= A_FLAG; - if (tempi & 0x100) flags |= C_FLAG; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) cpu_state.flags |= C_FLAG; } - if ((flags & C_FLAG) || (AL > 0x9f)) + if ((cpu_state.flags & C_FLAG) || (AL > 0x9f)) { AL += 0x60; - flags |= C_FLAG; + cpu_state.flags |= C_FLAG; } - tempw = flags & (C_FLAG | A_FLAG); + tempw = cpu_state.flags & (C_FLAG | A_FLAG); setznp8(AL); flags_rebuild(); - flags |= tempw; + cpu_state.flags |= tempw; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); @@ -89,23 +89,23 @@ static int opDAS(uint32_t fetchdat) uint16_t tempw; flags_rebuild(); - if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { int tempi = ((uint16_t)AL) - 6; AL -= 6; - flags |= A_FLAG; - if (tempi & 0x100) flags |= C_FLAG; + cpu_state.flags |= A_FLAG; + if (tempi & 0x100) cpu_state.flags |= C_FLAG; } - if ((flags & C_FLAG) || (AL > 0x9f)) + if ((cpu_state.flags & C_FLAG) || (AL > 0x9f)) { AL -= 0x60; - flags |= C_FLAG; + cpu_state.flags |= C_FLAG; } - tempw = flags & (C_FLAG | A_FLAG); + tempw = cpu_state.flags & (C_FLAG | A_FLAG); setznp8(AL); flags_rebuild(); - flags |= tempw; + cpu_state.flags |= tempw; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); diff --git a/src/x86_ops_bit.h b/src/x86_ops_bit.h index 272d22b..7261fef 100644 --- a/src/x86_ops_bit.h +++ b/src/x86_ops_bit.h @@ -3,11 +3,12 @@ static int opBT_w_r_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; temp = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); - if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 0); @@ -18,11 +19,12 @@ static int opBT_w_r_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; temp = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); - if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 1); @@ -33,11 +35,12 @@ static int opBT_l_r_a16(uint32_t fetchdat) uint32_t temp; fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; temp = geteal(); if (cpu_state.abrt) return 1; flags_rebuild(); - if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 0); @@ -48,11 +51,12 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint32_t temp; fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; temp = geteal(); if (cpu_state.abrt) return 1; flags_rebuild(); - if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 1); @@ -66,14 +70,16 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint16_t temp; \ \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = eal_w = 0; \ temp = geteaw(); if (cpu_state.abrt) return 1; \ tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0; \ temp operation (1 << (cpu_state.regs[cpu_reg].w & 15)); \ seteaw(temp); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ - else flags &= ~C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ \ CLOCK_CYCLES(6); \ PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 0); \ @@ -85,14 +91,16 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint16_t temp; \ \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = eal_w = 0; \ temp = geteaw(); if (cpu_state.abrt) return 1; \ tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0; \ temp operation (1 << (cpu_state.regs[cpu_reg].w & 15)); \ seteaw(temp); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ - else flags &= ~C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ \ CLOCK_CYCLES(6); \ PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 1); \ @@ -104,14 +112,16 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint32_t temp; \ \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = eal_w = 0; \ temp = geteal(); if (cpu_state.abrt) return 1; \ tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0; \ temp operation (1 << (cpu_state.regs[cpu_reg].l & 31)); \ seteal(temp); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ - else flags &= ~C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ \ CLOCK_CYCLES(6); \ PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 0); \ @@ -123,14 +133,16 @@ static int opBT_l_r_a32(uint32_t fetchdat) uint32_t temp; \ \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = eal_w = 0; \ temp = geteal(); if (cpu_state.abrt) return 1; \ tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0; \ temp operation (1 << (cpu_state.regs[cpu_reg].l & 31)); \ seteal(temp); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ - else flags &= ~C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ + else cpu_state.flags &= ~C_FLAG; \ \ CLOCK_CYCLES(6); \ PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 1); \ @@ -147,7 +159,9 @@ static int opBA_w_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); count = getbyte(); if (cpu_state.abrt) return 1; tempc = temp & (1 << count); @@ -155,8 +169,8 @@ static int opBA_w_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x20: /*BT w,imm*/ - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); return 0; @@ -177,8 +191,8 @@ static int opBA_w_a16(uint32_t fetchdat) break; } seteaw(temp); if (cpu_state.abrt) return 1; - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(6); PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); return 0; @@ -189,7 +203,9 @@ static int opBA_w_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteaw(); count = getbyte(); if (cpu_state.abrt) return 1; tempc = temp & (1 << count); @@ -197,8 +213,8 @@ static int opBA_w_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x20: /*BT w,imm*/ - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); return 0; @@ -219,8 +235,8 @@ static int opBA_w_a32(uint32_t fetchdat) break; } seteaw(temp); if (cpu_state.abrt) return 1; - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(6); PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); return 0; @@ -232,7 +248,9 @@ static int opBA_l_a16(uint32_t fetchdat) uint32_t temp; fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); count = getbyte(); if (cpu_state.abrt) return 1; tempc = temp & (1 << count); @@ -240,8 +258,8 @@ static int opBA_l_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x20: /*BT w,imm*/ - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); return 0; @@ -262,8 +280,8 @@ static int opBA_l_a16(uint32_t fetchdat) break; } seteal(temp); if (cpu_state.abrt) return 1; - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(6); PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); return 0; @@ -274,7 +292,9 @@ static int opBA_l_a32(uint32_t fetchdat) uint32_t temp; fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + temp = geteal(); count = getbyte(); if (cpu_state.abrt) return 1; tempc = temp & (1 << count); @@ -282,8 +302,8 @@ static int opBA_l_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x20: /*BT w,imm*/ - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); return 0; @@ -304,8 +324,8 @@ static int opBA_l_a32(uint32_t fetchdat) break; } seteal(temp); if (cpu_state.abrt) return 1; - if (tempc) flags |= C_FLAG; - else flags &= ~C_FLAG; + if (tempc) cpu_state.flags |= C_FLAG; + else cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(6); PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); return 0; diff --git a/src/x86_ops_bitscan.h b/src/x86_ops_bitscan.h index 0c1ee04..98349da 100644 --- a/src/x86_ops_bitscan.h +++ b/src/x86_ops_bitscan.h @@ -4,7 +4,7 @@ if (temp) \ { \ int c; \ - flags &= ~Z_FLAG; \ + cpu_state.flags &= ~Z_FLAG; \ for (c = start; c != end; c += dir) \ { \ CLOCK_CYCLES(time); \ @@ -17,7 +17,7 @@ } \ } \ else \ - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; static int opBSF_w_a16(uint32_t fetchdat) { @@ -25,6 +25,8 @@ static int opBSF_w_a16(uint32_t fetchdat) int instr_cycles; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); @@ -40,6 +42,8 @@ static int opBSF_w_a32(uint32_t fetchdat) int instr_cycles; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); @@ -55,6 +59,8 @@ static int opBSF_l_a16(uint32_t fetchdat) int instr_cycles; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); @@ -70,6 +76,8 @@ static int opBSF_l_a32(uint32_t fetchdat) int instr_cycles; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); @@ -86,6 +94,8 @@ static int opBSR_w_a16(uint32_t fetchdat) int instr_cycles; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); @@ -101,6 +111,8 @@ static int opBSR_w_a32(uint32_t fetchdat) int instr_cycles; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); @@ -116,6 +128,8 @@ static int opBSR_l_a16(uint32_t fetchdat) int instr_cycles; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); @@ -131,6 +145,8 @@ static int opBSR_l_a32(uint32_t fetchdat) int instr_cycles; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); diff --git a/src/x86_ops_call.h b/src/x86_ops_call.h index bbb5dca..8b6087d 100644 --- a/src/x86_ops_call.h +++ b/src/x86_ops_call.h @@ -1,11 +1,10 @@ #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); \ + if (msw & 1) loadcscall(new_seg, old_pc); \ else \ { \ loadcs(new_seg); \ @@ -17,24 +16,23 @@ if (cgate32) \ { \ uint32_t old_esp = ESP; \ - PUSH_L(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - PUSH_L(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + PUSH_L(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ } \ else \ { \ uint32_t old_esp = ESP; \ - PUSH_W(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - PUSH_W(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + PUSH_W(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (cpu_state.abrt) { CS = old_cs; 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); \ + if (msw & 1) loadcscall(new_seg, old_pc); \ else \ { \ loadcs(new_seg); \ @@ -46,14 +44,14 @@ if (cgate16) \ { \ uint32_t old_esp = ESP; \ - PUSH_W(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - PUSH_W(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + PUSH_W(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ } \ else \ { \ uint32_t old_esp = ESP; \ - PUSH_L(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ - PUSH_L(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + PUSH_L(old_cs); if (cpu_state.abrt) { CS = old_cs; cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { CS = old_cs; ESP = old_esp; return 1; } \ } @@ -104,6 +102,8 @@ static int opFF_w_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*INC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp + 1); if (cpu_state.abrt) return 1; setadd16nc(temp, 1); @@ -111,6 +111,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); break; case 0x08: /*DEC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp - 1); if (cpu_state.abrt) return 1; setsub16nc(temp, 1); @@ -118,6 +120,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); break; case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteaw(); if (cpu_state.abrt) return 1; PUSH_W(cpu_state.pc); cpu_state.pc = new_pc; @@ -128,6 +132,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; @@ -137,6 +143,8 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteaw(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); @@ -146,16 +154,20 @@ static int opFF_w_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ - oxpc = cpu_state.pc; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + old_pc = cpu_state.pc; new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; - loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 0); PREFETCH_FLUSH(); break; case 0x30: /*PUSH w*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; PUSH_W(temp); CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); @@ -181,6 +193,8 @@ static int opFF_w_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*INC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp + 1); if (cpu_state.abrt) return 1; setadd16nc(temp, 1); @@ -188,6 +202,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); break; case 0x08: /*DEC w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(temp - 1); if (cpu_state.abrt) return 1; setsub16nc(temp, 1); @@ -195,6 +211,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); break; case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteaw(); if (cpu_state.abrt) return 1; PUSH_W(cpu_state.pc); cpu_state.pc = new_pc; @@ -205,6 +223,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; @@ -214,6 +234,8 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteaw(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); @@ -223,16 +245,20 @@ static int opFF_w_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ - oxpc = cpu_state.pc; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + old_pc = cpu_state.pc; new_pc = readmemw(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; - loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 1); PREFETCH_FLUSH(); break; case 0x30: /*PUSH w*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; PUSH_W(temp); CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); @@ -259,6 +285,8 @@ static int opFF_l_a16(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*INC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp + 1); if (cpu_state.abrt) return 1; setadd32nc(temp, 1); @@ -266,6 +294,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); break; case 0x08: /*DEC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp - 1); if (cpu_state.abrt) return 1; setsub32nc(temp, 1); @@ -273,6 +303,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); break; case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteal(); if (cpu_state.abrt) return 1; PUSH_L(cpu_state.pc); cpu_state.pc = new_pc; @@ -283,6 +315,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; @@ -292,6 +326,8 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteal(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); @@ -301,16 +337,20 @@ static int opFF_l_a16(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ - oxpc = cpu_state.pc; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + old_pc = cpu_state.pc; new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; - loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 0); PREFETCH_FLUSH(); break; case 0x30: /*PUSH l*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; PUSH_L(temp); CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); @@ -336,6 +376,8 @@ static int opFF_l_a32(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*INC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp + 1); if (cpu_state.abrt) return 1; setadd32nc(temp, 1); @@ -343,6 +385,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); break; case 0x08: /*DEC l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(temp - 1); if (cpu_state.abrt) return 1; setsub32nc(temp, 1); @@ -350,6 +394,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); break; case 0x10: /*CALL*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteal(); if (cpu_state.abrt) return 1; PUSH_L(cpu_state.pc); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; @@ -360,6 +406,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x18: /*CALL far*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; @@ -369,6 +417,8 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x20: /*JMP*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_pc = geteal(); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; CPU_BLOCK_END(); @@ -378,16 +428,20 @@ static int opFF_l_a32(uint32_t fetchdat) PREFETCH_FLUSH(); break; case 0x28: /*JMP far*/ - oxpc = cpu_state.pc; + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + old_pc = cpu_state.pc; new_pc = readmeml(easeg, cpu_state.eaaddr); new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; cpu_state.pc = new_pc; - loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; + loadcsjmp(new_cs, old_pc); if (cpu_state.abrt) return 1; CPU_BLOCK_END(); PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); PREFETCH_FLUSH(); break; case 0x30: /*PUSH l*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; PUSH_L(temp); PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); diff --git a/src/x86_ops_cyrix.h b/src/x86_ops_cyrix.h new file mode 100644 index 0000000..e6464ce --- /dev/null +++ b/src/x86_ops_cyrix.h @@ -0,0 +1,274 @@ +/*Cyrix-only instructions*/ +/*System Management Mode*/ +static void opSVDC_common(uint32_t fetchdat) +{ + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_es); + writememw(0, easeg+cpu_state.eaaddr+8, ES); + break; + case 0x08: /*CS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_cs); + writememw(0, easeg+cpu_state.eaaddr+8, CS); + break; + case 0x18: /*DS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_ds); + writememw(0, easeg+cpu_state.eaaddr+8, DS); + break; + case 0x10: /*SS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_ss); + writememw(0, easeg+cpu_state.eaaddr+8, SS); + break; + case 0x20: /*FS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_fs); + writememw(0, easeg+cpu_state.eaaddr+8, FS); + break; + case 0x28: /*GS*/ + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_gs); + writememw(0, easeg+cpu_state.eaaddr+8, GS); + break; + default: + pclog("opSVDC: unknown rmdat %02x\n", rmdat); + x86illegal(); + } +} +static int opSVDC_a16(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + opSVDC_common(fetchdat); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opSVDC_a32(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + opSVDC_common(fetchdat); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static void opRSDC_common(uint32_t fetchdat) +{ + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_es); + break; + case 0x18: /*DS*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_ds); + break; + case 0x10: /*SS*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_ss); + break; + case 0x20: /*FS*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_fs); + break; + case 0x28: /*GS*/ + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &cpu_state.seg_gs); + break; + default: + pclog("opRSDC: unknown rmdat %02x\n", rmdat); + x86illegal(); + } +} +static int opRSDC_a16(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + opRSDC_common(fetchdat); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opRSDC_a32(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + opRSDC_common(fetchdat); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opSVLDT_a16(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &ldt); + writememw(0, easeg+cpu_state.eaaddr+8, ldt.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opSVLDT_a32(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &ldt); + writememw(0, easeg+cpu_state.eaaddr+8, ldt.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opRSLDT_a16(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &ldt); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opRSLDT_a32(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); + cyrix_load_seg_descriptor(easeg+cpu_state.eaaddr, &ldt); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opSVTS_a16(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &tr); + writememw(0, easeg+cpu_state.eaaddr+8, tr.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opSVTS_a32(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &tr); + writememw(0, easeg+cpu_state.eaaddr+8, tr.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opRSTS_a16(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &tr); + writememw(0, easeg+cpu_state.eaaddr+8, tr.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} +static int opRSTS_a32(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + { + fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); + cyrix_write_seg_descriptor(easeg+cpu_state.eaaddr, &tr); + writememw(0, easeg+cpu_state.eaaddr+8, tr.seg); + } + else + x86illegal(); + + return cpu_state.abrt; +} + +static int opSMINT(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + fatal("opSMINT\n"); + else + x86illegal(); + + return 1; +} + +static int opRDSHR_a16(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + fatal("opRDSHR_a16\n"); + else + x86illegal(); + + return 1; +} +static int opRDSHR_a32(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + fatal("opRDSHR_a32\n"); + else + x86illegal(); + + return 1; +} + +static int opWRSHR_a16(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + fatal("opWRSHR_a16\n"); + else + x86illegal(); + + return 1; +} +static int opWRSHR_a32(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + fatal("opWRSHR_a32\n"); + else + x86illegal(); + + return 1; +} diff --git a/src/x86_ops_flag.h b/src/x86_ops_flag.h index 3fbaba6..64f43e9 100644 --- a/src/x86_ops_flag.h +++ b/src/x86_ops_flag.h @@ -1,7 +1,7 @@ static int opCMC(uint32_t fetchdat) { flags_rebuild(); - flags ^= C_FLAG; + cpu_state.flags ^= C_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; @@ -11,14 +11,14 @@ static int opCMC(uint32_t fetchdat) static int opCLC(uint32_t fetchdat) { flags_rebuild(); - flags &= ~C_FLAG; + cpu_state.flags &= ~C_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; } static int opCLD(uint32_t fetchdat) { - flags &= ~D_FLAG; + cpu_state.flags &= ~D_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; @@ -27,11 +27,19 @@ static int opCLI(uint32_t fetchdat) { if (!IOPLp) { - x86gpf(NULL,0); - return 1; + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + cpu_state.eflags &= ~VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } } else - flags &= ~I_FLAG; + cpu_state.flags &= ~I_FLAG; CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); @@ -41,14 +49,14 @@ static int opCLI(uint32_t fetchdat) static int opSTC(uint32_t fetchdat) { flags_rebuild(); - flags |= C_FLAG; + cpu_state.flags |= C_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; } static int opSTD(uint32_t fetchdat) { - flags |= D_FLAG; + cpu_state.flags |= D_FLAG; CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; @@ -57,14 +65,30 @@ static int opSTI(uint32_t fetchdat) { if (!IOPLp) { - x86gpf(NULL,0); - return 1; + if ((!(cpu_state.eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((cpu_state.eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + if (cpu_state.eflags & VIP_FLAG) + { + x86gpf(NULL,0); + return 1; + } + else + cpu_state.eflags |= VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } } else - flags |= I_FLAG; + cpu_state.flags |= I_FLAG; + + /*First instruction after STI will always execute, regardless of whether + there is a pending interrupt*/ + cpu_end_block_after_ins = 2; - CPU_BLOCK_END(); - CLOCK_CYCLES(2); PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); return 0; @@ -73,7 +97,7 @@ static int opSTI(uint32_t fetchdat) static int opSAHF(uint32_t fetchdat) { flags_rebuild(); - flags = (flags & 0xff00) | (AH & 0xd5) | 2; + cpu_state.flags = (cpu_state.flags & 0xff00) | (AH & 0xd5) | 2; CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); @@ -84,7 +108,7 @@ static int opSAHF(uint32_t fetchdat) static int opLAHF(uint32_t fetchdat) { flags_rebuild(); - AH = flags & 0xff; + AH = cpu_state.flags & 0xff; CLOCK_CYCLES(3); PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); return 0; @@ -92,13 +116,29 @@ static int opLAHF(uint32_t fetchdat) static int opPUSHF(uint32_t fetchdat) { - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { - x86gpf(NULL,0); - return 1; + if (cr4 & CR4_VME) + { + uint16_t temp; + + flags_rebuild(); + temp = (cpu_state.flags & ~I_FLAG) | 0x3000; + if (cpu_state.eflags & VIF_FLAG) + temp |= I_FLAG; + PUSH_W(temp); + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + { + flags_rebuild(); + PUSH_W(cpu_state.flags); } - flags_rebuild(); - PUSH_W(flags); CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); return cpu_state.abrt; @@ -106,15 +146,16 @@ static int opPUSHF(uint32_t fetchdat) static int opPUSHFD(uint32_t fetchdat) { uint16_t tempw; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { x86gpf(NULL, 0); return 1; } - if (CPUID) tempw = eflags & 0x24; - else tempw = eflags & 4; + if (cpu_CR4_mask & CR4_VME) tempw = cpu_state.eflags & 0x3c; + else if (CPUID) tempw = cpu_state.eflags & 0x24; + else tempw = cpu_state.eflags & 4; flags_rebuild(); - PUSH_L(flags | (tempw << 16)); + PUSH_L(cpu_state.flags | (tempw << 16)); CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); return cpu_state.abrt; @@ -124,7 +165,7 @@ static int opPOPF_286(uint32_t fetchdat) { uint16_t tempw; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { x86gpf(NULL, 0); return 1; @@ -132,10 +173,10 @@ static int opPOPF_286(uint32_t fetchdat) tempw = POP_W(); if (cpu_state.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; + if (!(msw & 1)) cpu_state.flags = (cpu_state.flags & 0x7000) | (tempw & 0x0fd5) | 2; + else if (!(CPL)) cpu_state.flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; + else cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; flags_extract(); CLOCK_CYCLES(5); @@ -149,17 +190,50 @@ static int opPOPF(uint32_t fetchdat) { uint16_t tempw; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { - x86gpf(NULL, 0); - return 1; - } - - tempw = POP_W(); if (cpu_state.abrt) return 1; + if (cr4 & CR4_VME) + { + uint32_t old_esp = ESP; - if (!(CPL) || !(msw & 1)) flags = (tempw & 0x7fd5) | 2; - else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; - else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + tempw = POP_W(); + if (cpu_state.abrt) + { + ESP = old_esp; + return 1; + } + + if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (cpu_state.eflags & VIP_FLAG))) + { + ESP = old_esp; + x86gpf(NULL, 0); + return 1; + } + if (tempw & I_FLAG) + cpu_state.eflags |= VIF_FLAG; + else + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; + } + else + { + x86gpf(NULL, 0); + return 1; + } + } + else + { + tempw = POP_W(); + if (cpu_state.abrt) + return 1; + + if (!(CPL) || !(msw & 1)) + cpu_state.flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempw & 0x4fd5) | 2; + else + cpu_state.flags = (cpu_state.flags & 0x3200) | (tempw & 0x4dd5) | 2; + } flags_extract(); CLOCK_CYCLES(5); @@ -173,7 +247,7 @@ static int opPOPFD(uint32_t fetchdat) { uint32_t templ; - if ((eflags & VM_FLAG) && (IOPL < 3)) + if ((cpu_state.eflags & VM_FLAG) && (IOPL < 3)) { x86gpf(NULL, 0); return 1; @@ -181,15 +255,16 @@ static int opPOPFD(uint32_t fetchdat) templ = POP_L(); if (cpu_state.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; + if (!(CPL) || !(msw & 1)) cpu_state.flags = (templ & 0x7fd5) | 2; + else if (IOPLp) cpu_state.flags = (cpu_state.flags & 0x3000) | (templ & 0x4fd5) | 2; + else cpu_state.flags = (cpu_state.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; + templ &= is486 ? 0x3c0000 : 0; + templ |= ((cpu_state.eflags&3) << 16); + if (cpu_CR4_mask & CR4_VME) cpu_state.eflags = (templ >> 16) & 0x3f; + else if (CPUID) cpu_state.eflags = (templ >> 16) & 0x27; + else if (is486) cpu_state.eflags = (templ >> 16) & 7; + else cpu_state.eflags = (templ >> 16) & 3; flags_extract(); diff --git a/src/x86_ops_inc_dec.h b/src/x86_ops_inc_dec.h index b13070c..8b9509b 100644 --- a/src/x86_ops_inc_dec.h +++ b/src/x86_ops_inc_dec.h @@ -50,6 +50,8 @@ static int opINCDEC_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp=geteab(); if (cpu_state.abrt) return 1; if (rmdat&0x38) @@ -71,6 +73,8 @@ static int opINCDEC_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp=geteab(); if (cpu_state.abrt) return 1; if (rmdat&0x38) diff --git a/src/x86_ops_int.h b/src/x86_ops_int.h index f72ef60..3ac96f3 100644 --- a/src/x86_ops_int.h +++ b/src/x86_ops_int.h @@ -1,7 +1,7 @@ static int opINT3(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; @@ -15,7 +15,7 @@ static int opINT3(uint32_t fetchdat) static int opINT1(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; @@ -29,15 +29,39 @@ static int opINT1(uint32_t fetchdat) static int opINT(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - 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)) + uint8_t temp = getbytef(); + + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { - x86gpf(NULL,0); + if (cr4 & CR4_VME) + { + uint16_t t; + uint8_t d; + + cpl_override = 1; + t = readmemw(tr.base, 0x66) - 32; + cpl_override = 0; + if (cpu_state.abrt) return 1; + + t += (temp >> 3); + if (t <= tr.limit) + { + cpl_override = 1; + d = readmemb(tr.base, t);// + (temp >> 3)); + cpl_override = 0; + if (cpu_state.abrt) return 1; + + if (!(d & (1 << (temp & 7)))) + { + x86_int_sw_rm(temp); + PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); + return 1; + } + } + } + x86gpf_expected(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; @@ -80,7 +104,7 @@ static int opINTO(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; diff --git a/src/x86_ops_io.h b/src/x86_ops_io.h index 292bcb5..cd18934 100644 --- a/src/x86_ops_io.h +++ b/src/x86_ops_io.h @@ -5,6 +5,10 @@ static int opIN_AL_imm(uint32_t fetchdat) AL = inb(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opIN_AX_imm(uint32_t fetchdat) @@ -15,6 +19,10 @@ static int opIN_AX_imm(uint32_t fetchdat) AX = inw(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opIN_EAX_imm(uint32_t fetchdat) @@ -27,6 +35,10 @@ static int opIN_EAX_imm(uint32_t fetchdat) EAX = inl(port); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, -1, 0,1,0,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } @@ -37,6 +49,10 @@ static int opOUT_AL_imm(uint32_t fetchdat) outb(port, AL); CLOCK_CYCLES(10); PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; if (port == 0x64) return x86_was_reset; return 0; @@ -49,6 +65,10 @@ static int opOUT_AX_imm(uint32_t fetchdat) outw(port, AX); CLOCK_CYCLES(10); PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opOUT_EAX_imm(uint32_t fetchdat) @@ -61,6 +81,10 @@ static int opOUT_EAX_imm(uint32_t fetchdat) outl(port, EAX); CLOCK_CYCLES(10); PREFETCH_RUN(10, 2, -1, 0,0,0,1, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } @@ -70,6 +94,10 @@ static int opIN_AL_DX(uint32_t fetchdat) AL = inb(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opIN_AX_DX(uint32_t fetchdat) @@ -79,6 +107,10 @@ static int opIN_AX_DX(uint32_t fetchdat) AX = inw(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opIN_EAX_DX(uint32_t fetchdat) @@ -90,6 +122,10 @@ static int opIN_EAX_DX(uint32_t fetchdat) EAX = inl(DX); CLOCK_CYCLES(12); PREFETCH_RUN(12, 1, -1, 0,1,0,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } @@ -99,6 +135,10 @@ static int opOUT_AL_DX(uint32_t fetchdat) outb(DX, AL); CLOCK_CYCLES(11); PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return x86_was_reset; } static int opOUT_AX_DX(uint32_t fetchdat) @@ -109,6 +149,10 @@ static int opOUT_AX_DX(uint32_t fetchdat) outw(DX, AX); CLOCK_CYCLES(11); PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } static int opOUT_EAX_DX(uint32_t fetchdat) @@ -119,5 +163,9 @@ static int opOUT_EAX_DX(uint32_t fetchdat) check_io_perm(DX + 3); outl(DX, EAX); PREFETCH_RUN(11, 1, -1, 0,0,0,1, 0); + if (cpu_state.smi_pending) + return 1; + if (nmi && nmi_enable && nmi_mask) + return 1; return 0; } diff --git a/src/x86_ops_jump.h b/src/x86_ops_jump.h index 292102a..94cad2d 100644 --- a/src/x86_ops_jump.h +++ b/src/x86_ops_jump.h @@ -23,6 +23,8 @@ if (cond_ ## condition) \ { \ cpu_state.pc += offset; \ + if (!(cpu_state.op32 & 0x100)) \ + cpu_state.pc &= 0xffff; \ CLOCK_CYCLES_ALWAYS(timing_bt); \ CPU_BLOCK_END(); \ PREFETCH_RUN(timing_bt+timing_bnt, 2, -1, 0,0,0,0, 0); \ @@ -40,6 +42,7 @@ if (cond_ ## condition) \ { \ cpu_state.pc += offset; \ + cpu_state.pc &= 0xffff; \ CLOCK_CYCLES_ALWAYS(timing_bt); \ CPU_BLOCK_END(); \ PREFETCH_RUN(timing_bt+timing_bnt, 3, -1, 0,0,0,0, 0); \ @@ -95,6 +98,8 @@ static int opLOOPNE_w(uint32_t fetchdat) if (CX && !ZF_SET()) { cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); PREFETCH_FLUSH(); return 1; @@ -110,6 +115,8 @@ static int opLOOPNE_l(uint32_t fetchdat) if (ECX && !ZF_SET()) { cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); PREFETCH_FLUSH(); return 1; @@ -126,6 +133,8 @@ static int opLOOPE_w(uint32_t fetchdat) if (CX && ZF_SET()) { cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); PREFETCH_FLUSH(); return 1; @@ -141,6 +150,8 @@ static int opLOOPE_l(uint32_t fetchdat) if (ECX && ZF_SET()) { cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); PREFETCH_FLUSH(); return 1; @@ -157,6 +168,8 @@ static int opLOOP_w(uint32_t fetchdat) if (CX) { cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); PREFETCH_FLUSH(); return 1; @@ -172,6 +185,8 @@ static int opLOOP_l(uint32_t fetchdat) if (ECX) { cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); PREFETCH_FLUSH(); return 1; @@ -186,6 +201,8 @@ static int opJCXZ(uint32_t fetchdat) if (!CX) { cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CLOCK_CYCLES(4); CPU_BLOCK_END(); PREFETCH_RUN(9, 2, -1, 0,0,0,0, 0); @@ -202,6 +219,8 @@ static int opJECXZ(uint32_t fetchdat) if (!ECX) { cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CLOCK_CYCLES(4); CPU_BLOCK_END(); PREFETCH_RUN(9, 2, -1, 0,0,0,0, 0); @@ -217,6 +236,8 @@ static int opJMP_r8(uint32_t fetchdat) { int8_t offset = (int8_t)getbytef(); cpu_state.pc += offset; + if (!(cpu_state.op32 & 0x100)) + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); CLOCK_CYCLES((is486) ? 3 : 7); PREFETCH_RUN(7, 2, -1, 0,0,0,0, 0); @@ -227,6 +248,7 @@ static int opJMP_r16(uint32_t fetchdat) { int16_t offset = (int16_t)getwordf(); cpu_state.pc += offset; + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); CLOCK_CYCLES((is486) ? 3 : 7); PREFETCH_RUN(7, 3, -1, 0,0,0,0, 0); @@ -248,9 +270,9 @@ static int opJMP_far_a16(uint32_t fetchdat) { uint16_t addr = getwordf(); uint16_t seg = getword(); if (cpu_state.abrt) return 1; - uint32_t oxpc = cpu_state.pc; + uint32_t old_pc = cpu_state.pc; cpu_state.pc = addr; - loadcsjmp(seg, oxpc); + loadcsjmp(seg, old_pc); CPU_BLOCK_END(); PREFETCH_RUN(11, 5, -1, 0,0,0,0, 0); PREFETCH_FLUSH(); @@ -260,9 +282,9 @@ static int opJMP_far_a32(uint32_t fetchdat) { uint32_t addr = getlong(); uint16_t seg = getword(); if (cpu_state.abrt) return 1; - uint32_t oxpc = cpu_state.pc; + uint32_t old_pc = cpu_state.pc; cpu_state.pc = addr; - loadcsjmp(seg, oxpc); + loadcsjmp(seg, old_pc); CPU_BLOCK_END(); PREFETCH_RUN(11, 7, -1, 0,0,0,0, 0); PREFETCH_FLUSH(); @@ -274,6 +296,7 @@ static int opCALL_r16(uint32_t fetchdat) int16_t addr = (int16_t)getwordf(); PUSH_W(cpu_state.pc); cpu_state.pc += addr; + cpu_state.pc &= 0xffff; CPU_BLOCK_END(); CLOCK_CYCLES((is486) ? 3 : 7); PREFETCH_RUN(7, 3, -1, 0,0,1,0, 0); diff --git a/src/x86_ops_misc.h b/src/x86_ops_misc.h index beee6bd..4dc7566 100644 --- a/src/x86_ops_misc.h +++ b/src/x86_ops_misc.h @@ -46,12 +46,17 @@ static int opSETALC(uint32_t fetchdat) static int opF6_a16(uint32_t fetchdat) { - int tempws, tempws2; + int tempws, tempws2 = 0; uint16_t tempw, src16; uint8_t src, dst; int8_t temps; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + { + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + } dst = geteab(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { @@ -64,11 +69,15 @@ static int opF6_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x10: /*NOT b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); break; case 0x18: /*NEG b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(0 - dst); if (cpu_state.abrt) return 1; setsub8(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); @@ -77,8 +86,8 @@ static int opF6_a16(uint32_t fetchdat) case 0x20: /*MUL AL,b*/ AX = AL * dst; flags_rebuild(); - if (AH) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (AH) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(13); PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; @@ -86,8 +95,8 @@ static int opF6_a16(uint32_t fetchdat) 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); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(14); PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; @@ -101,7 +110,8 @@ static int opF6_a16(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -109,8 +119,8 @@ static int opF6_a16(uint32_t fetchdat) x86_int(0); return 1; } - CLOCK_CYCLES(is486 ? 16 : 14); - PREFETCH_RUN(is486 ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 16 : 14); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x38: /*IDIV AL,b*/ tempws = (int)(int16_t)AX; @@ -123,7 +133,8 @@ static int opF6_a16(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags|=0x8D5; /*Not a Cyrix*/ + cpu_state.flags|=0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -144,12 +155,14 @@ static int opF6_a16(uint32_t fetchdat) } static int opF6_a32(uint32_t fetchdat) { - int tempws, tempws2; + int tempws, tempws2 = 0; uint16_t tempw, src16; uint8_t src, dst; int8_t temps; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteab(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { @@ -162,11 +175,15 @@ static int opF6_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x10: /*NOT b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); break; case 0x18: /*NEG b*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteab(0 - dst); if (cpu_state.abrt) return 1; setsub8(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); @@ -175,8 +192,8 @@ static int opF6_a32(uint32_t fetchdat) case 0x20: /*MUL AL,b*/ AX = AL * dst; flags_rebuild(); - if (AH) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (AH) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(13); PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; @@ -184,8 +201,8 @@ static int opF6_a32(uint32_t fetchdat) 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); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(14); PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; @@ -199,7 +216,8 @@ static int opF6_a32(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -207,8 +225,8 @@ static int opF6_a32(uint32_t fetchdat) x86_int(0); return 1; } - CLOCK_CYCLES(is486 ? 16 : 14); - PREFETCH_RUN(is486 ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 16 : 14); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x38: /*IDIV AL,b*/ tempws = (int)(int16_t)AX; @@ -221,7 +239,8 @@ static int opF6_a32(uint32_t fetchdat) if (!cpu_iscyrix) { flags_rebuild(); - flags|=0x8D5; /*Not a Cyrix*/ + cpu_state.flags |= 0x8D5; /*Not a Cyrix*/ + cpu_state.flags &= ~1; } } else @@ -246,11 +265,13 @@ static int opF6_a32(uint32_t fetchdat) static int opF7_w_a16(uint32_t fetchdat) { uint32_t templ, templ2; - int tempws, tempws2; + int tempws, tempws2 = 0; int16_t temps16; uint16_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { @@ -263,11 +284,15 @@ static int opF7_w_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x10: /*NOT w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); break; case 0x18: /*NEG w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(0 - dst); if (cpu_state.abrt) return 1; setsub16(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); @@ -278,8 +303,8 @@ static int opF7_w_a16(uint32_t fetchdat) AX = templ & 0xFFFF; DX = templ >> 16; flags_rebuild(); - if (DX) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (DX) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(21); PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; @@ -288,8 +313,8 @@ static int opF7_w_a16(uint32_t fetchdat) 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); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(22); PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; @@ -308,8 +333,8 @@ static int opF7_w_a16(uint32_t fetchdat) x86_int(0); return 1; } - CLOCK_CYCLES(is486 ? 24 : 22); - PREFETCH_RUN(is486 ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 24 : 22); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); break; case 0x38: /*IDIV AX,w*/ tempws = (int)((DX << 16)|AX); @@ -340,11 +365,13 @@ static int opF7_w_a16(uint32_t fetchdat) static int opF7_w_a32(uint32_t fetchdat) { uint32_t templ, templ2; - int tempws, tempws2; + int tempws, tempws2 = 1; int16_t temps16; uint16_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteaw(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { @@ -357,11 +384,15 @@ static int opF7_w_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x10: /*NOT w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); break; case 0x18: /*NEG w*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(0 - dst); if (cpu_state.abrt) return 1; setsub16(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); @@ -372,8 +403,8 @@ static int opF7_w_a32(uint32_t fetchdat) AX = templ & 0xFFFF; DX = templ >> 16; flags_rebuild(); - if (DX) flags |= (C_FLAG | V_FLAG); - else flags &= ~(C_FLAG | V_FLAG); + if (DX) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(21); PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; @@ -382,8 +413,8 @@ static int opF7_w_a32(uint32_t fetchdat) 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); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(22); PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; @@ -402,8 +433,8 @@ static int opF7_w_a32(uint32_t fetchdat) x86_int(0); return 1; } - CLOCK_CYCLES(is486 ? 24 : 22); - PREFETCH_RUN(is486 ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 24 : 22); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); break; case 0x38: /*IDIV AX,w*/ tempws = (int)((DX << 16)|AX); @@ -438,6 +469,8 @@ static int opF7_l_a16(uint32_t fetchdat) uint32_t src, dst; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) @@ -451,11 +484,15 @@ static int opF7_l_a16(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); break; case 0x10: /*NOT l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); break; case 0x18: /*NEG l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(0 - dst); if (cpu_state.abrt) return 1; setsub32(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); @@ -466,8 +503,8 @@ static int opF7_l_a16(uint32_t fetchdat) EAX = temp64 & 0xffffffff; EDX = temp64 >> 32; flags_rebuild(); - if (EDX) flags |= (C_FLAG|V_FLAG); - else flags &= ~(C_FLAG|V_FLAG); + if (EDX) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.flags &= ~(C_FLAG|V_FLAG); CLOCK_CYCLES(21); PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); break; @@ -476,8 +513,8 @@ static int opF7_l_a16(uint32_t fetchdat) 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); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(38); PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); break; @@ -508,6 +545,8 @@ static int opF7_l_a32(uint32_t fetchdat) uint32_t src, dst; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); dst = geteal(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) @@ -521,11 +560,15 @@ static int opF7_l_a32(uint32_t fetchdat) PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); break; case 0x10: /*NOT l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(~dst); if (cpu_state.abrt) return 1; CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); break; case 0x18: /*NEG l*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(0 - dst); if (cpu_state.abrt) return 1; setsub32(0, dst); CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); @@ -536,8 +579,8 @@ static int opF7_l_a32(uint32_t fetchdat) EAX = temp64 & 0xffffffff; EDX = temp64 >> 32; flags_rebuild(); - if (EDX) flags |= (C_FLAG|V_FLAG); - else flags &= ~(C_FLAG|V_FLAG); + if (EDX) cpu_state.flags |= (C_FLAG|V_FLAG); + else cpu_state.flags &= ~(C_FLAG|V_FLAG); CLOCK_CYCLES(21); PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); break; @@ -546,8 +589,8 @@ static int opF7_l_a32(uint32_t fetchdat) 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); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) cpu_state.flags |= (C_FLAG | V_FLAG); + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(38); PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); break; @@ -576,12 +619,12 @@ static int opF7_l_a32(uint32_t fetchdat) static int opHLT(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { x86gpf(NULL,0); return 1; } - if (!((flags&I_FLAG) && pic_intpending)) + if (!((cpu_state.flags & I_FLAG) && pic_intpending)) { CLOCK_CYCLES_ALWAYS(100); cpu_state.pc--; @@ -617,6 +660,7 @@ static int opBOUND_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteaw(); high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -636,6 +680,7 @@ static int opBOUND_w_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteaw(); high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -656,6 +701,7 @@ static int opBOUND_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteal(); high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -675,6 +721,7 @@ static int opBOUND_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); low = geteal(); high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; @@ -692,7 +739,7 @@ static int opBOUND_l_a32(uint32_t fetchdat) static int opCLTS(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't CLTS\n"); x86gpf(NULL,0); @@ -734,8 +781,8 @@ static int opLOADALL(uint32_t fetchdat) x86gpf(NULL,0); return 1; } - msw = readmemw(0, 0x806); - flags = (readmemw(0, 0x818) & 0xffd5) | 2; + msw = (msw & 1) | readmemw(0, 0x806); + cpu_state.flags = (readmemw(0, 0x818) & 0xffd5) | 2; flags_extract(); tr.seg = readmemw(0, 0x816); cpu_state.pc = readmemw(0, 0x81A); @@ -753,17 +800,25 @@ static int opLOADALL(uint32_t fetchdat) CX = readmemw(0, 0x832); AX = readmemw(0, 0x834); es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); - _es.access = readmemb(0, 0x839); - _es.limit = readmemw(0, 0x83A); + cpu_state.seg_es.access = readmemb(0, 0x839); + cpu_state.seg_es.limit = readmemw(0, 0x83A); cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); - _cs.access = readmemb(0, 0x83F); - _cs.limit = readmemw(0, 0x840); + cpu_state.seg_cs.access = readmemb(0, 0x83F); + cpu_state.seg_cs.limit = readmemw(0, 0x840); ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); - _ss.access = readmemb(0, 0x845); - _ss.limit = readmemw(0, 0x846); + cpu_state.seg_ss.access = readmemb(0, 0x845); + cpu_state.seg_ss.limit = readmemw(0, 0x846); + if (cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && cpu_state.seg_ss.limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16); - _ds.access = readmemb(0, 0x84B); - _ds.limit = readmemw(0, 0x84C); + cpu_state.seg_ds.access = readmemb(0, 0x84B); + cpu_state.seg_ds.limit = readmemw(0, 0x84C); + if (cpu_state.seg_ds.base == 0 && cpu_state.seg_ds.limit_low == 0 && cpu_state.seg_ds.limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; gdt.base = readmemw(0, 0x84E) | (readmemb(0, 0x850) << 16); gdt.limit = readmemw(0, 0x852); ldt.base = readmemw(0, 0x854) | (readmemb(0, 0x856) << 16); @@ -801,10 +856,33 @@ static void loadall_load_segment(uint32_t addr, x86seg *s) 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; + if (s == &cpu_state.seg_cs) + use32 = (segdat3 & 0x40) ? 0x300 : 0; + if (s == &cpu_state.seg_ss) + stack32 = (segdat3 & 0x40) ? 1 : 0; + + cpu_cur_status &= ~(CPU_STATUS_USE32 | CPU_STATUS_STACK32); + if (use32) + cpu_cur_status |= CPU_STATUS_USE32; + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; set_segment_limit(s, segdat3); + + if (s == &cpu_state.seg_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } } static int opLOADALL386(uint32_t fetchdat) @@ -812,8 +890,8 @@ 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); + cpu_state.flags = readmemw(0, la_addr + 4); + cpu_state.eflags = readmemw(0, la_addr + 6); flags_extract(); cpu_state.pc = readmeml(0, la_addr + 8); EDI = readmeml(0, la_addr + 0xC); @@ -839,14 +917,15 @@ static int opLOADALL386(uint32_t fetchdat) 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); + loadall_load_segment(la_addr + 0x84, &cpu_state.seg_gs); + loadall_load_segment(la_addr + 0x90, &cpu_state.seg_fs); + loadall_load_segment(la_addr + 0x9c, &cpu_state.seg_ds); + loadall_load_segment(la_addr + 0xa8, &cpu_state.seg_ss); + loadall_load_segment(la_addr + 0xb4, &cpu_state.seg_cs); + loadall_load_segment(la_addr + 0xc0, &cpu_state.seg_es); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; CLOCK_CYCLES(350); return 0; @@ -867,7 +946,7 @@ static int opCPUID(uint32_t fetchdat) static int opRDMSR(uint32_t fetchdat) { - if (cpu_hasMSR) + if (cpu_has_feature(CPU_FEATURE_MSR)) { cpu_RDMSR(); CLOCK_CYCLES(9); @@ -880,7 +959,7 @@ static int opRDMSR(uint32_t fetchdat) static int opWRMSR(uint32_t fetchdat) { - if (cpu_hasMSR) + if (cpu_has_feature(CPU_FEATURE_MSR)) { cpu_WRMSR(); CLOCK_CYCLES(9); @@ -891,3 +970,39 @@ static int opWRMSR(uint32_t fetchdat) return 1; } +static int opSYSENTER(uint32_t fetchdat) +{ + if (!(cr0 & 1) || !(sysenter_cs & 0xfffc)) + { + x86gpf(NULL,0); + return 1; + } +// pclog("opSYSENTER: CS=%04x EIP=%08x ESP=%08x %04x:%08x %i\n", sysenter_cs, sysenter_eip, sysenter_esp, CS,cpu_state.pc, times); + sysenter(); + CPU_BLOCK_END(); + return 0; +} + +static int opSYSEXIT(uint32_t fetchdat) +{ + if (!(cr0 & 1) || !(sysenter_cs & 0xfffc) || CPL) + { + x86gpf(NULL,0); + return 1; + } +// pclog("opSYSEXIT\n"); + sysexit(); + CPU_BLOCK_END(); + return 0; +} + +static int opHINTNOP_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + return 0; +} +static int opHINTNOP_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + return 0; +} diff --git a/src/x86_ops_mmx.h b/src/x86_ops_mmx.h index 4397a39..712d185 100644 --- a/src/x86_ops_mmx.h +++ b/src/x86_ops_mmx.h @@ -11,12 +11,13 @@ } \ else \ { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ src.q = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; \ CLOCK_CYCLES(2); \ } #define MMX_ENTER() \ - if (!cpu_hasMMX) \ + if (!cpu_has_feature(CPU_FEATURE_MMX)) \ { \ cpu_state.pc = cpu_state.oldpc; \ x86illegal(); \ @@ -31,13 +32,13 @@ static int opEMMS(uint32_t fetchdat) { - if (!cpu_hasMMX) + if (!cpu_has_feature(CPU_FEATURE_MMX)) { cpu_state.pc = cpu_state.oldpc; x86illegal(); return 1; } - if (cr0 & 4) + if (cr0 & 0xc) { x86_int(7); return 1; diff --git a/src/x86_ops_mmx_arith.h b/src/x86_ops_mmx_arith.h index 0a66eea..231662c 100644 --- a/src/x86_ops_mmx_arith.h +++ b/src/x86_ops_mmx_arith.h @@ -293,7 +293,8 @@ static int opPMULLW_a16(uint32_t fetchdat) else { MMX_REG src; - + + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].w[0] *= src.w[0]; @@ -321,6 +322,7 @@ static int opPMULLW_a32(uint32_t fetchdat) { MMX_REG src; + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].w[0] *= src.w[0]; @@ -349,6 +351,7 @@ static int opPMULHW_a16(uint32_t fetchdat) { MMX_REG src; + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; @@ -376,6 +379,7 @@ static int opPMULHW_a32(uint32_t fetchdat) { MMX_REG src; + SEG_CHECK_READ(cpu_state.ea_seg); src.l[0] = readmeml(easeg, cpu_state.eaaddr); src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; diff --git a/src/x86_ops_mmx_cmp.h b/src/x86_ops_mmx_cmp.h index ea090f5..b61ac67 100644 --- a/src/x86_ops_mmx_cmp.h +++ b/src/x86_ops_mmx_cmp.h @@ -166,7 +166,7 @@ static int opPCMPEQD_a32(uint32_t fetchdat) MMX_ENTER(); - fetch_ea_16(fetchdat); + fetch_ea_32(fetchdat); MMX_GETSRC(); cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; @@ -195,7 +195,7 @@ static int opPCMPGTD_a32(uint32_t fetchdat) MMX_ENTER(); - fetch_ea_16(fetchdat); + fetch_ea_32(fetchdat); MMX_GETSRC(); cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; diff --git a/src/x86_ops_mmx_mov.h b/src/x86_ops_mmx_mov.h index 2d43663..548b6c4 100644 --- a/src/x86_ops_mmx_mov.h +++ b/src/x86_ops_mmx_mov.h @@ -12,7 +12,8 @@ static int opMOVD_l_mm_a16(uint32_t fetchdat) else { uint32_t dst; - + + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].l[0] = dst; cpu_state.MM[cpu_reg].l[1] = 0; @@ -35,7 +36,8 @@ static int opMOVD_l_mm_a32(uint32_t fetchdat) else { uint32_t dst; - + + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].l[0] = dst; cpu_state.MM[cpu_reg].l[1] = 0; @@ -48,7 +50,7 @@ static int opMOVD_l_mm_a32(uint32_t fetchdat) static int opMOVD_mm_l_a16(uint32_t fetchdat) { MMX_ENTER(); - + fetch_ea_16(fetchdat); if (cpu_mod == 3) { @@ -57,6 +59,7 @@ static int opMOVD_mm_l_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); @@ -66,6 +69,52 @@ static int opMOVD_mm_l_a16(uint32_t fetchdat) static int opMOVD_mm_l_a32(uint32_t fetchdat) { MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.MM[cpu_reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} + +/*Cyrix maps both MOVD and SMINT to the same opcode*/ +static int opMOVD_mm_l_a16_cx(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + return opSMINT(fetchdat); + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.MM[cpu_reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + SEG_CHECK_WRITE(cpu_state.ea_seg); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_mm_l_a32_cx(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + return opSMINT(fetchdat); + + MMX_ENTER(); fetch_ea_32(fetchdat); if (cpu_mod == 3) @@ -75,6 +124,7 @@ static int opMOVD_mm_l_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); @@ -96,6 +146,7 @@ static int opMOVQ_q_mm_a16(uint32_t fetchdat) { uint64_t dst; + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].q = dst; CLOCK_CYCLES(2); @@ -116,6 +167,7 @@ static int opMOVQ_q_mm_a32(uint32_t fetchdat) { uint64_t dst; + SEG_CHECK_READ(cpu_state.ea_seg); dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; cpu_state.MM[cpu_reg].q = dst; CLOCK_CYCLES(2); @@ -135,8 +187,9 @@ static int opMOVQ_mm_q_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); - writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); } return 0; @@ -153,6 +206,7 @@ static int opMOVQ_mm_q_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1; CLOCK_CYCLES(2); diff --git a/src/x86_ops_mmx_pack.h b/src/x86_ops_mmx_pack.h index cdba2a2..5b8b798 100644 --- a/src/x86_ops_mmx_pack.h +++ b/src/x86_ops_mmx_pack.h @@ -12,6 +12,7 @@ static int opPUNPCKLDQ_a16(uint32_t fetchdat) { uint32_t src; + SEG_CHECK_READ(cpu_state.ea_seg); src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].l[1] = src; @@ -32,7 +33,8 @@ static int opPUNPCKLDQ_a32(uint32_t fetchdat) else { uint32_t src; - + + SEG_CHECK_READ(cpu_state.ea_seg); src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; cpu_state.MM[cpu_reg].l[1] = src; diff --git a/src/x86_ops_mmx_shift.h b/src/x86_ops_mmx_shift.h index ad3fc16..d641279 100644 --- a/src/x86_ops_mmx_shift.h +++ b/src/x86_ops_mmx_shift.h @@ -6,6 +6,7 @@ } \ else \ { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ shift = readmemb(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; \ CLOCK_CYCLES(2); \ } diff --git a/src/x86_ops_mov.h b/src/x86_ops_mov.h index 32b88c9..6a0a087 100644 --- a/src/x86_ops_mov.h +++ b/src/x86_ops_mov.h @@ -181,6 +181,8 @@ static int opMOV_b_imm_a16(uint32_t fetchdat) { uint8_t temp; fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = readmemb(cs,cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(temp); @@ -192,6 +194,8 @@ static int opMOV_b_imm_a32(uint32_t fetchdat) { uint8_t temp; fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getbyte(); if (cpu_state.abrt) return 1; seteab(temp); CLOCK_CYCLES(timing_rr); @@ -203,6 +207,8 @@ static int opMOV_w_imm_a16(uint32_t fetchdat) { uint16_t temp; fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getword(); if (cpu_state.abrt) return 1; seteaw(temp); CLOCK_CYCLES(timing_rr); @@ -213,6 +219,8 @@ static int opMOV_w_imm_a32(uint32_t fetchdat) { uint16_t temp; fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getword(); if (cpu_state.abrt) return 1; seteaw(temp); CLOCK_CYCLES(timing_rr); @@ -223,6 +231,8 @@ static int opMOV_l_imm_a16(uint32_t fetchdat) { uint32_t temp; fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getlong(); if (cpu_state.abrt) return 1; seteal(temp); CLOCK_CYCLES(timing_rr); @@ -233,6 +243,8 @@ static int opMOV_l_imm_a32(uint32_t fetchdat) { uint32_t temp; fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = getlong(); if (cpu_state.abrt) return 1; seteal(temp); CLOCK_CYCLES(timing_rr); @@ -244,7 +256,10 @@ static int opMOV_l_imm_a32(uint32_t fetchdat) static int opMOV_AL_a16(uint32_t fetchdat) { uint16_t addr = getwordf(); - uint8_t temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + uint8_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); @@ -253,7 +268,10 @@ static int opMOV_AL_a16(uint32_t fetchdat) static int opMOV_AL_a32(uint32_t fetchdat) { uint32_t addr = getlong(); - uint8_t temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + uint8_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); @@ -262,7 +280,10 @@ static int opMOV_AL_a32(uint32_t fetchdat) static int opMOV_AX_a16(uint32_t fetchdat) { uint16_t addr = getwordf(); - uint16_t temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + uint16_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+1); + temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); @@ -271,7 +292,10 @@ static int opMOV_AX_a16(uint32_t fetchdat) static int opMOV_AX_a32(uint32_t fetchdat) { uint32_t addr = getlong(); - uint16_t temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + uint16_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+1); + temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); @@ -280,7 +304,10 @@ static int opMOV_AX_a32(uint32_t fetchdat) static int opMOV_EAX_a16(uint32_t fetchdat) { uint16_t addr = getwordf(); - uint32_t temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+3); + temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; EAX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 3, -1, 0,1,0,0, 0); @@ -289,7 +316,10 @@ static int opMOV_EAX_a16(uint32_t fetchdat) static int opMOV_EAX_a32(uint32_t fetchdat) { uint32_t addr = getlong(); - uint32_t temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); + CHECK_READ(cpu_state.ea_seg, addr, addr+3); + temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; EAX = temp; CLOCK_CYCLES((is486) ? 1 : 4); PREFETCH_RUN(4, 5, -1, 0,1,0,0, 1); @@ -299,6 +329,7 @@ static int opMOV_EAX_a32(uint32_t fetchdat) static int opMOV_a16_AL(uint32_t fetchdat) { uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); writememb(cpu_state.ea_seg->base, addr, AL); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); @@ -307,6 +338,7 @@ static int opMOV_a16_AL(uint32_t fetchdat) static int opMOV_a32_AL(uint32_t fetchdat) { uint32_t addr = getlong(); + SEG_CHECK_WRITE(cpu_state.ea_seg); writememb(cpu_state.ea_seg->base, addr, AL); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); @@ -315,6 +347,7 @@ static int opMOV_a32_AL(uint32_t fetchdat) static int opMOV_a16_AX(uint32_t fetchdat) { uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); writememw(cpu_state.ea_seg->base, addr, AX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); @@ -323,6 +356,7 @@ static int opMOV_a16_AX(uint32_t fetchdat) static int opMOV_a32_AX(uint32_t fetchdat) { uint32_t addr = getlong(); if (cpu_state.abrt) return 1; + SEG_CHECK_WRITE(cpu_state.ea_seg); writememw(cpu_state.ea_seg->base, addr, AX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); @@ -331,6 +365,7 @@ static int opMOV_a32_AX(uint32_t fetchdat) static int opMOV_a16_EAX(uint32_t fetchdat) { uint16_t addr = getwordf(); + SEG_CHECK_WRITE(cpu_state.ea_seg); writememl(cpu_state.ea_seg->base, addr, EAX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); @@ -339,6 +374,7 @@ static int opMOV_a16_EAX(uint32_t fetchdat) static int opMOV_a32_EAX(uint32_t fetchdat) { uint32_t addr = getlong(); if (cpu_state.abrt) return 1; + SEG_CHECK_WRITE(cpu_state.ea_seg); writememl(cpu_state.ea_seg->base, addr, EAX); CLOCK_CYCLES((is486) ? 1 : 2); PREFETCH_RUN(2, 5, -1, 0,0,0,1, 1); @@ -389,7 +425,10 @@ static int opLEA_l_a32(uint32_t fetchdat) static int opXLAT_a16(uint32_t fetchdat) { uint32_t addr = (BX + AL)&0xFFFF; - uint8_t temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); @@ -398,7 +437,10 @@ static int opXLAT_a16(uint32_t fetchdat) static int opXLAT_a32(uint32_t fetchdat) { uint32_t addr = EBX + AL; - uint8_t temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; AL = temp; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); @@ -416,6 +458,7 @@ static int opMOV_b_r_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(getr8(cpu_reg)); CLOCK_CYCLES(is486 ? 1 : 2); @@ -434,6 +477,7 @@ static int opMOV_b_r_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); seteab(getr8(cpu_reg)); CLOCK_CYCLES(is486 ? 1 : 2); @@ -452,6 +496,7 @@ static int opMOV_w_r_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); seteaw(cpu_state.regs[cpu_reg].w); CLOCK_CYCLES(is486 ? 1 : 2); @@ -470,6 +515,7 @@ static int opMOV_w_r_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); seteaw(cpu_state.regs[cpu_reg].w); CLOCK_CYCLES(is486 ? 1 : 2); @@ -488,6 +534,7 @@ static int opMOV_l_r_a16(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); seteal(cpu_state.regs[cpu_reg].l); CLOCK_CYCLES(is486 ? 1 : 2); @@ -506,6 +553,7 @@ static int opMOV_l_r_a32(uint32_t fetchdat) } else { + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); seteal(cpu_state.regs[cpu_reg].l); CLOCK_CYCLES(is486 ? 1 : 2); @@ -526,6 +574,7 @@ static int opMOV_r_b_a16(uint32_t fetchdat) else { uint8_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); temp = geteab(); if (cpu_state.abrt) return 1; setr8(cpu_reg, temp); @@ -546,6 +595,7 @@ static int opMOV_r_b_a32(uint32_t fetchdat) else { uint8_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); temp = geteab(); if (cpu_state.abrt) return 1; setr8(cpu_reg, temp); @@ -566,6 +616,7 @@ static int opMOV_r_w_a16(uint32_t fetchdat) else { uint16_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -586,6 +637,7 @@ static int opMOV_r_w_a32(uint32_t fetchdat) else { uint16_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -606,6 +658,7 @@ static int opMOV_r_l_a16(uint32_t fetchdat) else { uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); temp = geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp; @@ -626,6 +679,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) else { uint32_t temp; + SEG_CHECK_READ(cpu_state.ea_seg); CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); temp = geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp; @@ -646,6 +700,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) else \ { \ uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); \ temp = geteaw(); if (cpu_state.abrt) return 1; \ cpu_state.regs[cpu_reg].w = temp; \ @@ -664,6 +719,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) else \ { \ uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); \ temp = geteaw(); if (cpu_state.abrt) return 1; \ cpu_state.regs[cpu_reg].w = temp; \ @@ -682,6 +738,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) else \ { \ uint32_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); \ temp = geteal(); if (cpu_state.abrt) return 1; \ cpu_state.regs[cpu_reg].l = temp; \ @@ -701,6 +758,7 @@ static int opMOV_r_l_a32(uint32_t fetchdat) { \ uint32_t temp; \ CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ temp = geteal(); if (cpu_state.abrt) return 1; \ cpu_state.regs[cpu_reg].l = temp; \ } \ diff --git a/src/x86_ops_mov_ctrl.h b/src/x86_ops_mov_ctrl.h index 088cc73..962d1b2 100644 --- a/src/x86_ops_mov_ctrl.h +++ b/src/x86_ops_mov_ctrl.h @@ -1,6 +1,6 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load from CRx\n"); x86gpf(NULL, 0); @@ -21,7 +21,7 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat) cpu_state.regs[cpu_rm].l = cr3; break; case 4: - if (cpu_hasCR4) + if (cpu_has_feature(CPU_FEATURE_CR4)) { cpu_state.regs[cpu_rm].l = cr4; break; @@ -38,7 +38,7 @@ static int opMOV_r_CRx_a16(uint32_t fetchdat) } static int opMOV_r_CRx_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load from CRx\n"); x86gpf(NULL, 0); @@ -59,7 +59,7 @@ static int opMOV_r_CRx_a32(uint32_t fetchdat) cpu_state.regs[cpu_rm].l = cr3; break; case 4: - if (cpu_hasCR4) + if (cpu_has_feature(CPU_FEATURE_CR4)) { cpu_state.regs[cpu_rm].l = cr4; break; @@ -77,7 +77,7 @@ static int opMOV_r_CRx_a32(uint32_t fetchdat) static int opMOV_r_DRx_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load from DRx\n"); x86gpf(NULL, 0); @@ -91,7 +91,7 @@ static int opMOV_r_DRx_a16(uint32_t fetchdat) } static int opMOV_r_DRx_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load from DRx\n"); x86gpf(NULL, 0); @@ -108,7 +108,7 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) { uint32_t old_cr0 = cr0; - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load CRx\n"); x86gpf(NULL,0); @@ -131,6 +131,10 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) cpu_cache_int_enabled = 0; if (is486 && ((cr0 ^ old_cr0) & (1 << 30))) cpu_update_waitstates(); + if (cr0 & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; break; case 2: cr2 = cpu_state.regs[cpu_rm].l; @@ -140,7 +144,7 @@ static int opMOV_CRx_r_a16(uint32_t fetchdat) flushmmucache(); break; case 4: - if (cpu_hasCR4) + if (cpu_has_feature(CPU_FEATURE_CR4)) { cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; break; @@ -160,7 +164,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) { uint32_t old_cr0 = cr0; - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load CRx\n"); x86gpf(NULL,0); @@ -183,6 +187,10 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) cpu_cache_int_enabled = 0; if (is486 && ((cr0 ^ old_cr0) & (1 << 30))) cpu_update_waitstates(); + if (cr0 & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; break; case 2: cr2 = cpu_state.regs[cpu_rm].l; @@ -192,7 +200,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) flushmmucache(); break; case 4: - if (cpu_hasCR4) + if (cpu_has_feature(CPU_FEATURE_CR4)) { cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; break; @@ -211,7 +219,7 @@ static int opMOV_CRx_r_a32(uint32_t fetchdat) static int opMOV_DRx_r_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load DRx\n"); x86gpf(NULL, 0); @@ -225,7 +233,7 @@ static int opMOV_DRx_r_a16(uint32_t fetchdat) } static int opMOV_DRx_r_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load DRx\n"); x86gpf(NULL, 0); @@ -240,7 +248,7 @@ static int opMOV_DRx_r_a32(uint32_t fetchdat) static int opMOV_r_TRx_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load from TRx\n"); x86gpf(NULL, 0); @@ -254,7 +262,7 @@ static int opMOV_r_TRx_a16(uint32_t fetchdat) } static int opMOV_r_TRx_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load from TRx\n"); x86gpf(NULL, 0); @@ -269,7 +277,7 @@ static int opMOV_r_TRx_a32(uint32_t fetchdat) static int opMOV_TRx_r_a16(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load TRx\n"); x86gpf(NULL, 0); @@ -282,7 +290,7 @@ static int opMOV_TRx_r_a16(uint32_t fetchdat) } static int opMOV_TRx_r_a32(uint32_t fetchdat) { - if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + if ((CPL || (cpu_state.eflags&VM_FLAG)) && (cr0&1)) { pclog("Can't load TRx\n"); x86gpf(NULL, 0); diff --git a/src/x86_ops_mov_seg.h b/src/x86_ops_mov_seg.h index 5153bb1..54a30cb 100644 --- a/src/x86_ops_mov_seg.h +++ b/src/x86_ops_mov_seg.h @@ -1,7 +1,9 @@ static int opMOV_w_seg_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -31,7 +33,9 @@ static int opMOV_w_seg_a16(uint32_t fetchdat) static int opMOV_w_seg_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -62,7 +66,9 @@ static int opMOV_w_seg_a32(uint32_t fetchdat) static int opMOV_l_seg_a16(uint32_t fetchdat) { fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -98,7 +104,9 @@ static int opMOV_l_seg_a16(uint32_t fetchdat) static int opMOV_l_seg_a32(uint32_t fetchdat) { fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + switch (rmdat & 0x38) { case 0x00: /*ES*/ @@ -137,34 +145,35 @@ static int opMOV_seg_w_a16(uint32_t fetchdat) uint16_t new_seg; fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_seg=geteaw(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { case 0x00: /*ES*/ - loadseg(new_seg, &_es); + loadseg(new_seg, &cpu_state.seg_es); break; case 0x18: /*DS*/ - loadseg(new_seg, &_ds); + loadseg(new_seg, &cpu_state.seg_ds); break; case 0x10: /*SS*/ - loadseg(new_seg, &_ss); + loadseg(new_seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; fetchdat = fastreadl(cs + cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return 1; case 0x20: /*FS*/ - loadseg(new_seg, &_fs); + loadseg(new_seg, &cpu_state.seg_fs); break; case 0x28: /*GS*/ - loadseg(new_seg, &_gs); + loadseg(new_seg, &cpu_state.seg_gs); break; } @@ -177,34 +186,35 @@ static int opMOV_seg_w_a32(uint32_t fetchdat) uint16_t new_seg; fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); new_seg=geteaw(); if (cpu_state.abrt) return 1; switch (rmdat & 0x38) { case 0x00: /*ES*/ - loadseg(new_seg, &_es); + loadseg(new_seg, &cpu_state.seg_es); break; case 0x18: /*DS*/ - loadseg(new_seg, &_ds); + loadseg(new_seg, &cpu_state.seg_ds); break; case 0x10: /*SS*/ - loadseg(new_seg, &_ss); + loadseg(new_seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; fetchdat = fastreadl(cs + cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return 1; case 0x20: /*FS*/ - loadseg(new_seg, &_fs); + loadseg(new_seg, &cpu_state.seg_fs); break; case 0x28: /*GS*/ - loadseg(new_seg, &_gs); + loadseg(new_seg, &cpu_state.seg_gs); break; } @@ -220,9 +230,10 @@ static int opLDS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; CLOCK_CYCLES(7); @@ -235,9 +246,10 @@ static int opLDS_w_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; CLOCK_CYCLES(7); @@ -251,9 +263,10 @@ static int opLDS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; CLOCK_CYCLES(7); @@ -267,9 +280,10 @@ static int opLDS_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ds); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; CLOCK_CYCLES(7); @@ -283,9 +297,10 @@ static int opLSS_w_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; CLOCK_CYCLES(7); @@ -298,9 +313,10 @@ static int opLSS_w_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmemw(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; - loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = addr; CLOCK_CYCLES(7); @@ -314,9 +330,10 @@ static int opLSS_l_a16(uint32_t fetchdat) fetch_ea_16(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; CLOCK_CYCLES(7); @@ -330,9 +347,10 @@ static int opLSS_l_a32(uint32_t fetchdat) fetch_ea_32(fetchdat); ILLEGAL_ON(cpu_mod == 3); + SEG_CHECK_READ(cpu_state.ea_seg); addr = readmeml(easeg, cpu_state.eaaddr); seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; - loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + loadseg(seg, &cpu_state.seg_ss); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = addr; CLOCK_CYCLES(7); @@ -346,6 +364,7 @@ static int opLSS_l_a32(uint32_t fetchdat) uint16_t addr, seg; \ \ fetch_ea_16(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ addr = readmemw(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ @@ -362,6 +381,7 @@ static int opLSS_l_a32(uint32_t fetchdat) uint16_t addr, seg; \ \ fetch_ea_32(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ addr = readmemw(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ @@ -379,6 +399,7 @@ static int opLSS_l_a32(uint32_t fetchdat) uint16_t seg; \ \ fetch_ea_16(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ addr = readmeml(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ @@ -396,6 +417,7 @@ static int opLSS_l_a32(uint32_t fetchdat) uint16_t seg; \ \ fetch_ea_32(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ ILLEGAL_ON(cpu_mod == 3); \ addr = readmeml(easeg, cpu_state.eaaddr); \ seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ @@ -407,6 +429,6 @@ static int opLSS_l_a32(uint32_t fetchdat) return 0; \ } -opLsel(ES, _es) -opLsel(FS, _fs) -opLsel(GS, _gs) +opLsel(ES, cpu_state.seg_es) +opLsel(FS, cpu_state.seg_fs) +opLsel(GS, cpu_state.seg_gs) diff --git a/src/x86_ops_movx.h b/src/x86_ops_movx.h index 9dfced8..2f679b0 100644 --- a/src/x86_ops_movx.h +++ b/src/x86_ops_movx.h @@ -3,6 +3,8 @@ static int opMOVZX_w_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; @@ -15,6 +17,8 @@ static int opMOVZX_w_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; @@ -27,6 +31,8 @@ static int opMOVZX_l_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; @@ -39,6 +45,8 @@ static int opMOVZX_l_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; @@ -51,6 +59,8 @@ static int opMOVZX_w_w_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -63,6 +73,8 @@ static int opMOVZX_w_w_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -75,6 +87,8 @@ static int opMOVZX_l_w_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; @@ -87,6 +101,8 @@ static int opMOVZX_l_w_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; @@ -100,6 +116,8 @@ static int opMOVSX_w_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; if (temp & 0x80) @@ -114,6 +132,8 @@ static int opMOVSX_w_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = (uint16_t)temp; if (temp & 0x80) @@ -128,6 +148,8 @@ static int opMOVSX_l_b_a16(uint32_t fetchdat) uint8_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x80) @@ -142,6 +164,8 @@ static int opMOVSX_l_b_a32(uint32_t fetchdat) uint8_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x80) @@ -156,6 +180,8 @@ static int opMOVSX_l_w_a16(uint32_t fetchdat) uint16_t temp; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x8000) @@ -170,6 +196,8 @@ static int opMOVSX_l_w_a32(uint32_t fetchdat) uint16_t temp; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = (uint32_t)temp; if (temp & 0x8000) diff --git a/src/x86_ops_msr.h b/src/x86_ops_msr.h index a3080a8..c2d3c3c 100644 --- a/src/x86_ops_msr.h +++ b/src/x86_ops_msr.h @@ -1,6 +1,6 @@ static int opRDTSC(uint32_t fetchdat) { - if (!cpu_hasrdtsc) + if (!cpu_has_feature(CPU_FEATURE_RDTSC)) { cpu_state.pc = cpu_state.oldpc; x86illegal(); diff --git a/src/x86_ops_mul.h b/src/x86_ops_mul.h index 9a316b9..5971140 100644 --- a/src/x86_ops_mul.h +++ b/src/x86_ops_mul.h @@ -4,14 +4,16 @@ static int opIMUL_w_iw_a16(uint32_t fetchdat) int16_t tempw, tempw2; fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getword(); if (cpu_state.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); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); @@ -24,14 +26,16 @@ static int opIMUL_w_iw_a32(uint32_t fetchdat) int16_t tempw, tempw2; fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getword(); if (cpu_state.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); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); @@ -45,14 +49,16 @@ static int opIMUL_l_il_a16(uint32_t fetchdat) int32_t templ, templ2; fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getlong(); if (cpu_state.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); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; CLOCK_CYCLES(25); @@ -65,14 +71,16 @@ static int opIMUL_l_il_a32(uint32_t fetchdat) int32_t templ, templ2; fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getlong(); if (cpu_state.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); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; CLOCK_CYCLES(25); @@ -86,15 +94,17 @@ static int opIMUL_w_ib_a16(uint32_t fetchdat) int16_t tempw, tempw2; fetch_ea_16(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getbyte(); if (cpu_state.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); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); @@ -107,15 +117,17 @@ static int opIMUL_w_ib_a32(uint32_t fetchdat) int16_t tempw, tempw2; fetch_ea_32(fetchdat); - + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + tempw = geteaw(); if (cpu_state.abrt) return 1; tempw2 = getbyte(); if (cpu_state.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); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].w = templ & 0xffff; CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); @@ -129,14 +141,17 @@ static int opIMUL_l_ib_a16(uint32_t fetchdat) int32_t templ, templ2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getbyte(); if (cpu_state.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); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; CLOCK_CYCLES(20); @@ -149,14 +164,17 @@ static int opIMUL_l_ib_a32(uint32_t fetchdat) int32_t templ, templ2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = geteal(); if (cpu_state.abrt) return 1; templ2 = getbyte(); if (cpu_state.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); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; CLOCK_CYCLES(20); @@ -171,12 +189,15 @@ static int opIMUL_w_w_a16(uint32_t fetchdat) int32_t templ; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = templ & 0xFFFF; flags_rebuild(); - if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(18); PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 0); @@ -187,12 +208,15 @@ static int opIMUL_w_w_a32(uint32_t fetchdat) int32_t templ; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = templ & 0xFFFF; flags_rebuild(); - if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((templ >> 15) != 0 && (templ >> 15) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(18); PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 1); @@ -204,12 +228,15 @@ static int opIMUL_l_l_a16(uint32_t fetchdat) int64_t temp64; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; flags_rebuild(); - if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(30); PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 0); @@ -220,12 +247,15 @@ static int opIMUL_l_l_a32(uint32_t fetchdat) int64_t temp64; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; flags_rebuild(); - if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; - else flags &= ~(C_FLAG | V_FLAG); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) cpu_state.flags |= C_FLAG | V_FLAG; + else cpu_state.flags &= ~(C_FLAG | V_FLAG); CLOCK_CYCLES(30); PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 1); diff --git a/src/x86_ops_pmode.h b/src/x86_ops_pmode.h index 426776e..3578b5f 100644 --- a/src/x86_ops_pmode.h +++ b/src/x86_ops_pmode.h @@ -4,6 +4,8 @@ static int opARPL_a16(uint32_t fetchdat) NOTRM fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); pclog("ARPL_a16\n"); temp_seg = geteaw(); if (cpu_state.abrt) return 1; @@ -12,10 +14,10 @@ static int opARPL_a16(uint32_t fetchdat) { temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); seteaw(temp_seg); if (cpu_state.abrt) return 1; - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; } else - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; CLOCK_CYCLES(is486 ? 9 : 20); PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 0); @@ -27,7 +29,9 @@ static int opARPL_a32(uint32_t fetchdat) NOTRM fetch_ea_32(fetchdat); - pclog("ARPL_a32\n"); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); + pclog("ARPL_a32\n"); temp_seg = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); @@ -35,10 +39,10 @@ static int opARPL_a32(uint32_t fetchdat) { temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); seteaw(temp_seg); if (cpu_state.abrt) return 1; - flags |= Z_FLAG; + cpu_state.flags |= Z_FLAG; } else - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; CLOCK_CYCLES(is486 ? 9 : 20); PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 1); @@ -53,11 +57,13 @@ static int opARPL_a32(uint32_t fetchdat) \ NOTRM \ fetch_ea(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ \ sel = geteaw(); if (cpu_state.abrt) return 1; \ \ flags_rebuild(); \ - if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ + if (!(sel & 0xfffc)) { cpu_state.flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ if (valid) \ { \ @@ -65,7 +71,7 @@ static int opARPL_a32(uint32_t fetchdat) desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ cpl_override = 0; if (cpu_state.abrt) return 1; \ } \ - flags &= ~Z_FLAG; \ + cpu_state.flags &= ~Z_FLAG; \ if ((desc & 0x1f00) == 0x000) valid = 0; \ if ((desc & 0x1f00) == 0x800) valid = 0; \ if ((desc & 0x1f00) == 0xa00) valid = 0; \ @@ -77,7 +83,7 @@ static int opARPL_a32(uint32_t fetchdat) } \ if (valid) \ { \ - flags |= Z_FLAG; \ + cpu_state.flags |= Z_FLAG; \ cpl_override = 1; \ if (is32) \ cpu_state.regs[cpu_reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \ @@ -103,10 +109,12 @@ opLAR(l_a32, fetch_ea_32, 1, 1) \ NOTRM \ fetch_ea(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ \ sel = geteaw(); if (cpu_state.abrt) return 1; \ flags_rebuild(); \ - flags &= ~Z_FLAG; \ + cpu_state.flags &= ~Z_FLAG; \ if (!(sel & 0xfffc)) return 0; /*Null selector*/ \ valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ if (valid) \ @@ -125,7 +133,7 @@ opLAR(l_a32, fetch_ea_32, 1, 1) } \ if (valid) \ { \ - flags |= Z_FLAG; \ + cpu_state.flags |= Z_FLAG; \ cpl_override = 1; \ if (is32) \ { \ @@ -157,37 +165,46 @@ static int op0F00_common(uint32_t fetchdat, int ea32) int dpl, valid, granularity; uint32_t addr, base, limit; uint16_t desc, sel; - uint8_t access; + uint8_t access, access2; // pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); switch (rmdat & 0x38) { case 0x00: /*SLDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(ldt.seg); CLOCK_CYCLES(4); PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; case 0x08: /*STR*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(tr.seg); CLOCK_CYCLES(4); PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; case 0x10: /*LLDT*/ - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { pclog("Invalid LLDT!\n"); x86gpf(NULL,0); return 1; } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); sel = geteaw(); if (cpu_state.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); + access2 = readmemb(0, addr + 6); granularity = readmemb(0, addr + 6) & 0x80; if (cpu_state.abrt) return 1; ldt.limit = limit; + ldt.limit_raw = limit; ldt.access = access; + ldt.access2 = access2; if (granularity) { ldt.limit <<= 12; @@ -199,22 +216,30 @@ static int op0F00_common(uint32_t fetchdat, int ea32) PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); break; case 0x18: /*LTR*/ - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { pclog("Invalid LTR!\n"); x86gpf(NULL,0); break; } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); sel = geteaw(); if (cpu_state.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); + access2 = readmemb(0, addr + 6); granularity = readmemb(0, addr + 6) & 0x80; if (cpu_state.abrt) return 1; + access |= 2; + writememb(0, addr + 5, access); + if (cpu_state.abrt) return 1; tr.seg = sel; tr.limit = limit; + tr.limit_raw = limit; tr.access = access; + tr.access2 = access2; if (granularity) { tr.limit <<= 12; @@ -225,9 +250,11 @@ static int op0F00_common(uint32_t fetchdat, int ea32) PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); break; case 0x20: /*VERR*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); sel = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; if (!(sel & 0xfffc)) return 0; /*Null selector*/ cpl_override = 1; valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); @@ -240,14 +267,16 @@ static int op0F00_common(uint32_t fetchdat, int ea32) if (dpl < CPL || dpl < (sel & 3)) valid = 0; } if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/ - if (valid) flags |= Z_FLAG; + if (valid) cpu_state.flags |= Z_FLAG; CLOCK_CYCLES(20); PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); break; case 0x28: /*VERW*/ + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); sel = geteaw(); if (cpu_state.abrt) return 1; flags_rebuild(); - flags &= ~Z_FLAG; + cpu_state.flags &= ~Z_FLAG; if (!(sel & 0xfffc)) return 0; /*Null selector*/ cpl_override = 1; valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); @@ -258,7 +287,7 @@ static int op0F00_common(uint32_t fetchdat, int ea32) 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; + if (valid) cpu_state.flags |= Z_FLAG; CLOCK_CYCLES(20); PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); break; @@ -297,6 +326,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) switch (rmdat & 0x38) { case 0x00: /*SGDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(gdt.limit); base = gdt.base; //is32 ? gdt.base : (gdt.base & 0xffffff); if (is286) @@ -306,6 +337,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); break; case 0x08: /*SIDT*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(idt.limit); base = idt.base; if (is286) @@ -315,12 +348,14 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); break; case 0x10: /*LGDT*/ - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { pclog("Invalid LGDT!\n"); x86gpf(NULL,0); break; } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); // pclog("LGDT %08X:%08X\n", easeg, eaaddr); limit = geteaw(); base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -332,12 +367,14 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, ea32); break; case 0x18: /*LIDT*/ - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { pclog("Invalid LIDT!\n"); x86gpf(NULL,0); break; } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); // pclog("LIDT %08X:%08X\n", easeg, eaaddr); limit = geteaw(); base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; @@ -350,6 +387,8 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) break; case 0x20: /*SMSW*/ + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); if (is486) seteaw(msw); else if (is386) seteaw(msw | 0xFF00); else seteaw(msw | 0xFFF0); @@ -357,28 +396,40 @@ static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; case 0x30: /*LMSW*/ - if ((CPL || eflags&VM_FLAG) && (msw&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (msw&1)) { pclog("LMSW - ring not zero!\n"); x86gpf(NULL, 0); break; } + if (cpu_mod != 3) + SEG_CHECK_READ(cpu_state.ea_seg); tempw = geteaw(); if (cpu_state.abrt) return 1; if (msw & 1) tempw |= 1; - if (!is386) tempw &= 0xF; + if (is386) + { + tempw &= ~0x10; + tempw |= (msw & 0x10); + } + else tempw &= 0xF; msw = tempw; + if (msw & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); break; case 0x38: /*INVLPG*/ if (is486) { - if ((CPL || eflags&VM_FLAG) && (cr0&1)) + if ((CPL || cpu_state.eflags&VM_FLAG) && (cr0&1)) { pclog("Invalid INVLPG!\n"); x86gpf(NULL, 0); break; } + SEG_CHECK_READ(cpu_state.ea_seg); mmu_invalidate(ds + cpu_state.eaaddr); CLOCK_CYCLES(12); PREFETCH_RUN(12, 2, rmdat, 0,0,0,0, ea32); @@ -425,3 +476,14 @@ static int op0F01_286(uint32_t fetchdat) return op0F01_common(fetchdat, 0, 1, 0); } + + +static int opRSM(uint32_t fetchdat) +{ + if (cpu_cur_status & CPU_STATUS_SMM) + x86_smi_leave(); + else + x86illegal(); + + return 1; +} diff --git a/src/x86_ops_prefix.h b/src/x86_ops_prefix.h index 18d84d7..8cfe95e 100644 --- a/src/x86_ops_prefix.h +++ b/src/x86_ops_prefix.h @@ -1,4 +1,4 @@ -#define op_seg(name, seg) \ +#define op_seg(name, seg, opcode_table, normal_opcode_table) \ static int op ## name ## _w_a16(uint32_t fetchdat) \ { \ fetchdat = fastreadl(cs + cpu_state.pc); \ @@ -10,7 +10,9 @@ static int op ## name ## _w_a16(uint32_t fetchdat) \ CLOCK_CYCLES(4); \ PREFETCH_PREFIX(); \ \ - return x86_opcodes[fetchdat & 0xff](fetchdat >> 8); \ + if (opcode_table[fetchdat & 0xff]) \ + return opcode_table[fetchdat & 0xff](fetchdat >> 8); \ + return normal_opcode_table[fetchdat & 0xff](fetchdat >> 8); \ } \ \ static int op ## name ## _l_a16(uint32_t fetchdat) \ @@ -24,7 +26,9 @@ static int op ## name ## _l_a16(uint32_t fetchdat) \ CLOCK_CYCLES(4); \ PREFETCH_PREFIX(); \ \ - return x86_opcodes[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ + if (opcode_table[(fetchdat & 0xff) | 0x100]) \ + return opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ } \ \ static int op ## name ## _w_a32(uint32_t fetchdat) \ @@ -38,7 +42,9 @@ static int op ## name ## _w_a32(uint32_t fetchdat) \ CLOCK_CYCLES(4); \ PREFETCH_PREFIX(); \ \ - return x86_opcodes[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ + if (opcode_table[(fetchdat & 0xff) | 0x200]) \ + return opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ } \ \ static int op ## name ## _l_a32(uint32_t fetchdat) \ @@ -52,15 +58,31 @@ static int op ## name ## _l_a32(uint32_t fetchdat) \ CLOCK_CYCLES(4); \ PREFETCH_PREFIX(); \ \ - return x86_opcodes[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ + if (opcode_table[(fetchdat & 0xff) | 0x300]) \ + return opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ + return normal_opcode_table[(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) +op_seg(CS, cpu_state.seg_cs, x86_opcodes, x86_opcodes) +op_seg(DS, cpu_state.seg_ds, x86_opcodes, x86_opcodes) +op_seg(ES, cpu_state.seg_es, x86_opcodes, x86_opcodes) +op_seg(FS, cpu_state.seg_fs, x86_opcodes, x86_opcodes) +op_seg(GS, cpu_state.seg_gs, x86_opcodes, x86_opcodes) +op_seg(SS, cpu_state.seg_ss, x86_opcodes, x86_opcodes) + +op_seg(CS_REPE, cpu_state.seg_cs, x86_opcodes_REPE, x86_opcodes) +op_seg(DS_REPE, cpu_state.seg_ds, x86_opcodes_REPE, x86_opcodes) +op_seg(ES_REPE, cpu_state.seg_es, x86_opcodes_REPE, x86_opcodes) +op_seg(FS_REPE, cpu_state.seg_fs, x86_opcodes_REPE, x86_opcodes) +op_seg(GS_REPE, cpu_state.seg_gs, x86_opcodes_REPE, x86_opcodes) +op_seg(SS_REPE, cpu_state.seg_ss, x86_opcodes_REPE, x86_opcodes) + +op_seg(CS_REPNE, cpu_state.seg_cs, x86_opcodes_REPNE, x86_opcodes) +op_seg(DS_REPNE, cpu_state.seg_ds, x86_opcodes_REPNE, x86_opcodes) +op_seg(ES_REPNE, cpu_state.seg_es, x86_opcodes_REPNE, x86_opcodes) +op_seg(FS_REPNE, cpu_state.seg_fs, x86_opcodes_REPNE, x86_opcodes) +op_seg(GS_REPNE, cpu_state.seg_gs, x86_opcodes_REPNE, x86_opcodes) +op_seg(SS_REPNE, cpu_state.seg_ss, x86_opcodes_REPNE, x86_opcodes) static int op_66(uint32_t fetchdat) /*Data size select*/ { @@ -84,3 +106,56 @@ static int op_67(uint32_t fetchdat) /*Address size select*/ PREFETCH_PREFIX(); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); } + +static int op_66_REPE(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67_REPE(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_66_REPNE(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67_REPNE(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} diff --git a/src/x86_ops_rep.h b/src/x86_ops_rep.h index 7d3713a..d19a8f2 100644 --- a/src/x86_ops_rep.h +++ b/src/x86_ops_rep.h @@ -1,9 +1,692 @@ +#define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ +static int opREP_INSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint8_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + temp = inb(DX); \ + writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_INSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint16_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + temp = inw(DX); \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_INSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint32_t temp; \ + \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + temp = inl(DX); \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_OUTSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint8_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + outb(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ + else SRC_REG++; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_OUTSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint16_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + outw(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ + else SRC_REG += 2; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_OUTSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint32_t temp; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + outl(DX, temp); \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ + else SRC_REG += 4; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_MOVSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint8_t temp; \ + \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + else { DEST_REG++; SRC_REG++; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_MOVSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint16_t temp; \ + \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + else { DEST_REG += 2; SRC_REG += 2; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_MOVSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + { \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + } \ + while (CNT_REG > 0) \ + { \ + uint32_t temp; \ + \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + else { DEST_REG += 4; SRC_REG += 4; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ + \ +static int opREP_STOSB_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG); \ + writememb(es, DEST_REG, AL); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_STOSW_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG+1); \ + writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_STOSL_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_WRITE(&cpu_state.seg_es); \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&cpu_state.seg_es, DEST_REG, DEST_REG+3); \ + writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_LODSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + AL = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG--; \ + else SRC_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_LODSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + AX = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 2; \ + else SRC_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_LODSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + if (CNT_REG > 0) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + while (CNT_REG > 0) \ + { \ + EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (cpu_state.flags & D_FLAG) SRC_REG -= 4; \ + else SRC_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + + +#define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \ +static int opREP_CMPSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint8_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + else { DEST_REG++; SRC_REG++; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub8(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_CMPSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint16_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + else { DEST_REG += 2; SRC_REG += 2; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub16(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_CMPSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint32_t temp, temp2; \ + SEG_CHECK_READ(cpu_state.ea_seg); \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ + temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (cpu_state.flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + else { DEST_REG += 4; SRC_REG += 4; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub32(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_SCASB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint8_t temp = readmemb(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub8(AL, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_SCASW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint16_t temp = readmemw(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub16(AX, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_SCASL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + SEG_CHECK_READ(&cpu_state.seg_es); \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint32_t temp = readmeml(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub32(EAX, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (cpu_state.flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} + +REP_OPS(a16, CX, SI, DI) +REP_OPS(a32, ECX, ESI, EDI) +REP_OPS_CMPS_SCAS(a16_NE, CX, SI, DI, 0) +REP_OPS_CMPS_SCAS(a16_E, CX, SI, DI, 1) +REP_OPS_CMPS_SCAS(a32_NE, ECX, ESI, EDI, 0) +REP_OPS_CMPS_SCAS(a32_E, ECX, ESI, EDI, 1) + static int opREPNE(uint32_t fetchdat) { - return rep386(0); + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); } static int opREPE(uint32_t fetchdat) { - return rep386(1); -} + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} diff --git a/src/x86_ops_ret.h b/src/x86_ops_ret.h index 3a600ce..3dd93f4 100644 --- a/src/x86_ops_ret.h +++ b/src/x86_ops_ret.h @@ -1,10 +1,9 @@ #define RETF_a16(stack_offset) \ - if ((msw&1) && !(eflags&VM_FLAG)) \ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) \ { \ pmoderetf(0, stack_offset); \ return 1; \ } \ - oxpc = cpu_state.pc; \ if (stack32) \ { \ cpu_state.pc = readmemw(ss, ESP); \ @@ -21,12 +20,11 @@ cycles -= timing_retf_rm; #define RETF_a32(stack_offset) \ - if ((msw&1) && !(eflags&VM_FLAG)) \ + if ((msw&1) && !(cpu_state.eflags&VM_FLAG)) \ { \ pmoderetf(1, stack_offset); \ return 1; \ } \ - oxpc = cpu_state.pc; \ if (stack32) \ { \ cpu_state.pc = readmeml(ss, ESP); \ @@ -94,7 +92,7 @@ static int opIRET_286(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { x86gpf(NULL,0); return 1; @@ -108,19 +106,18 @@ static int opIRET_286(uint32_t fetchdat) 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; + cpu_state.flags = (cpu_state.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; + cpu_state.flags = (cpu_state.flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; SP += 6; } loadcs(new_cs); @@ -139,37 +136,68 @@ static int opIRET(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.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) + if (cr4 & CR4_VME) { - cpu_state.pc = readmemw(ss, ESP); - new_cs = readmemw(ss, ESP + 2); - flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; - ESP += 6; + uint16_t new_pc, new_cs, new_flags; + + new_pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + new_flags = readmemw(ss, ((SP + 4) & 0xffff)); + if (cpu_state.abrt) + return 1; + + if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (cpu_state.eflags & VIP_FLAG))) + { + x86gpf(NULL, 0); + return 1; + } + SP += 6; + if (new_flags & I_FLAG) + cpu_state.eflags |= VIF_FLAG; + else + cpu_state.eflags &= ~VIF_FLAG; + cpu_state.flags = (cpu_state.flags & 0x3300) | (new_flags & 0x4cd5) | 2; + loadcs(new_cs); + cpu_state.pc = new_pc; + + cycles -= timing_iret_rm; } else { - cpu_state.pc = readmemw(ss, SP); - new_cs = readmemw(ss, ((SP + 2) & 0xffff)); - flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; - SP += 6; + x86gpf_expected(NULL,0); + return 1; + } + } + else + { + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + cpu_state.flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + cpu_state.flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; } - loadcs(new_cs); - cycles -= timing_iret_rm; } flags_extract(); nmi_enable = 1; @@ -184,9 +212,9 @@ static int opIRETD(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + if ((cr0 & 1) && (cpu_state.eflags & VM_FLAG) && (IOPL != 3)) { - x86gpf(NULL,0); + x86gpf_expected(NULL,0); return 1; } if (msw & 1) @@ -198,21 +226,20 @@ static int opIRETD(uint32_t fetchdat) 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); + cpu_state.flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2; + cpu_state.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); + cpu_state.flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; + cpu_state.eflags = readmemw(ss, (SP + 10) & 0xffff); SP += 12; } loadcs(new_cs); diff --git a/src/x86_ops_set.h b/src/x86_ops_set.h index 298f28c..5a3dfaa 100644 --- a/src/x86_ops_set.h +++ b/src/x86_ops_set.h @@ -2,6 +2,8 @@ static int opSET ## condition ## _a16(uint32_t fetchdat) \ { \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ seteab((cond_ ## condition) ? 1 : 0); \ CLOCK_CYCLES(4); \ return cpu_state.abrt; \ @@ -10,6 +12,8 @@ static int opSET ## condition ## _a32(uint32_t fetchdat) \ { \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_READ(cpu_state.ea_seg); \ seteab((cond_ ## condition) ? 1 : 0); \ CLOCK_CYCLES(4); \ return cpu_state.abrt; \ diff --git a/src/x86_ops_shift.h b/src/x86_ops_shift.h index 5144d10..0d6d193 100644 --- a/src/x86_ops_shift.h +++ b/src/x86_ops_shift.h @@ -6,36 +6,21 @@ switch (rmdat & 0x38) \ { \ case 0x00: /*ROL b, c*/ \ - while (c > 0) \ - { \ - temp2 = (temp & 0x80) ? 1 : 0; \ - temp = (temp << 1) | temp2; \ - c--; \ - } \ - seteab(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + temp = (temp << (c & 7)) | (temp >> (8-(c & 7))); \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL8, temp); \ CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x08: /*ROR b,CL*/ \ - while (c > 0) \ - { \ - temp2 = temp & 1; \ - temp >>= 1; \ - if (temp2) temp |= 0x80; \ - c--; \ - } \ - seteab(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + temp = (temp >> (c & 7)) | (temp << (8-(c & 7))); \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR8, temp); \ CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x10: /*RCL b,CL*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -45,14 +30,14 @@ c--; \ } \ seteab(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 7)) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x18: /*RCR b,CL*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -62,9 +47,9 @@ c--; \ } \ seteab(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ @@ -98,36 +83,21 @@ switch (rmdat & 0x38) \ { \ case 0x00: /*ROL w, c*/ \ - while (c > 0) \ - { \ - temp2 = (temp & 0x8000) ? 1 : 0; \ - temp = (temp << 1) | temp2; \ - c--; \ - } \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + temp = (temp << (c & 15)) | (temp >> (16-(c & 15))); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL16, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ - case 0x08: /*ROR w, c*/ \ - while (c > 0) \ - { \ - temp2 = temp & 1; \ - temp >>= 1; \ - if (temp2) temp |= 0x8000; \ - c--; \ - } \ - seteaw(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + case 0x08: /*ROR w,CL*/ \ + temp = (temp >> (c & 15)) | (temp << (16-(c & 15))); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR16, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x10: /*RCL w, c*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -137,14 +107,14 @@ c--; \ } \ seteaw(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 15)) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x18: /*RCR w, c*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -154,9 +124,9 @@ c--; \ } \ seteaw(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ @@ -190,33 +160,18 @@ switch (rmdat & 0x38) \ { \ case 0x00: /*ROL l, c*/ \ - while (c > 0) \ - { \ - temp2 = (temp & 0x80000000) ? 1 : 0; \ - temp = (temp << 1) | temp2; \ - c--; \ - } \ - seteal(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + temp = (temp << c) | (temp >> (32-c)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROL32, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ - case 0x08: /*ROR l, c*/ \ - while (c > 0) \ - { \ - temp2 = temp & 1; \ - temp >>= 1; \ - if (temp2) temp |= 0x80000000; \ - c--; \ - } \ - seteal(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ - CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ - PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + case 0x08: /*ROR l,CL*/ \ + temp = (temp >> c) | (temp << (32-c)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_rotate(FLAGS_ROR32, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ break; \ case 0x10: /*RCL l, c*/ \ temp2 = CF_SET(); \ @@ -229,14 +184,14 @@ c--; \ } \ seteal(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((cpu_state.flags & C_FLAG) ^ (temp >> 31)) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ break; \ case 0x18: /*RCR l, c*/ \ - temp2 = flags & C_FLAG; \ + temp2 = cpu_state.flags & C_FLAG; \ if (is486) CLOCK_CYCLES_ALWAYS(c); \ while (c > 0) \ { \ @@ -246,9 +201,9 @@ c--; \ } \ seteal(temp); if (cpu_state.abrt) return 1; \ - flags &= ~(C_FLAG | V_FLAG); \ - if (temp2) flags |= C_FLAG; \ - if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + cpu_state.flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) cpu_state.flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) cpu_state.flags |= V_FLAG; \ CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ break; \ @@ -281,6 +236,8 @@ static int opC0_a16(uint32_t fetchdat) uint8_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteab(); if (cpu_state.abrt) return 1; @@ -294,6 +251,8 @@ static int opC0_a32(uint32_t fetchdat) uint8_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteab(); if (cpu_state.abrt) return 1; @@ -307,6 +266,8 @@ static int opC1_w_a16(uint32_t fetchdat) uint16_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteaw(); if (cpu_state.abrt) return 1; @@ -320,6 +281,8 @@ static int opC1_w_a32(uint32_t fetchdat) uint16_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteaw(); if (cpu_state.abrt) return 1; @@ -333,6 +296,8 @@ static int opC1_l_a16(uint32_t fetchdat) uint32_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteal(); if (cpu_state.abrt) return 1; @@ -346,6 +311,8 @@ static int opC1_l_a32(uint32_t fetchdat) uint32_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; PREFETCH_PREFIX(); temp = geteal(); if (cpu_state.abrt) return 1; @@ -360,6 +327,8 @@ static int opD0_a16(uint32_t fetchdat) uint8_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; OP_SHIFT_b(c, 0); return 0; @@ -371,6 +340,8 @@ static int opD0_a32(uint32_t fetchdat) uint8_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; OP_SHIFT_b(c, 1); return 0; @@ -382,6 +353,8 @@ static int opD1_w_a16(uint32_t fetchdat) uint16_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; OP_SHIFT_w(c, 0); return 0; @@ -393,6 +366,8 @@ static int opD1_w_a32(uint32_t fetchdat) uint16_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; OP_SHIFT_w(c, 1); return 0; @@ -404,6 +379,8 @@ static int opD1_l_a16(uint32_t fetchdat) uint32_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; OP_SHIFT_l(c, 0); return 0; @@ -415,6 +392,8 @@ static int opD1_l_a32(uint32_t fetchdat) uint32_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; OP_SHIFT_l(c, 1); return 0; @@ -427,6 +406,8 @@ static int opD2_a16(uint32_t fetchdat) uint8_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteab(); if (cpu_state.abrt) return 1; OP_SHIFT_b(c, 0); @@ -439,6 +420,8 @@ static int opD2_a32(uint32_t fetchdat) uint8_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteab(); if (cpu_state.abrt) return 1; OP_SHIFT_b(c, 1); @@ -451,6 +434,8 @@ static int opD3_w_a16(uint32_t fetchdat) uint16_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteaw(); if (cpu_state.abrt) return 1; OP_SHIFT_w(c, 0); @@ -463,6 +448,8 @@ static int opD3_w_a32(uint32_t fetchdat) uint16_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteaw(); if (cpu_state.abrt) return 1; OP_SHIFT_w(c, 1); @@ -475,6 +462,8 @@ static int opD3_l_a16(uint32_t fetchdat) uint32_t temp, temp2; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteal(); if (cpu_state.abrt) return 1; OP_SHIFT_l(c, 0); @@ -487,6 +476,8 @@ static int opD3_l_a32(uint32_t fetchdat) uint32_t temp, temp2; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); c = CL & 31; temp = geteal(); if (cpu_state.abrt) return 1; OP_SHIFT_l(c, 1); @@ -505,7 +496,7 @@ static int opD3_l_a32(uint32_t fetchdat) seteaw(tempw); if (cpu_state.abrt) return 1; \ setznp16(tempw); \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ } #define SHLD_l() \ @@ -517,7 +508,7 @@ static int opD3_l_a32(uint32_t fetchdat) seteal(templ); if (cpu_state.abrt) return 1; \ setznp32(templ); \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ } @@ -531,7 +522,7 @@ static int opD3_l_a32(uint32_t fetchdat) seteaw(tempw); if (cpu_state.abrt) return 1; \ setznp16(tempw); \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ } #define SHRD_l() \ @@ -543,7 +534,7 @@ static int opD3_l_a32(uint32_t fetchdat) seteal(templ); if (cpu_state.abrt) return 1; \ setznp32(templ); \ flags_rebuild(); \ - if (tempc) flags |= C_FLAG; \ + if (tempc) cpu_state.flags |= C_FLAG; \ } #define opSHxD(operation) \ @@ -552,6 +543,8 @@ static int opD3_l_a32(uint32_t fetchdat) int count; \ \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = getbyte() & 31; \ operation(); \ \ @@ -564,6 +557,8 @@ static int opD3_l_a32(uint32_t fetchdat) int count; \ \ fetch_ea_16(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = CL & 31; \ operation(); \ \ @@ -576,6 +571,8 @@ static int opD3_l_a32(uint32_t fetchdat) int count; \ \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = getbyte() & 31; \ operation(); \ \ @@ -588,6 +585,8 @@ static int opD3_l_a32(uint32_t fetchdat) int count; \ \ fetch_ea_32(fetchdat); \ + if (cpu_mod != 3) \ + SEG_CHECK_WRITE(cpu_state.ea_seg); \ count = CL & 31; \ operation(); \ \ diff --git a/src/x86_ops_stack.h b/src/x86_ops_stack.h index 31f0908..b7e827b 100644 --- a/src/x86_ops_stack.h +++ b/src/x86_ops_stack.h @@ -236,6 +236,8 @@ static int opPOPW_a16(uint32_t fetchdat) temp = POP_W(); if (cpu_state.abrt) return 1; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(temp); if (cpu_state.abrt) { @@ -255,6 +257,8 @@ static int opPOPW_a32(uint32_t fetchdat) temp = POP_W(); if (cpu_state.abrt) return 1; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteaw(temp); if (cpu_state.abrt) { @@ -275,6 +279,8 @@ static int opPOPL_a16(uint32_t fetchdat) temp = POP_L(); if (cpu_state.abrt) return 1; fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(temp); if (cpu_state.abrt) { @@ -294,6 +300,8 @@ static int opPOPL_a32(uint32_t fetchdat) temp = POP_L(); if (cpu_state.abrt) return 1; fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); seteal(temp); if (cpu_state.abrt) { @@ -462,10 +470,10 @@ 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); +POP_SEG_OPS(DS, &cpu_state.seg_ds); +POP_SEG_OPS(ES, &cpu_state.seg_es); +POP_SEG_OPS(FS, &cpu_state.seg_fs); +POP_SEG_OPS(GS, &cpu_state.seg_gs); static int opPOP_SS_w(uint32_t fetchdat) @@ -473,14 +481,14 @@ static int opPOP_SS_w(uint32_t fetchdat) uint16_t temp_seg; uint32_t temp_esp = ESP; temp_seg = POP_W(); if (cpu_state.abrt) return 1; - loadseg(temp_seg, &_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } + loadseg(temp_seg, &cpu_state.seg_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } CLOCK_CYCLES(is486 ? 3 : 7); PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; fetchdat = fastreadl(cs + cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; @@ -493,14 +501,14 @@ static int opPOP_SS_l(uint32_t fetchdat) uint32_t temp_seg; uint32_t temp_esp = ESP; temp_seg = POP_L(); if (cpu_state.abrt) return 1; - loadseg(temp_seg & 0xffff, &_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } + loadseg(temp_seg & 0xffff, &cpu_state.seg_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } CLOCK_CYCLES(is486 ? 3 : 7); PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); cpu_state.oldpc = cpu_state.pc; cpu_state.op32 = use32; cpu_state.ssegs = 0; - cpu_state.ea_seg = &_ds; + cpu_state.ea_seg = &cpu_state.seg_ds; fetchdat = fastreadl(cs + cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; diff --git a/src/x86_ops_string.h b/src/x86_ops_string.h index b08460b..433d683 100644 --- a/src/x86_ops_string.h +++ b/src/x86_ops_string.h @@ -1,19 +1,27 @@ static int opMOVSB_a16(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; writememb(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { DI--; SI--; } - else { DI++; SI++; } + if (cpu_state.flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); return 0; } static int opMOVSB_a32(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; writememb(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { EDI--; ESI--; } - else { EDI++; ESI++; } + if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); return 0; @@ -21,20 +29,28 @@ static int opMOVSB_a32(uint32_t fetchdat) static int opMOVSW_a16(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; writememw(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { DI -= 2; SI -= 2; } - else { DI += 2; SI += 2; } + if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); return 0; } static int opMOVSW_a32(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; writememw(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } - else { EDI += 2; ESI += 2; } + if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); return 0; @@ -42,20 +58,28 @@ static int opMOVSW_a32(uint32_t fetchdat) static int opMOVSL_a16(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; writememl(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { DI -= 4; SI -= 4; } - else { DI += 4; SI += 4; } + if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,1, 0); return 0; } static int opMOVSL_a32(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_WRITE(&cpu_state.seg_es); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; writememl(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } - else { EDI += 4; ESI += 4; } + if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,1, 1); return 0; @@ -64,22 +88,30 @@ static int opMOVSL_a32(uint32_t fetchdat) static int opCMPSB_a16(uint32_t fetchdat) { - uint8_t src = readmemb(cpu_state.ea_seg->base, SI); - uint8_t dst = readmemb(es, DI); if (cpu_state.abrt) return 1; + uint8_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemb(cpu_state.ea_seg->base, SI); + dst = readmemb(es, DI); if (cpu_state.abrt) return 1; setsub8(src, dst); - if (flags & D_FLAG) { DI--; SI--; } - else { DI++; SI++; } + if (cpu_state.flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0); return 0; } static int opCMPSB_a32(uint32_t fetchdat) { - uint8_t src = readmemb(cpu_state.ea_seg->base, ESI); - uint8_t dst = readmemb(es, EDI); if (cpu_state.abrt) return 1; + uint8_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemb(cpu_state.ea_seg->base, ESI); + dst = readmemb(es, EDI); if (cpu_state.abrt) return 1; setsub8(src, dst); - if (flags & D_FLAG) { EDI--; ESI--; } - else { EDI++; ESI++; } + if (cpu_state.flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1); return 0; @@ -87,22 +119,30 @@ static int opCMPSB_a32(uint32_t fetchdat) static int opCMPSW_a16(uint32_t fetchdat) { - uint16_t src = readmemw(cpu_state.ea_seg->base, SI); - uint16_t dst = readmemw(es, DI); if (cpu_state.abrt) return 1; + uint16_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemw(cpu_state.ea_seg->base, SI); + dst = readmemw(es, DI); if (cpu_state.abrt) return 1; setsub16(src, dst); - if (flags & D_FLAG) { DI -= 2; SI -= 2; } - else { DI += 2; SI += 2; } + if (cpu_state.flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0); return 0; } static int opCMPSW_a32(uint32_t fetchdat) { - uint16_t src = readmemw(cpu_state.ea_seg->base, ESI); - uint16_t dst = readmemw(es, EDI); if (cpu_state.abrt) return 1; + uint16_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmemw(cpu_state.ea_seg->base, ESI); + dst = readmemw(es, EDI); if (cpu_state.abrt) return 1; setsub16(src, dst); - if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } - else { EDI += 2; ESI += 2; } + if (cpu_state.flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1); return 0; @@ -110,22 +150,30 @@ static int opCMPSW_a32(uint32_t fetchdat) static int opCMPSL_a16(uint32_t fetchdat) { - uint32_t src = readmeml(cpu_state.ea_seg->base, SI); - uint32_t dst = readmeml(es, DI); if (cpu_state.abrt) return 1; + uint32_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmeml(cpu_state.ea_seg->base, SI); + dst = readmeml(es, DI); if (cpu_state.abrt) return 1; setsub32(src, dst); - if (flags & D_FLAG) { DI -= 4; SI -= 4; } - else { DI += 4; SI += 4; } + if (cpu_state.flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 0); return 0; } static int opCMPSL_a32(uint32_t fetchdat) { - uint32_t src = readmeml(cpu_state.ea_seg->base, ESI); - uint32_t dst = readmeml(es, EDI); if (cpu_state.abrt) return 1; + uint32_t src, dst; + + SEG_CHECK_READ(cpu_state.ea_seg); + SEG_CHECK_READ(&cpu_state.seg_es); + src = readmeml(cpu_state.ea_seg->base, ESI); + dst = readmeml(es, EDI); if (cpu_state.abrt) return 1; setsub32(src, dst); - if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } - else { EDI += 4; ESI += 4; } + if (cpu_state.flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } CLOCK_CYCLES((is486) ? 8 : 10); PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 1); return 0; @@ -133,18 +181,20 @@ static int opCMPSL_a32(uint32_t fetchdat) static int opSTOSB_a16(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememb(es, DI, AL); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI--; - else DI++; + if (cpu_state.flags & D_FLAG) DI--; + else DI++; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); return 0; } static int opSTOSB_a32(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememb(es, EDI, AL); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI--; - else EDI++; + if (cpu_state.flags & D_FLAG) EDI--; + else EDI++; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); return 0; @@ -152,18 +202,20 @@ static int opSTOSB_a32(uint32_t fetchdat) static int opSTOSW_a16(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememw(es, DI, AX); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI -= 2; - else DI += 2; + if (cpu_state.flags & D_FLAG) DI -= 2; + else DI += 2; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); return 0; } static int opSTOSW_a32(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememw(es, EDI, AX); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI -= 2; - else EDI += 2; + if (cpu_state.flags & D_FLAG) EDI -= 2; + else EDI += 2; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); return 0; @@ -171,18 +223,20 @@ static int opSTOSW_a32(uint32_t fetchdat) static int opSTOSL_a16(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememl(es, DI, EAX); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI -= 4; - else DI += 4; + if (cpu_state.flags & D_FLAG) DI -= 4; + else DI += 4; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); return 0; } static int opSTOSL_a32(uint32_t fetchdat) { + SEG_CHECK_WRITE(&cpu_state.seg_es); writememl(es, EDI, EAX); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI -= 4; - else EDI += 4; + if (cpu_state.flags & D_FLAG) EDI -= 4; + else EDI += 4; CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,0,1, 1); return 0; @@ -191,20 +245,26 @@ static int opSTOSL_a32(uint32_t fetchdat) static int opLODSB_a16(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; AL = temp; - if (flags & D_FLAG) SI--; - else SI++; + if (cpu_state.flags & D_FLAG) SI--; + else SI++; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); return 0; } static int opLODSB_a32(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; AL = temp; - if (flags & D_FLAG) ESI--; - else ESI++; + if (cpu_state.flags & D_FLAG) ESI--; + else ESI++; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); return 0; @@ -212,20 +272,26 @@ static int opLODSB_a32(uint32_t fetchdat) static int opLODSW_a16(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; AX = temp; - if (flags & D_FLAG) SI -= 2; - else SI += 2; + if (cpu_state.flags & D_FLAG) SI -= 2; + else SI += 2; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); return 0; } static int opLODSW_a32(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; AX = temp; - if (flags & D_FLAG) ESI -= 2; - else ESI += 2; + if (cpu_state.flags & D_FLAG) ESI -= 2; + else ESI += 2; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); return 0; @@ -233,20 +299,26 @@ static int opLODSW_a32(uint32_t fetchdat) static int opLODSL_a16(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; EAX = temp; - if (flags & D_FLAG) SI -= 4; - else SI += 4; + if (cpu_state.flags & D_FLAG) SI -= 4; + else SI += 4; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); return 0; } static int opLODSL_a32(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; EAX = temp; - if (flags & D_FLAG) ESI -= 4; - else ESI += 4; + if (cpu_state.flags & D_FLAG) ESI -= 4; + else ESI += 4; CLOCK_CYCLES(5); PREFETCH_RUN(5, 1, -1, 0,1,0,0, 1); return 0; @@ -255,20 +327,26 @@ static int opLODSL_a32(uint32_t fetchdat) static int opSCASB_a16(uint32_t fetchdat) { - uint8_t temp = readmemb(es, DI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemb(es, DI); if (cpu_state.abrt) return 1; setsub8(AL, temp); - if (flags & D_FLAG) DI--; - else DI++; + if (cpu_state.flags & D_FLAG) DI--; + else DI++; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); return 0; } static int opSCASB_a32(uint32_t fetchdat) { - uint8_t temp = readmemb(es, EDI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemb(es, EDI); if (cpu_state.abrt) return 1; setsub8(AL, temp); - if (flags & D_FLAG) EDI--; - else EDI++; + if (cpu_state.flags & D_FLAG) EDI--; + else EDI++; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); return 0; @@ -276,20 +354,26 @@ static int opSCASB_a32(uint32_t fetchdat) static int opSCASW_a16(uint32_t fetchdat) { - uint16_t temp = readmemw(es, DI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemw(es, DI); if (cpu_state.abrt) return 1; setsub16(AX, temp); - if (flags & D_FLAG) DI -= 2; - else DI += 2; + if (cpu_state.flags & D_FLAG) DI -= 2; + else DI += 2; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); return 0; } static int opSCASW_a32(uint32_t fetchdat) { - uint16_t temp = readmemw(es, EDI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmemw(es, EDI); if (cpu_state.abrt) return 1; setsub16(AX, temp); - if (flags & D_FLAG) EDI -= 2; - else EDI += 2; + if (cpu_state.flags & D_FLAG) EDI -= 2; + else EDI += 2; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); return 0; @@ -297,20 +381,26 @@ static int opSCASW_a32(uint32_t fetchdat) static int opSCASL_a16(uint32_t fetchdat) { - uint32_t temp = readmeml(es, DI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmeml(es, DI); if (cpu_state.abrt) return 1; setsub32(EAX, temp); - if (flags & D_FLAG) DI -= 4; - else DI += 4; + if (cpu_state.flags & D_FLAG) DI -= 4; + else DI += 4; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,0, 0); return 0; } static int opSCASL_a32(uint32_t fetchdat) { - uint32_t temp = readmeml(es, EDI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(&cpu_state.seg_es); + temp = readmeml(es, EDI); if (cpu_state.abrt) return 1; setsub32(EAX, temp); - if (flags & D_FLAG) EDI -= 4; - else EDI += 4; + if (cpu_state.flags & D_FLAG) EDI -= 4; + else EDI += 4; CLOCK_CYCLES(7); PREFETCH_RUN(7, 1, -1, 0,1,0,0, 1); return 0; @@ -319,11 +409,13 @@ static int opSCASL_a32(uint32_t fetchdat) static int opINSB_a16(uint32_t fetchdat) { uint8_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); temp = inb(DX); writememb(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI--; - else DI++; + if (cpu_state.flags & D_FLAG) DI--; + else DI++; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); return 0; @@ -331,11 +423,13 @@ static int opINSB_a16(uint32_t fetchdat) static int opINSB_a32(uint32_t fetchdat) { uint8_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); temp = inb(DX); writememb(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI--; - else EDI++; + if (cpu_state.flags & D_FLAG) EDI--; + else EDI++; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); return 0; @@ -344,12 +438,14 @@ static int opINSB_a32(uint32_t fetchdat) static int opINSW_a16(uint32_t fetchdat) { uint16_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); temp = inw(DX); writememw(es, DI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI -= 2; - else DI += 2; + if (cpu_state.flags & D_FLAG) DI -= 2; + else DI += 2; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); return 0; @@ -357,12 +453,14 @@ static int opINSW_a16(uint32_t fetchdat) static int opINSW_a32(uint32_t fetchdat) { uint16_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); check_io_perm(DX); check_io_perm(DX + 1); temp = inw(DX); writememw(es, EDI, temp); if (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI -= 2; - else EDI += 2; + if (cpu_state.flags & D_FLAG) EDI -= 2; + else EDI += 2; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); return 0; @@ -371,14 +469,16 @@ static int opINSW_a32(uint32_t fetchdat) static int opINSL_a16(uint32_t fetchdat) { uint32_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); 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 (cpu_state.abrt) return 1; - if (flags & D_FLAG) DI -= 4; - else DI += 4; + if (cpu_state.flags & D_FLAG) DI -= 4; + else DI += 4; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 0,1,0,1, 0); return 0; @@ -386,14 +486,16 @@ static int opINSL_a16(uint32_t fetchdat) static int opINSL_a32(uint32_t fetchdat) { uint32_t temp; + + SEG_CHECK_WRITE(&cpu_state.seg_es); 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 (cpu_state.abrt) return 1; - if (flags & D_FLAG) EDI -= 4; - else EDI += 4; + if (cpu_state.flags & D_FLAG) EDI -= 4; + else EDI += 4; CLOCK_CYCLES(15); PREFETCH_RUN(15, 1, -1, 0,1,0,1, 1); return 0; @@ -401,10 +503,13 @@ static int opINSL_a32(uint32_t fetchdat) static int opOUTSB_a16(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; check_io_perm(DX); - if (flags & D_FLAG) SI--; - else SI++; + if (cpu_state.flags & D_FLAG) SI--; + else SI++; outb(DX, temp); CLOCK_CYCLES(14); PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0); @@ -412,10 +517,13 @@ static int opOUTSB_a16(uint32_t fetchdat) } static int opOUTSB_a32(uint32_t fetchdat) { - uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint8_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; check_io_perm(DX); - if (flags & D_FLAG) ESI--; - else ESI++; + if (cpu_state.flags & D_FLAG) ESI--; + else ESI++; outb(DX, temp); CLOCK_CYCLES(14); PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1); @@ -424,11 +532,14 @@ static int opOUTSB_a32(uint32_t fetchdat) static int opOUTSW_a16(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); - if (flags & D_FLAG) SI -= 2; - else SI += 2; + if (cpu_state.flags & D_FLAG) SI -= 2; + else SI += 2; outw(DX, temp); CLOCK_CYCLES(14); PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0); @@ -436,11 +547,14 @@ static int opOUTSW_a16(uint32_t fetchdat) } static int opOUTSW_a32(uint32_t fetchdat) { - uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint16_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; check_io_perm(DX); check_io_perm(DX + 1); - if (flags & D_FLAG) ESI -= 2; - else ESI += 2; + if (cpu_state.flags & D_FLAG) ESI -= 2; + else ESI += 2; outw(DX, temp); CLOCK_CYCLES(14); PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1); @@ -449,13 +563,16 @@ static int opOUTSW_a32(uint32_t fetchdat) static int opOUTSL_a16(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.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; + if (cpu_state.flags & D_FLAG) SI -= 4; + else SI += 4; outl(EDX, temp); CLOCK_CYCLES(14); PREFETCH_RUN(14, 1, -1, 0,1,0,1, 0); @@ -463,13 +580,16 @@ static int opOUTSL_a16(uint32_t fetchdat) } static int opOUTSL_a32(uint32_t fetchdat) { - uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + uint32_t temp; + + SEG_CHECK_READ(cpu_state.ea_seg); + temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.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; + if (cpu_state.flags & D_FLAG) ESI -= 4; + else ESI += 4; outl(EDX, temp); CLOCK_CYCLES(14); PREFETCH_RUN(14, 1, -1, 0,1,0,1, 1); diff --git a/src/x86_ops_xchg.h b/src/x86_ops_xchg.h index 6e08933..ae8f69c 100644 --- a/src/x86_ops_xchg.h +++ b/src/x86_ops_xchg.h @@ -1,7 +1,10 @@ static int opXCHG_b_a16(uint32_t fetchdat) { uint8_t temp; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; seteab(getr8(cpu_reg)); if (cpu_state.abrt) return 1; setr8(cpu_reg, temp); @@ -12,7 +15,10 @@ static int opXCHG_b_a16(uint32_t fetchdat) static int opXCHG_b_a32(uint32_t fetchdat) { uint8_t temp; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteab(); if (cpu_state.abrt) return 1; seteab(getr8(cpu_reg)); if (cpu_state.abrt) return 1; setr8(cpu_reg, temp); @@ -24,7 +30,10 @@ static int opXCHG_b_a32(uint32_t fetchdat) static int opXCHG_w_a16(uint32_t fetchdat) { uint16_t temp; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -35,7 +44,10 @@ static int opXCHG_w_a16(uint32_t fetchdat) static int opXCHG_w_a32(uint32_t fetchdat) { uint16_t temp; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteaw(); if (cpu_state.abrt) return 1; seteaw(cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].w = temp; @@ -47,7 +59,10 @@ static int opXCHG_w_a32(uint32_t fetchdat) static int opXCHG_l_a16(uint32_t fetchdat) { uint32_t temp; + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp; @@ -58,7 +73,10 @@ static int opXCHG_l_a16(uint32_t fetchdat) static int opXCHG_l_a32(uint32_t fetchdat) { uint32_t temp; + fetch_ea_32(fetchdat); + if (cpu_mod != 3) + SEG_CHECK_WRITE(cpu_state.ea_seg); temp = geteal(); if (cpu_state.abrt) return 1; seteal(cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; cpu_state.regs[cpu_reg].l = temp; diff --git a/src/x86seg.c b/src/x86seg.c index 69a0ce0..f2d465f 100644 --- a/src/x86seg.c +++ b/src/x86seg.c @@ -5,9 +5,12 @@ #include "ibm.h" #include "mem.h" #include "x86.h" -#include "386.h" +#include "x86_flags.h" #include "386_common.h" #include "cpu.h" +#include "config.h" +#include "paths.h" +#include "i440bx.h" /*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ #define CS_ACCESSED @@ -30,55 +33,68 @@ int intgatesize; void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); void taskswitch386(uint16_t seg, uint16_t *segdat); -int output; - /*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); + char buf[256]; + // return; + if (!pclogf) + { + strcpy(buf, logs_path); + put_backslash(buf); + strcat(buf, "pcem.log"); + pclogf=fopen(buf, "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; + s->access2 = 0; s->limit = 0xFFFF; s->limit_low = 0; s->limit_high = 0xffff; + if (s == &cpu_state.seg_cs) + { + // TODO - When the PC is reset, initialization of the CS descriptor must be like the annotated line below. + //s->base = AT ? (cpu_16bitbus ? 0xFF0000 : 0xFFFF0000) : 0xFFFF0; + s->base = AT ? 0xF0000 : 0xFFFF0; + s->seg = AT ? 0xF000 : 0xFFFF; + } + else + { + s->base = 0; + s->seg = 0; + } } void x86seg_reset() { - seg_reset(&_cs); - seg_reset(&_ds); - seg_reset(&_es); - seg_reset(&_fs); - seg_reset(&_gs); - seg_reset(&_ss); + seg_reset(&cpu_state.seg_cs); + seg_reset(&cpu_state.seg_ds); + seg_reset(&cpu_state.seg_es); + seg_reset(&cpu_state.seg_fs); + seg_reset(&cpu_state.seg_gs); + seg_reset(&cpu_state.seg_ss); } void x86_doabrt(int x86_abrt) { // ingpf = 1; - CS = oldcs; cpu_state.pc = cpu_state.oldpc; - _cs.access = oldcpl << 5; + cpu_state.seg_cs.access = oldcpl << 5; // pclog("x86_doabrt - %02X %08X %04X:%08X %i\n", x86_abrt, abrt_error, CS, pc, ins); /* if (CS == 0x3433 && pc == 0x000006B0) @@ -96,28 +112,27 @@ void x86_doabrt(int x86_abrt) uint32_t addr = (x86_abrt << 2) + idt.base; if (stack32) { - writememw(ss,ESP-2,flags); + writememw(ss,ESP-2,cpu_state.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-2)&0xFFFF),cpu_state.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.flags &= ~I_FLAG; + cpu_state.flags &= ~T_FLAG; cpu_state.pc=readmemw(0,addr); loadcs(readmemw(0,addr+2)); return; } - if (cpu_state.abrt) return; + if (cpu_state.abrt || x86_was_reset) return; if (intgatesize == 16) { @@ -145,15 +160,19 @@ void x86_doabrt(int x86_abrt) SP-=4; } } -// ingpf = 0; -// abrt = gpf = 1; } void x86gpf(char *s, uint16_t error) { -// pclog("GPF %04X\n", error); +// pclog("GPF %04X %04x(%08x):%08x\n", error, CS,cs,cpu_state.pc); cpu_state.abrt = ABRT_GPF; abrt_error = error; } +void x86gpf_expected(char *s, uint16_t error) +{ +// pclog("GPF_v86 %04X %04x(%08x):%08x\n", error, CS,cs,cpu_state.pc); + cpu_state.abrt = ABRT_GPF | ABRT_EXPECTED; + abrt_error = error; +} void x86ss(char *s, uint16_t error) { // pclog("SS %04X\n", error); @@ -174,15 +193,40 @@ void x86np(char *s, uint16_t error) } +static void set_stack32(int s) +{ + stack32 = s; + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; + else + cpu_cur_status &= ~CPU_STATUS_STACK32; +} + +static void set_use32(int u) +{ + if (u) + { + use32 = 0x300; + cpu_cur_status |= CPU_STATUS_USE32; + } + else + { + use32 = 0; + cpu_cur_status &= ~CPU_STATUS_USE32; + } +} + static void do_seg_load(x86seg *s, uint16_t *segdat) { s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); + s->limit_raw = s->limit; 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; + s->access2 = segdat[3] & 0xf0; if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ { @@ -195,11 +239,27 @@ static void do_seg_load(x86seg *s, uint16_t *segdat) 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); + + if (s == &cpu_state.seg_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } } static void do_seg_v86_init(x86seg *s) { s->access = (3 << 5) | 2; + s->access2 = 0; s->limit = 0xffff; s->limit_low = 0; s->limit_high = 0xffff; @@ -252,22 +312,22 @@ static void check_seg_valid(x86seg *s) loadseg(0, s); } -void loadseg(uint16_t seg, x86seg *s) +int loadseg(uint16_t seg, x86seg *s) { uint16_t segdat[4]; uint32_t addr; int dpl; - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { // intcount++; if (!(seg&~3)) { - if (s==&_ss) + if (s==&cpu_state.seg_ss) { pclog("SS selector = NULL!\n"); x86ss(NULL,0); - return; + return 1; // dumpregs(); // exit(-1); } @@ -275,8 +335,10 @@ void loadseg(uint16_t seg, x86seg *s) s->seg=0; s->access = 0; s->base=-1; + if (s == &cpu_state.seg_ds) + cpu_cur_status |= CPU_STATUS_NOTFLATDS; // 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,pc); - return; + return 0; } // if (s==&_ss) pclog("Load SS %04X\n",seg); // pclog("Protected mode seg load!\n"); @@ -285,12 +347,12 @@ void loadseg(uint16_t seg, x86seg *s) { if (addr>=ldt.limit) { - pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n",seg,ldt.limit, opcode, opcode2, 0/*rmdat*/); + pclog("Bigger than LDT limit %04X %04X %02X\n",seg,ldt.limit, 0/*rmdat*/); // dumppic(); // dumpregs(); // exit(-1); x86gpf(NULL,seg&~3); - return; + return 1; } addr+=ldt.base; } @@ -302,7 +364,7 @@ void loadseg(uint16_t seg, x86seg *s) // dumpregs(); // exit(-1); x86gpf(NULL,seg&~3); - return; + return 1; } addr+=gdt.base; } @@ -310,22 +372,22 @@ void loadseg(uint16_t seg, x86seg *s) 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 (cpu_state.abrt) return; + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return 1; dpl=(segdat[2]>>13)&3; - if (s==&_ss) + if (s==&cpu_state.seg_ss) { if (!(seg&~3)) { pclog("Load SS null selector\n"); x86gpf(NULL,seg&~3); - return; + return 1; } 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; + return 1; } switch ((segdat[2]>>8)&0x1F) { @@ -335,18 +397,18 @@ void loadseg(uint16_t seg, x86seg *s) pclog("Invalid SS type\n"); x86gpf(NULL,seg&~3); // x86abort("Invalid SS segment type for %04X!\n",seg&0xFFFC); - return; + return 1; } if (!(segdat[2]&0x8000)) { pclog("Load SS not present!\n"); x86ss(NULL,seg&~3); - return; + return 1; } - stack32 = (segdat[3] & 0x40) ? 1 : 0; + set_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) + else if (s!=&cpu_state.seg_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); @@ -361,7 +423,7 @@ void loadseg(uint16_t seg, x86seg *s) 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; + return 1; } break; case 0x1E: case 0x1F: /*Readable conforming code*/ @@ -369,14 +431,14 @@ void loadseg(uint16_t seg, x86seg *s) default: pclog("Invalid segment type for %04X! %04X\n",seg&0xFFFC,segdat[2]); x86gpf(NULL,seg&~3); - return; + return 1; } } if (!(segdat[2] & 0x8000)) { x86np("Load data seg not present", seg & 0xfffc); - return; + return 1; } s->seg = seg; do_seg_load(s, segdat); @@ -394,16 +456,42 @@ void loadseg(uint16_t seg, x86seg *s) } #endif s->checked = 0; + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; } else { s->access = (3 << 5) | 2; + s->access2 = 0; s->base = seg << 4; s->seg = seg; - if (s == &_ss) - stack32 = 0; s->checked = 1; + if (s == &cpu_state.seg_ds) + codegen_flat_ds = 0; + if (s == &cpu_state.seg_ss) + codegen_flat_ss = 0; + if (s == &cpu_state.seg_ss && (cpu_state.eflags & VM_FLAG)) + set_stack32(0); } + + if (s == &cpu_state.seg_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &cpu_state.seg_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } + + return cpu_state.abrt; } #define DPL ((segdat[2]>>13)&3) @@ -415,7 +503,7 @@ 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)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { // intcount++; // flushmmucache(); @@ -465,7 +553,7 @@ void loadcs(uint16_t seg) if ((seg&3)>CPL) { x86gpf(NULL,seg&~3); - pclog("loadcs RPL > CPL %04X %04X %i %02X\n",segdat[2],seg,CPL,opcode); + pclog("loadcs RPL > CPL %04X %04X %i\n",segdat[2],seg,CPL); return; } if (CPL != DPL) @@ -484,12 +572,12 @@ void loadcs(uint16_t seg) x86np("Load CS not present", seg & 0xfffc); return; } - if (segdat[3]&0x40) use32=0x300; - else use32=0; + set_use32(segdat[3] & 0x40); CS=(seg&~3)|CPL; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); use32=(segdat[3]&0x40)?0x300:0; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; #ifdef CS_ACCESSED cpl_override = 1; @@ -509,7 +597,7 @@ void loadcs(uint16_t seg) switch (segdat[2]&0xF00) { default: - pclog("Bad CS %02X %02X %i special descriptor %03X %04X\n",opcode,0/*rmdat*/,optype,segdat[2]&0xF00,seg); + pclog("Bad CS %02X %i special descriptor %03X %04X\n",0/*rmdat*/,optype,segdat[2]&0xF00,seg); x86gpf(NULL,seg&~3); return; } @@ -520,25 +608,26 @@ void loadcs(uint16_t seg) } else { - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg; - if (eflags&VM_FLAG) _cs.access=(3<<5) | 2; - else _cs.access=(0<<5) | 2; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2; + else cpu_state.seg_cs.access=(0<<5) | 2; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; } } -void loadcsjmp(uint16_t seg, uint32_t oxpc) +void loadcsjmp(uint16_t seg, uint32_t old_pc) { uint16_t segdat[4]; uint32_t addr; uint16_t type,seg2; uint32_t newpc; // pclog("Load CS JMP %04X\n",seg); - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { if (!(seg&~3)) { @@ -601,8 +690,7 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) x86np("Load CS JMP not present\n", seg & 0xfffc); return; } - if (segdat[3]&0x40) use32=0x300; - else use32=0; + set_use32(segdat[3]&0x40); #ifdef CS_ACCESSED cpl_override = 1; @@ -613,9 +701,19 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) CS = (seg & ~3) | CPL; segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + oldcpl = CPL; +/* if (segdat[3]&0x40) + { + use32=0x300; + cpu_cur_status |= CPU_STATUS_USE32; + } + else + { + use32=0; + cpu_cur_status &= ~CPU_STATUS_USE32; + }*/ cycles -= timing_jmp_pm; } else /*System segment*/ @@ -627,8 +725,8 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) return; } type=segdat[2]&0xF00; - if (type==0x400) newpc=segdat[0]; - else newpc=segdat[0]|(segdat[3]<<16); + newpc=segdat[0]; + if (type&0x800) newpc|=segdat[3]<<16; switch (type) { case 0x400: /*Call gate*/ @@ -636,7 +734,6 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) // pclog("Call gate\n"); cgate32=(type&0x800); cgate16=!cgate32; - oldcs=CS; cpu_state.oldpc = cpu_state.pc; if ((DPL < CPL) || (DPL < (seg&3))) { @@ -708,10 +805,11 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) } case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ CS=seg2; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; - cpu_state.pc=newpc; + oldcpl = CPL; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; #ifdef CS_ACCESSED cpl_override = 1; @@ -729,12 +827,14 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) break; + case 0x100: /*286 Task gate*/ case 0x900: /*386 Task gate*/ // pclog("Task gate\n"); - cpu_state.pc=oxpc; + cpu_state.pc = old_pc; + optype=JMP; cpl_override=1; taskswitch286(seg,segdat,segdat[2]&0x800); - flags &= ~NT_FLAG; + cpu_state.flags &= ~NT_FLAG; cpl_override=0; // case 0xB00: /*386 Busy task gate*/ // if (optype==JMP) pclog("Task switch!\n"); @@ -742,7 +842,7 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) return; default: - pclog("Bad JMP CS %02X %02X %i special descriptor %03X %04X\n",opcode,0/*rmdat*/,optype,segdat[2]&0xF00,seg); + pclog("Bad JMP CS %02X %i special descriptor %03X %04X\n",0/*rmdat*/,optype,segdat[2]&0xF00,seg); x86gpf(NULL,0); return; // dumpregs(); @@ -755,14 +855,15 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc) } else { - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg; - if (eflags&VM_FLAG) _cs.access=(3<<5) | 2; - else _cs.access=(0<<5) | 2; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2; + else cpu_state.seg_cs.access=(0<<5) | 2; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; cycles -= timing_jmp_rm; } } @@ -835,7 +936,7 @@ uint32_t POPL() return templ; } -void loadcscall(uint16_t seg) +void loadcscall(uint16_t seg, uint32_t old_pc) { uint16_t seg2; uint16_t segdat[4],segdat2[4],newss; @@ -848,7 +949,7 @@ void loadcscall(uint16_t seg) int csout = output; - if (msw&1 && !(eflags&VM_FLAG)) + if (msw&1 && !(cpu_state.eflags&VM_FLAG)) { //flushmmucache(); if (csout) pclog("Protected mode CS load! %04X\n",seg); @@ -887,8 +988,8 @@ void loadcscall(uint16_t seg) segdat[2]=readmemw(0,addr+4); segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; type=segdat[2]&0xF00; - if (type==0x400) newpc=segdat[0]; - else newpc=segdat[0]|(segdat[3]<<16); + newpc=segdat[0]; + if (type&0x800) newpc|=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) @@ -920,8 +1021,7 @@ void loadcscall(uint16_t seg) x86np("Load CS call not present", seg & 0xfffc); return; } - if (segdat[3]&0x40) use32=0x300; - else use32=0; + set_use32(segdat[3]&0x40); #ifdef CS_ACCESSED cpl_override = 1; @@ -938,9 +1038,19 @@ void loadcscall(uint16_t seg) else /*On non-conforming segments, set RPL = CPL*/ seg = (seg & ~3) | CPL; CS=seg; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + oldcpl = CPL; +/* if (segdat[3]&0x40) + { + use32=0x300; + cpu_cur_status |= CPU_STATUS_USE32; + } + else + { + use32=0; + cpu_cur_status &= ~CPU_STATUS_USE32; + }*/ if (csout) pclog("Complete\n"); cycles -= timing_call_pm; } @@ -1026,6 +1136,7 @@ void loadcscall(uint16_t seg) case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ if (DPL < CPL) { + uint16_t oldcs = CS; oaddr = addr; /*Load new stack*/ oldss=SS; @@ -1097,16 +1208,16 @@ void loadcscall(uint16_t seg) if (!(segdat2[2]&0x8000)) { pclog("Call gate loading SS not present\n"); - x86np("Call gate loading SS not present\n", newss & 0xfffc); + x86ss("Call gate loading SS not present\n", newss & 0xfffc); return; } if (!stack32) oldsp &= 0xFFFF; SS=newss; - stack32 = (segdat2[3] & 0x40) ? 1 : 0; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat2); + do_seg_load(&cpu_state.seg_ss, segdat2); if (output) pclog("Set access 1\n"); @@ -1117,9 +1228,10 @@ void loadcscall(uint16_t seg) #endif CS=seg2; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + oldcpl = CPL; + set_use32(segdat[3]&0x40); cpu_state.pc=newpc; if (output) pclog("Set access 2\n"); @@ -1140,6 +1252,7 @@ void loadcscall(uint16_t seg) pclog("ABRT PUSHL\n"); SS = oldss; ESP = oldsp2; + CS = oldcs; return; } // if (output) pclog("Stack now %04X:%08X\n",SS,ESP); @@ -1154,13 +1267,12 @@ void loadcscall(uint16_t seg) pclog("ABRT COPYL\n"); SS = oldss; ESP = oldsp2; + CS = oldcs; return; } } } // x86abort("Call gate with count %i\n",count); -// PUSHL(oldcs); -// PUSHL(oldpc); if (cpu_state.abrt) return; } else { @@ -1173,6 +1285,7 @@ void loadcscall(uint16_t seg) pclog("ABRT PUSHW\n"); SS = oldss; ESP = oldsp2; + CS = oldcs; return; } if (output) pclog("Write SP to %04X:%04X\n",SS,SP); @@ -1191,14 +1304,13 @@ void loadcscall(uint16_t seg) pclog("ABRT COPYW\n"); SS = oldss; ESP = oldsp2; + CS = oldcs; return; } } } // if (output) pclog("Stack %04X\n",SP); // if (count) x86abort("Call gate with count\n"); -// PUSHW(oldcs); -// PUSHW(oldpc); if (cpu_state.abrt) return; } cycles -= timing_call_pm_gate_inner; break; @@ -1210,21 +1322,12 @@ void loadcscall(uint16_t seg) return; } case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ -/* if (type==0xC00) - { - PUSHL(oldcs); - PUSHL(oldpc); if (cpu_state.abrt) return; - } - else - { - PUSHW(oldcs); - PUSHW(oldpc); if (cpu_state.abrt) return; - }*/ CS=seg2; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; - cpu_state.pc=newpc; + oldcpl = CPL; + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; #ifdef CS_ACCESSED cpl_override = 1; @@ -1241,12 +1344,14 @@ void loadcscall(uint16_t seg) } break; -// case 0x900: /*386 Task gate*/ -// case 0xB00: /*386 Busy task gate*/ -// if (optype==JMP) pclog("Task switch!\n"); -// taskswitch386(seg,segdat); -// return; - + case 0x100: /*286 Task gate*/ + case 0x900: /*386 Task gate*/ +// pclog("Task gate\n"); + cpu_state.pc = old_pc; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + cpl_override=0; + break; default: pclog("Bad CALL special descriptor %03X\n",segdat[2]&0xF00); @@ -1262,14 +1367,15 @@ void loadcscall(uint16_t seg) } else { - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg; - if (eflags&VM_FLAG) _cs.access=(3<<5) | 2; - else _cs.access=(0<<5) | 2; + if (cpu_state.eflags&VM_FLAG) cpu_state.seg_cs.access=(3<<5) | 2; + else cpu_state.seg_cs.access=(0<<5) | 2; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; } } @@ -1280,7 +1386,7 @@ void pmoderetf(int is32, uint16_t off) 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 (output) pclog("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,cpu_state.eflags); if (is32) { newpc=POPL(); @@ -1394,10 +1500,11 @@ void pmoderetf(int is32, uint16_t off) 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); + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + oldcpl = CPL; + set_use32(segdat[3] & 0x40); // pclog("CPL=RPL return to %04X:%08X\n",CS,pc); cycles -= timing_retf_pm; @@ -1526,10 +1633,10 @@ void pmoderetf(int is32, uint16_t off) return; } SS=newss; - stack32 = (segdat2[3] & 0x40) ? 1 : 0; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat2); + do_seg_load(&cpu_state.seg_ss, segdat2); #ifdef SEL_ACCESSED cpl_override = 1; @@ -1546,27 +1653,23 @@ void pmoderetf(int is32, uint16_t off) cpu_state.pc=newpc; CS=seg; - do_seg_load(&_cs, segdat); + do_seg_load(&cpu_state.seg_cs, segdat); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + oldcpl = CPL; + set_use32(segdat[3] & 0x40); if (stack32) ESP+=off; else SP+=off; - check_seg_valid(&_ds); - check_seg_valid(&_es); - check_seg_valid(&_fs); - check_seg_valid(&_gs); + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); // pclog("CPL=0x800) { // if (output) pclog("Push 32 %i\n",eflags&VM_FLAG); - if (eflags & VM_FLAG) + if (cpu_state.eflags & VM_FLAG) { PUSHL(GS); PUSHL(FS); PUSHL(DS); PUSHL(ES); if (cpu_state.abrt) return; - loadseg(0,&_ds); - loadseg(0,&_es); - loadseg(0,&_fs); - loadseg(0,&_gs); + loadseg(0,&cpu_state.seg_ds); + loadseg(0,&cpu_state.seg_es); + loadseg(0,&cpu_state.seg_fs); + loadseg(0,&cpu_state.seg_gs); } PUSHL(oldss); PUSHL(oldsp); - PUSHL(flags|(eflags<<16)); + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); // if (soft) pclog("Pushl CS %08X\n", CS); PUSHL(CS); // if (soft) pclog("Pushl PC %08X\n", pc); @@ -1818,7 +1924,7 @@ void pmodeint(int num, int soft) // if (output) pclog("Push 16\n"); PUSHW(oldss); PUSHW(oldsp); - PUSHW(flags); + PUSHW(cpu_state.flags); // if (soft) pclog("Pushw CS %04X\n", CS); PUSHW(CS); // if (soft) pclog("Pushw pc %04X\n", pc); @@ -1826,7 +1932,7 @@ void pmodeint(int num, int soft) // if (output) pclog("16Stack %04X:%08X\n",SS,ESP); } cpl_override=0; - _cs.access=0; + cpu_state.seg_cs.access=0; cycles -= timing_int_pm_outer - timing_int_pm; // pclog("Non-confirming int gate, CS = %04X\n"); break; @@ -1844,7 +1950,7 @@ void pmodeint(int num, int soft) x86np("Int gate CS not present\n", segdat[1] & 0xfffc); return; } - if ((eflags & VM_FLAG) && DPL20x800) { - PUSHL(flags|(eflags<<16)); + PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); // if (soft) pclog("Pushlc CS %08X\n", CS); PUSHL(CS); // if (soft) pclog("Pushlc PC %08X\n", pc); @@ -1861,7 +1967,7 @@ void pmodeint(int num, int soft) } else { - PUSHW(flags); + PUSHW(cpu_state.flags); // if (soft) pclog("Pushwc CS %04X\n", CS); PUSHW(CS); // if (soft) pclog("Pushwc PC %04X\n", pc); @@ -1874,14 +1980,15 @@ void pmodeint(int num, int soft) x86gpf(NULL,seg&~3); return; } - do_seg_load(&_cs, segdat2); + do_seg_load(&cpu_state.seg_cs, segdat2); CS = (seg & ~3) | new_cpl; - _cs.access = (_cs.access & ~(3 << 5)) | (new_cpl << 5); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | (new_cpl << 5); // pclog("New CS = %04X\n",CS); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); else cpu_state.pc=segdat[0]; - use32=(segdat2[3]&0x40)?0x300:0; + set_use32(segdat2[3]&0x40); // pclog("Int gate done!\n"); #ifdef CS_ACCESSED @@ -1890,13 +1997,14 @@ void pmodeint(int num, int soft) cpl_override = 0; #endif - eflags&=~VM_FLAG; + cpu_state.eflags &= ~VM_FLAG; + cpu_cur_status &= ~CPU_STATUS_V86; if (!(type&0x100)) { - flags&=~I_FLAG; + cpu_state.flags &= ~I_FLAG; // pclog("INT %02X disabling interrupts %i\n",num,soft); } - flags&=~(T_FLAG|NT_FLAG); + cpu_state.flags &= ~(T_FLAG|NT_FLAG); // if (output) pclog("Final Stack %04X:%08X\n",SS,ESP); cycles -= timing_int_pm; break; @@ -1961,7 +2069,7 @@ void pmodeiret(int is32) uint16_t seg = 0; uint32_t addr, oaddr; uint32_t oldsp=ESP; - if (is386 && (eflags&VM_FLAG)) + if (is386 && (cpu_state.eflags & VM_FLAG)) { // if (output) pclog("V86 IRET\n"); if (IOPL!=3) @@ -1970,7 +2078,6 @@ void pmodeiret(int is32) x86gpf(NULL,0); return; } - oxpc=cpu_state.pc; if (is32) { newpc=POPL(); @@ -1984,12 +2091,12 @@ void pmodeiret(int is32) tempflags=POPW(); if (cpu_state.abrt) return; } cpu_state.pc=newpc; - _cs.base=seg<<4; - _cs.limit=0xFFFF; - _cs.limit_low = 0; - _cs.limit_high = 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg; - flags=(flags&0x3000)|(tempflags&0xCFD5)|2; + cpu_state.flags = (cpu_state.flags & 0x3000) | (tempflags & 0xCFD5) | 2; cycles -= timing_iret_rm; return; } @@ -1998,7 +2105,7 @@ void pmodeiret(int is32) //flushmmucache(); // if (output) pclog("Pmode IRET %04X:%04X ",CS,pc); - if (flags&NT_FLAG) + if (cpu_state.flags & NT_FLAG) { // pclog("NT IRET\n"); seg=readmemw(tr.base,0); @@ -2024,11 +2131,10 @@ void pmodeiret(int is32) segdat[1]=readmemw(0,addr+2); segdat[2]=readmemw(0,addr+4); segdat[3]=readmemw(0,addr+6); - taskswitch286(seg,segdat,0); + taskswitch286(seg,segdat,segdat[2] & 0x800); cpl_override=0; return; } - oxpc=cpu_state.pc; flagmask=0xFFFF; if (CPL) flagmask&=~0x3000; if (IOPL>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); + cpu_state.eflags = tempflags>>16; + cpu_cur_status |= CPU_STATUS_V86; + loadseg(segs[0],&cpu_state.seg_es); + do_seg_v86_init(&cpu_state.seg_es); + loadseg(segs[1],&cpu_state.seg_ds); + do_seg_v86_init(&cpu_state.seg_ds); + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + loadseg(segs[2],&cpu_state.seg_fs); + do_seg_v86_init(&cpu_state.seg_fs); + loadseg(segs[3],&cpu_state.seg_gs); + do_seg_v86_init(&cpu_state.seg_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; + cpu_state.pc = newpc & 0xffff; + cpu_state.seg_cs.base=seg<<4; + cpu_state.seg_cs.limit=0xFFFF; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffff; CS=seg; - _cs.access=(3<<5) | 2; + cpu_state.seg_cs.access=(3<<5) | 2; if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; ESP=newsp; - loadseg(newss,&_ss); - do_seg_v86_init(&_ss); + loadseg(newss,&cpu_state.seg_ss); + do_seg_v86_init(&cpu_state.seg_ss); + cpu_cur_status |= CPU_STATUS_NOTFLATSS; use32=0; - flags=(tempflags&0xFFD5)|2; + cpu_cur_status &= ~CPU_STATUS_USE32; + cpu_state.flags = (tempflags&0xFFD5)|2; cycles -= timing_iret_v86; // pclog("V86 IRET to %04X:%04X %04X:%04X %04X %04X %04X %04X %i\n",CS,pc,SS,SP,DS,ES,FS,GS,abrt); // if (CS==0xFFFF && pc==0xFFFFFFFF) timetolive=12; @@ -2186,10 +2297,11 @@ void pmodeiret(int is32) { // pclog("Same level\n"); CS=seg; - do_seg_load(&_cs, segdat); - _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + oldcpl = CPL; + set_use32(segdat[3]&0x40); #ifdef CS_ACCESSED cpl_override = 1; @@ -2283,10 +2395,10 @@ void pmodeiret(int is32) return; } SS=newss; - stack32 = (segdat2[3] & 0x40) ? 1 : 0; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); if (stack32) ESP=newsp; else SP=newsp; - do_seg_load(&_ss, segdat2); + do_seg_load(&cpu_state.seg_ss, segdat2); #ifdef SEL_ACCESSED cpl_override = 1; @@ -2302,20 +2414,21 @@ void pmodeiret(int is32) 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); + do_seg_load(&cpu_state.seg_cs, segdat); + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~(3 << 5)) | ((CS & 3) << 5); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat[3]&0x40)?0x300:0; + oldcpl = CPL; + set_use32(segdat[3] & 0x40); - check_seg_valid(&_ds); - check_seg_valid(&_es); - check_seg_valid(&_fs); - check_seg_valid(&_gs); + check_seg_valid(&cpu_state.seg_ds); + check_seg_valid(&cpu_state.seg_es); + check_seg_valid(&cpu_state.seg_fs); + check_seg_valid(&cpu_state.seg_gs); cycles -= timing_iret_pm_outer; } cpu_state.pc=newpc; - flags=(flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; - if (is32) eflags=tempflags>>16; + cpu_state.flags = (cpu_state.flags&~flagmask) | (tempflags&flagmask&0xFFD5)|2; + if (is32) cpu_state.eflags = tempflags>>16; // pclog("done\n"); } @@ -2337,56 +2450,45 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) uint16_t segdat2[4]; //output=3; - base=segdat[1]|((segdat[2]&0xFF)<<16)|((segdat[3]>>8)<<24); - limit=segdat[0]|((segdat[3]&0xF)<<16); + base=segdat[1]|((segdat[2]&0xFF)<<16); + limit=segdat[0]; + if(is386) + { + base |= (segdat[3]>>8)<<24; + limit |= (segdat[3]&0xF)<<16; + } // pclog("286 Task switch! %04X:%04X\n",CS,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 (is32) { // 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 (cpu_state.abrt) return; - if (optype==JMP || optype==OPTYPE_INT) + if (limit < 103) { - if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); - else tempw=readmemw(gdt.base,(tr.seg&~7)+4); - if (cpu_state.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); + pclog("32-bit TSS %04X limit less than 103.\n", seg); + x86ts(NULL, seg); + return; } - - if (optype==IRET) flags&=~NT_FLAG; + + if (optype==JMP || optype==CALL || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (cpu_state.abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype==IRET) cpu_state.flags&=~NT_FLAG; // if (output) pclog("Write PC %08X %08X\n",tr.base,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,0x24,cpu_state.flags | (cpu_state.eflags<<16)); writememl(tr.base,0x28,EAX); writememl(tr.base,0x2C,ECX); @@ -2404,24 +2506,51 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) 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) + if (optype==JMP || optype==IRET) { - writememl(base,0,tr.seg); - new_flags|=NT_FLAG; + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (cpu_state.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 (cpu_state.abrt) return; - if (optype==JMP || optype==OPTYPE_INT) + + if (optype==OPTYPE_INT || optype==CALL) { - if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); - else tempw=readmemw(gdt.base,(seg&~7)+4); - if (cpu_state.abrt) return; - tempw|=0x200; - if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); - else writememw(gdt.base,(seg&~7)+4,tempw); + writememl(base,0,tr.seg); + if (cpu_state.abrt) + return; } + + new_cr3=readmeml(base,0x1C); + new_pc=readmeml(base,0x20); + new_flags=readmeml(base,0x24); + if (optype == OPTYPE_INT || optype == CALL) + new_flags |= NT_FLAG; + + 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); + + cr0 |= 8; cr3=new_cr3; @@ -2432,8 +2561,8 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) cpu_state.pc=new_pc; // if (output) pclog("New pc %08X\n",new_pc); - flags=new_flags; - eflags=new_flags>>16; + cpu_state.flags = new_flags; + cpu_state.eflags = new_flags>>16; cpu_386_flags_extract(); // if (output) pclog("Load LDT %04X\n",new_ldt); @@ -2450,17 +2579,219 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) // if (output) pclog("Limit %04X Base %08X\n",ldt.limit,ldt.base); - if (eflags&VM_FLAG) + if (cpu_state.eflags & VM_FLAG) { - pclog("Task switch V86!\n"); - x86gpf(NULL,0); + loadcs(new_cs); + set_use32(0); + cpu_cur_status |= CPU_STATUS_V86; + } + else + { + if (!(new_cs&~3)) + { + pclog("TS loading null CS\n"); + x86ts(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); + x86ts(NULL,new_cs&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X TS\n",new_cs,gdt.limit); + x86ts(NULL,new_cs&~3); + 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"); + x86ts(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"); + x86ts(NULL,new_cs&~3); + return; + } + break; + default: + pclog("TS load CS not code segment\n"); + x86ts(NULL,new_cs&~3); + return; + } + +// if (output) pclog("new_cs %04X\n",new_cs); + CS=new_cs; + do_seg_load(&cpu_state.seg_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + oldcpl = CPL; + set_use32(segdat2[3] & 0x40); + cpu_cur_status &= ~CPU_STATUS_V86; + } + + 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,&cpu_state.seg_es); + if (output) pclog("Load SS %04X\n",new_ss); + loadseg(new_ss,&cpu_state.seg_ss); + if (output) pclog("Load DS %04X\n",new_ds); + loadseg(new_ds,&cpu_state.seg_ds); + if (output) pclog("Load FS %04X\n",new_fs); + loadseg(new_fs,&cpu_state.seg_fs); + if (output) pclog("Load GS %04X\n",new_gs); + loadseg(new_gs,&cpu_state.seg_gs); + + if (output) pclog("Resuming at %04X:%08X\n",CS,cpu_state.pc); + } + else + { +// pclog("16-bit TSS\n"); +// resetx86(); + if (limit < 43) + { + pclog("16-bit TSS %04X limit less than 43.\n", seg); + x86ts(NULL, seg); return; } + if (optype==JMP || optype==CALL || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (cpu_state.abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype == IRET) + cpu_state.flags &= ~NT_FLAG; + +// if (output) pclog("Write PC %08X %08X\n",tr.base,pc); + cpu_386_flags_rebuild(); + writememw(tr.base,0x0E,cpu_state.pc); + writememw(tr.base,0x10,cpu_state.flags); + + writememw(tr.base,0x12,AX); + writememw(tr.base,0x14,CX); + writememw(tr.base,0x16,DX); + writememw(tr.base,0x18,BX); + writememw(tr.base,0x1A,SP); + writememw(tr.base,0x1C,BP); + writememw(tr.base,0x1E,SI); + writememw(tr.base,0x20,DI); + + writememw(tr.base,0x22,ES); +// if (output) pclog("Write CS %04X to %08X\n",CS,tr.base+0x4C); + writememw(tr.base,0x24,CS); + writememw(tr.base,0x26,SS); + writememw(tr.base,0x28,DS); + + if (optype==JMP || optype==IRET) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (cpu_state.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 (cpu_state.abrt) return; + + if (optype==OPTYPE_INT || optype==CALL) + { + writememw(base,0,tr.seg); + if (cpu_state.abrt) + return; + } + + new_pc=readmemw(base,0x0E); + new_flags=readmemw(base,0x10); + if (optype == OPTYPE_INT || optype == CALL) + new_flags |= NT_FLAG; + + new_eax=readmemw(base,0x12); + new_ecx=readmemw(base,0x14); + new_edx=readmemw(base,0x16); + new_ebx=readmemw(base,0x18); + new_esp=readmemw(base,0x1A); + new_ebp=readmemw(base,0x1C); + new_esi=readmemw(base,0x1E); + new_edi=readmemw(base,0x20); + + new_es=readmemw(base,0x22); +// if (output) pclog("Read CS from %08X\n",base+0x4C); + new_cs=readmemw(base,0x24); + new_ss=readmemw(base,0x26); + new_ds=readmemw(base,0x28); + new_ldt=readmemw(base,0x2A); + + msw |= 8; + + cpu_state.pc=new_pc; +// if (output) pclog("New pc %08X\n",new_pc); + cpu_state.flags = new_flags; + 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); + ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16); + if (is386) + { + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base|=(readmemb(0,templ+7)<<24); + } +// if (output) pclog("Limit %04X Base %08X\n",ldt.limit,ldt.base); + + if (!(new_cs&~3)) { pclog("TS loading null CS\n"); - x86gpf(NULL,0); + x86ts(NULL,0); return; } addr=new_cs&~7; @@ -2469,7 +2800,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) if (addr>=ldt.limit) { pclog("Bigger than LDT limit %04X %04X %04X TS\n",new_cs,ldt.limit,addr); - x86gpf(NULL,0); + x86ts(NULL,new_cs&~3); return; } addr+=ldt.base; @@ -2479,7 +2810,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) if (addr>=gdt.limit) { pclog("Bigger than GDT limit %04X %04X TS\n",new_cs,gdt.limit); - x86gpf(NULL,0); + x86ts(NULL,new_cs&~3); return; } addr+=gdt.base; @@ -2500,7 +2831,7 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) if ((new_cs&3) != DPL2) { pclog("TS load CS non-conforming RPL != DPL"); - x86gpf(NULL,new_cs&~3); + x86ts(NULL,new_cs&~3); return; } break; @@ -2508,48 +2839,45 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) if ((new_cs&3) < DPL2) { pclog("TS load CS non-conforming RPL < DPL"); - x86gpf(NULL,new_cs&~3); + x86ts(NULL,new_cs&~3); return; } break; default: pclog("TS load CS not code segment\n"); - x86gpf(NULL,new_cs&~3); + x86ts(NULL,new_cs&~3); return; } // if (output) pclog("new_cs %04X\n",new_cs); CS=new_cs; - do_seg_load(&_cs, segdat2); + do_seg_load(&cpu_state.seg_cs, segdat2); if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); - use32=(segdat2[3]&0x40)?0x300:0; + oldcpl = CPL; + set_use32(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; + EAX=new_eax | 0xFFFF0000; + ECX=new_ecx | 0xFFFF0000; + EDX=new_edx | 0xFFFF0000; + EBX=new_ebx | 0xFFFF0000; + ESP=new_esp | 0xFFFF0000; + EBP=new_ebp | 0xFFFF0000; + ESI=new_esi | 0xFFFF0000; + EDI=new_edi | 0xFFFF0000; if (output) pclog("Load ES %04X\n",new_es); - loadseg(new_es,&_es); + loadseg(new_es,&cpu_state.seg_es); if (output) pclog("Load SS %04X\n",new_ss); - loadseg(new_ss,&_ss); + loadseg(new_ss,&cpu_state.seg_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); + loadseg(new_ds,&cpu_state.seg_ds); + if (is386) + { + loadseg(0,&cpu_state.seg_fs); + loadseg(0,&cpu_state.seg_gs); + } if (output) pclog("Resuming at %04X:%08X\n",CS,cpu_state.pc); - } - else - { - pclog("16-bit TSS\n"); - resetx86(); //exit(-1); } @@ -2560,3 +2888,370 @@ void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) tr.access=segdat[2]>>8; } + +void sysenter(void) +{ + cpu_state.eflags &= ~VM_FLAG; + cpu_state.flags &= ~I_FLAG; + + ESP = sysenter_esp; + cpu_state.pc = sysenter_eip; + + cpu_state.seg_cs.seg = sysenter_cs & 0xfffc; + cpu_state.seg_cs.base = 0; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.access = 0x1b; + cpu_state.seg_cs.checked = 1; + oldcpl = 0; + + cpu_state.seg_ss.seg = (sysenter_cs & 0xfffc) + 8; + cpu_state.seg_ss.base = 0; + cpu_state.seg_ss.limit_low = 0; + cpu_state.seg_ss.limit = 0xffffffff; + cpu_state.seg_ss.limit_high = 0xffffffff; + cpu_state.seg_ss.access = 0x13; + cpu_state.seg_ss.checked = 1; + + cpu_cur_status &= ~(CPU_STATUS_NOTFLATSS | CPU_STATUS_V86); + cpu_cur_status |= (CPU_STATUS_USE32 | CPU_STATUS_STACK32 | CPU_STATUS_PMODE); + set_use32(1); + set_stack32(1); + +// pclog("syscall to %04x:%08x %04x:%08x\n", CS, cpu_state.pc, SS, ESP); +} + +void sysexit(void) +{ + ESP = ECX; + cpu_state.pc = EDX; + + cpu_state.seg_cs.seg = (sysenter_cs | 3) + 16; + cpu_state.seg_cs.base = 0; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.access = 0x7b; + cpu_state.seg_cs.checked = 1; + oldcpl = 3; + + cpu_state.seg_ss.seg = (sysenter_cs | 3) + 24; + cpu_state.seg_ss.base = 0; + cpu_state.seg_ss.limit_low = 0; + cpu_state.seg_ss.limit = 0xffffffff; + cpu_state.seg_ss.limit_high = 0xffffffff; + cpu_state.seg_ss.access = 0x73; + cpu_state.seg_ss.checked = 1; + + cpu_cur_status &= ~(CPU_STATUS_NOTFLATSS | CPU_STATUS_V86); + cpu_cur_status |= (CPU_STATUS_USE32 | CPU_STATUS_STACK32 | CPU_STATUS_PMODE); + flushmmucache_cr3(); + set_use32(1); + set_stack32(1); + +// pclog("sysexit to %04x:%08x %04x:%08x\n", CS, cpu_state.pc, SS, ESP); +} + +void x86_smi_trigger(void) +{ + cpu_state.smi_pending = 1; +} + +static void smi_write_descriptor_cache(uint32_t addr, x86seg *seg) +{ + writememl(0, addr + 8, seg->seg | (seg->access << 16) | (seg->access2 << 24)); + writememl(0, addr + 4, seg->base); + writememl(0, addr, seg->limit); +} +static void smi_load_descriptor_cache(uint32_t addr, x86seg *seg) +{ + uint32_t temp; + + temp = readmeml(0, addr + 8); + seg->base = readmeml(0, addr + 4); + seg->limit = readmeml(0, addr); + seg->seg = temp & 0xffff; + seg->access = temp >> 16; + seg->access2 = temp >> 24; + if ((seg->access & 0x18) != 0x10 || !(seg->access & (1 << 2))) /*expand-down*/ + { + seg->limit_high = seg->limit; + seg->limit_low = 0; + } + else + { + seg->limit_high = (seg->access2 & 0x40) ? 0xffffffff : 0xffff; + seg->limit_low = seg->limit + 1; + } +} + +static void smi_load_smi_selector(x86seg *seg) +{ + seg->seg = 0; + seg->base = 0; + seg->limit = 0xffffffff; + seg->limit_low = 0; + seg->limit_high = 0xffffffff; + seg->access = (3 << 5) | 2; + seg->access2 = 0; +} + +void cyrix_write_seg_descriptor(uint32_t addr, x86seg *seg) +{ + writememl(0, addr, (seg->limit_raw & 0xffff) | (seg->base << 16)); + writememl(0, addr+4, ((seg->base >> 16) & 0xff) | + (seg->access << 8) | + (seg->limit_raw & 0xf0000) | + (seg->access2 << 16) | + (seg->base & 0xff000000)); +} + +void cyrix_load_seg_descriptor(uint32_t addr, x86seg *seg) +{ + uint16_t segdat[4], selector; + + segdat[0] = readmemw(0, addr); + segdat[1] = readmemw(0, addr+2); + segdat[2] = readmemw(0, addr+4); + segdat[3] = readmemw(0, addr+6); + selector = readmemw(0, addr+8); + + if (!cpu_state.abrt) + { + do_seg_load(seg, segdat); + seg->seg = selector; + seg->checked = 0; + if (seg == &cpu_state.seg_ds) + { + if (seg->base == 0 && seg->limit_low == 0 && seg->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + codegen_flat_ds = 0; + } + if (seg == &cpu_state.seg_ss) + { + if (seg->base == 0 && seg->limit_low == 0 && seg->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + set_stack32((segdat[3] & 0x40) ? 1 : 0); + codegen_flat_ss = 0; + } + } +} + +void x86_smi_enter(void) +{ + uint32_t old_cr0 = cr0; + + if (smram_enable) + smram_enable(); + flushmmucache(); + + cpu_386_flags_rebuild(); + cpl_override = 1; + cr0 = 0; /*Disable MMU*/ + + if (cpu_iscyrix) + { + uint32_t base; + + if (!(cyrix.smhr & SMHR_VALID)) + cyrix.smhr = (cyrix.arr[3].base + cyrix.arr[3].size) | SMHR_VALID; + base = cyrix.smhr & SMHR_ADDR_MASK; + + writememl(0, base-4, dr[7]); + writememl(0, base-8, cpu_state.flags | (cpu_state.eflags << 16)); + writememl(0, base-0xc, old_cr0); + writememl(0, base-0x10, cpu_state.oldpc); + writememl(0, base-0x14, cpu_state.pc); + writememl(0, base-0x18, CS | (CPL << 21)); + cyrix_write_seg_descriptor(base-0x20, &cpu_state.seg_cs); + writememl(0, base-0x24, 0); + + cpl_override = 0; + + cpu_cur_status = CPU_STATUS_SMM; + cpu_state.flags = 2; + cpu_state.eflags = 0; + cpu_state.pc = 0; + cr0 &= ~((1 << 0) | (1 << 2) | (1 << 3) | (1 << 31)); + dr[7] = 0x400; + cpu_state.seg_cs.seg = cyrix.arr[3].base >> 4; /*Guess*/ + cpu_state.seg_cs.base = cyrix.arr[3].base; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.access = (0 << 5) | 2; + + use32 = 0; + stack32 = 0; + } + else + { + writememl(0, cpu_state.smbase + 0x8000 + 0x7ffc, old_cr0); + writememl(0, cpu_state.smbase + 0x8000 + 0x7ff8, cr3); + writememl(0, cpu_state.smbase + 0x8000 + 0x7ff4, cpu_state.flags | (cpu_state.eflags << 16)); + writememl(0, cpu_state.smbase + 0x8000 + 0x7ff0, cpu_state.pc); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fec, EDI); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fe8, ESI); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fe4, EBP); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fe0, ESP); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fdc, EBX); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fd8, EDX); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fd4, ECX); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fd0, EAX); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fcc, dr[6]); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fc8, dr[7]); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fc4, tr.seg); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fc0, ldt.seg); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fbc, cpu_state.seg_gs.seg); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fb8, cpu_state.seg_fs.seg); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fb4, cpu_state.seg_ds.seg); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fb0, cpu_state.seg_ss.seg); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fac, cpu_state.seg_cs.seg); + writememl(0, cpu_state.smbase + 0x8000 + 0x7fa8, cpu_state.seg_es.seg); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f9c, &tr); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f90, &idt); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f84, &gdt); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f78, &ldt); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f6c, &cpu_state.seg_gs); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f60, &cpu_state.seg_fs); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f54, &cpu_state.seg_ds); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f48, &cpu_state.seg_ss); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f3c, &cpu_state.seg_cs); + smi_write_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f30, &cpu_state.seg_es); + writememl(0, cpu_state.smbase + 0x8000 + 0x7f28, cr4); + writememl(0, cpu_state.smbase + 0x8000 + 0x7ef8, cpu_state.smbase); + writememl(0, cpu_state.smbase + 0x8000 + 0x7efc, 0x00020000); + cpl_override = 0; + + cpu_cur_status = CPU_STATUS_SMM; + cpu_state.flags = 2; + cpu_state.eflags = 0; + cpu_state.pc = 0x8000; + cr0 &= ~((1 << 0) | (1 << 2) | (1 << 3) | (1 << 31)); + dr[7] = 0x400; + smi_load_smi_selector(&cpu_state.seg_ds); + smi_load_smi_selector(&cpu_state.seg_es); + smi_load_smi_selector(&cpu_state.seg_fs); + smi_load_smi_selector(&cpu_state.seg_gs); + smi_load_smi_selector(&cpu_state.seg_ss); + cpu_state.seg_cs.seg = 0x3000; + cpu_state.seg_cs.base = cpu_state.smbase; + cpu_state.seg_cs.limit = 0xffffffff; + cpu_state.seg_cs.limit_low = 0; + cpu_state.seg_cs.limit_high = 0xffffffff; + cpu_state.seg_cs.access = (0 << 5) | 2; + + use32 = 0; + stack32 = 0; + } + + oldcpl = 0; + +// pclog("x86_smi_enter\n"); +} + +void x86_smi_leave(void) +{ + uint32_t temp; + uint32_t new_cr0; + + if (cpu_iscyrix) + { + uint32_t base = cyrix.smhr & SMHR_ADDR_MASK; + + cpl_override = 1; + dr[7] = readmeml(0, base-4); + temp = readmeml(0, base-8); + cpu_state.flags = temp & 0xffff; + cpu_state.eflags = temp >> 16; + new_cr0 = readmeml(0, base-0xc); + cpu_state.pc = readmeml(0, base-0x14); + cyrix_load_seg_descriptor(base-0x20, &cpu_state.seg_cs); + cpl_override = 0; + + cr0 = new_cr0; + } + else + { + cpl_override = 1; + new_cr0 = readmeml(0, cpu_state.smbase + 0x8000 + 0x7ffc); + cr3 = readmeml(0, cpu_state.smbase + 0x8000 + 0x7ff8); + temp = readmeml(0, cpu_state.smbase + 0x8000 + 0x7ff4); + cpu_state.flags = temp & 0xffff; + cpu_state.eflags = temp >> 16; + cpu_state.pc = readmeml(0, cpu_state.smbase + 0x8000 + 0x7ff0); + EDI = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fec); + ESI = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fe8); + EBP = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fe4); + ESP = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fe0); + EBX = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fdc); + EDX = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fd8); + ECX = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fd4); + EAX = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fd0); + dr[6] = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fcc); + dr[7] = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fc8); + tr.seg = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fc4); + ldt.seg = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fc0); + cpu_state.seg_gs.seg = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fbc); + cpu_state.seg_fs.seg = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fb8); + cpu_state.seg_ds.seg = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fb4); + cpu_state.seg_ss.seg = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fb0); + cpu_state.seg_cs.seg = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fac); + cpu_state.seg_es.seg = readmeml(0, cpu_state.smbase + 0x8000 + 0x7fa8); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f9c, &tr); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f90, &idt); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f84, &gdt); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f78, &ldt); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f6c, &cpu_state.seg_gs); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f60, &cpu_state.seg_fs); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f54, &cpu_state.seg_ds); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f48, &cpu_state.seg_ss); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f3c, &cpu_state.seg_cs); + smi_load_descriptor_cache(cpu_state.smbase + 0x8000 + 0x7f30, &cpu_state.seg_es); + cr4 = readmeml(0, cpu_state.smbase + 0x8000 + 0x7f28); + cpu_state.smbase = readmeml(0, cpu_state.smbase + 0x8000 + 0x7ef8); + cpl_override = 0; + + cr0 = new_cr0; + } + + cpu_386_flags_extract(); + cpu_cur_status = 0; + use32 = stack32 = 0; + if (cr0 & 1) + { + cpu_cur_status |= CPU_STATUS_PMODE; + if (cpu_state.eflags & VM_FLAG) + cpu_cur_status |= CPU_STATUS_V86; + else + { + if (cpu_state.seg_cs.access2 & 0x40) + { + cpu_cur_status |= CPU_STATUS_USE32; + use32 = 0x300; + } + if (cpu_state.seg_ss.access2 & 0x40) + { + cpu_cur_status |= CPU_STATUS_STACK32; + stack32 = 1; + } + } + } + if (!(cpu_state.seg_ds.base == 0 && cpu_state.seg_ds.limit_low == 0 && cpu_state.seg_ds.limit_high == 0xffffffff)) + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + if (!(cpu_state.seg_ss.base == 0 && cpu_state.seg_ss.limit_low == 0 && cpu_state.seg_ss.limit_high == 0xffffffff)) + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + + if (smram_disable) + smram_disable(); + flushmmucache(); + + oldcpl = CPL; + +// pclog("x86_smi_leave\n"); +} diff --git a/src/x87.c b/src/x87.c index 25ce726..ac2650d 100644 --- a/src/x87.c +++ b/src/x87.c @@ -19,6 +19,11 @@ #include "x87.h" #include "386_common.h" +#define X87_TAG_VALID 0 +#define X87_TAG_ZERO 1 +#define X87_TAG_INVALID 2 +#define X87_TAG_EMPTY 3 + uint16_t x87_gettag() { uint16_t ret = 0; @@ -26,10 +31,14 @@ uint16_t x87_gettag() for (c = 0; c < 8; c++) { - if (cpu_state.tag[c] & TAG_UINT64) + if (cpu_state.tag[c] == TAG_EMPTY) + ret |= X87_TAG_EMPTY << (c * 2); + else if (cpu_state.tag[c] & TAG_UINT64) ret |= 2 << (c*2); + else if (cpu_state.ST[c] == 0.0 && !cpu_state.ismmx) + ret |= X87_TAG_ZERO << (c * 2); else - ret |= (cpu_state.tag[c] << (c*2)); + ret |= X87_TAG_VALID << (c * 2); } return ret; @@ -37,14 +46,19 @@ uint16_t x87_gettag() void x87_settag(uint16_t new_tag) { - cpu_state.tag[0] = new_tag & 3; - cpu_state.tag[1] = (new_tag >> 2) & 3; - cpu_state.tag[2] = (new_tag >> 4) & 3; - cpu_state.tag[3] = (new_tag >> 6) & 3; - cpu_state.tag[4] = (new_tag >> 8) & 3; - cpu_state.tag[5] = (new_tag >> 10) & 3; - cpu_state.tag[6] = (new_tag >> 12) & 3; - cpu_state.tag[7] = (new_tag >> 14) & 3; + int c; + + for (c = 0; c < 8; c++) + { + int tag = (new_tag >> (c * 2)) & 3; + + if (tag == X87_TAG_EMPTY) + cpu_state.tag[c] = TAG_EMPTY; + else if (tag == 2) + cpu_state.tag[c] = TAG_VALID | TAG_UINT64; + else + cpu_state.tag[c] = TAG_VALID; + } } void x87_dumpregs() @@ -56,7 +70,7 @@ void x87_dumpregs() } else { - pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",cpu_state.ST[cpu_state.TOP],cpu_state.ST[(cpu_state.TOP+1)&7],cpu_state.ST[(cpu_state.TOP+2)&7],cpu_state.ST[(cpu_state.TOP+3)&7]); + pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",cpu_state.ST[cpu_state.TOP&7],cpu_state.ST[(cpu_state.TOP+1)&7],cpu_state.ST[(cpu_state.TOP+2)&7],cpu_state.ST[(cpu_state.TOP+3)&7]); pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",cpu_state.ST[(cpu_state.TOP+4)&7],cpu_state.ST[(cpu_state.TOP+5)&7],cpu_state.ST[(cpu_state.TOP+6)&7],cpu_state.ST[(cpu_state.TOP+7)&7]); } pclog("Status = %04X Control = %04X Tag = %04X\n", cpu_state.npxs, cpu_state.npxc, x87_gettag()); diff --git a/src/x87.h b/src/x87.h index 790b6eb..9441a41 100644 --- a/src/x87.h +++ b/src/x87.h @@ -1,16 +1,21 @@ +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + uint32_t x87_pc_off,x87_op_off; uint16_t x87_pc_seg,x87_op_seg; static inline void x87_set_mmx() { cpu_state.TOP = 0; - *(uint64_t *)cpu_state.tag = 0; + *(uint64_t *)cpu_state.tag = 0x0101010101010101ull; cpu_state.ismmx = 1; } static inline void x87_emms() { - *(uint64_t *)cpu_state.tag = 0x0303030303030303ll; + *(uint64_t *)cpu_state.tag = 0; cpu_state.ismmx = 0; } @@ -19,5 +24,14 @@ void x87_settag(uint16_t new_tag); void x87_dumpregs(); void x87_reset(); +#define TAG_EMPTY 0 +#define TAG_VALID (1 << 0) /*Hack for FPU copy. If set then MM[].q contains the 64-bit integer loaded by FILD*/ -#define TAG_UINT64 (1 << 2) +#define TAG_UINT64 (1 << 7) + +#define X87_ROUNDING_NEAREST 0 +#define X87_ROUNDING_DOWN 1 +#define X87_ROUNDING_UP 2 +#define X87_ROUNDING_CHOP 3 + +void codegen_set_rounding_mode(int mode); diff --git a/src/x87_ops.h b/src/x87_ops.h index 1bb5fd5..361dcb7 100644 --- a/src/x87_ops.h +++ b/src/x87_ops.h @@ -1,5 +1,6 @@ #include #include +#include "x87_timings.h" #define fplog 0 @@ -7,26 +8,23 @@ static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZ #define ST(x) cpu_state.ST[((cpu_state.TOP+(x))&7)] -#define C0 (1<<8) -#define C1 (1<<9) -#define C2 (1<<10) -#define C3 (1<<14) - #define STATUS_ZERODIVIDE 4 +#define FPCW_DISI (1 << 7) + #define x87_div(dst, src1, src2) do \ { \ if (((double)src2) == 0.0) \ { \ - cpu_state.npxs |= STATUS_ZERODIVIDE; \ - if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ dst = src1 / (double)src2; \ else \ { \ pclog("FPU : divide by zero\n"); \ picint(1 << 13); \ + return 1; \ } \ - return 1; \ } \ else \ dst = src1 / (double)src2; \ @@ -38,16 +36,31 @@ static inline void x87_checkexceptions() static inline void x87_push(double i) { - cpu_state.TOP=(cpu_state.TOP-1)&7; - cpu_state.ST[cpu_state.TOP] = i; - cpu_state.tag[cpu_state.TOP&7] = (i == 0.0) ? 1 : 0; + cpu_state.TOP--; + cpu_state.ST[cpu_state.TOP&7] = i; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; +} + +static inline void x87_push_u64(uint64_t i) +{ + union + { + double d; + uint64_t ll; + } td; + + td.ll = i; + + cpu_state.TOP--; + cpu_state.ST[cpu_state.TOP&7] = td.d; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; } static inline double x87_pop() { - double t = cpu_state.ST[cpu_state.TOP]; - cpu_state.tag[cpu_state.TOP&7] = 3; - cpu_state.TOP=(cpu_state.TOP+1)&7; + double t = cpu_state.ST[cpu_state.TOP&7]; + cpu_state.tag[cpu_state.TOP&7] = TAG_EMPTY; + cpu_state.TOP++; return t; } @@ -171,13 +184,15 @@ static inline void x87_ld_frstor(int reg) cpu_state.MM[reg].q = readmemq(easeg, cpu_state.eaaddr); cpu_state.MM_w4[reg] = readmemw(easeg, cpu_state.eaaddr + 8); - if (cpu_state.MM_w4[reg] == 0x5555 && cpu_state.tag[reg] == 2) + if ((cpu_state.MM_w4[reg] == 0x5555) && (cpu_state.tag[reg] & TAG_UINT64)) { - cpu_state.tag[reg] = TAG_UINT64; cpu_state.ST[reg] = (double)cpu_state.MM[reg].q; } else + { + cpu_state.tag[reg] &= ~TAG_UINT64; cpu_state.ST[reg] = x87_ld80(); + } } static inline void x87_ldmmx(MMX_REG *r, uint16_t *w4) @@ -196,7 +211,7 @@ static inline void x87_stmmx(MMX_REG r) 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 +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 || defined __amd64__ uint32_t out; /* Memory barrier, to force GCC to write to the input parameters @@ -230,7 +245,7 @@ static inline uint16_t x87_compare(double a, double b) 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 +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 || defined __amd64__ uint32_t out; /* Memory barrier, to force GCC to write to the input parameters @@ -274,6 +289,9 @@ typedef union uint64_t i; } x87_td; +#ifdef X8087 +#define FP_ENTER() fpucount++ +#else #define FP_ENTER() do \ { \ if (cr0 & 0xc) \ @@ -283,6 +301,7 @@ typedef union } \ fpucount++; \ } while (0) +#endif #include "x87_ops_arith.h" #include "x87_ops_misc.h" @@ -622,7 +641,7 @@ OpFn OP_TABLE(fpu_db_a16)[256] = 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, + opFENI, opFDISI, 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, @@ -662,7 +681,7 @@ OpFn OP_TABLE(fpu_db_a32)[256] = 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, + opFENI, opFDISI, 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, diff --git a/src/x87_ops_arith.h b/src/x87_ops_arith.h index 6723bd1..cf8d1ae 100644 --- a/src/x87_ops_arith.h +++ b/src/x87_ops_arith.h @@ -1,17 +1,18 @@ -#define opFPU(name, optype, a_size, load_var, get, use_var) \ +#define opFPU(name, optype, a_size, load_var, get, use_var, cycle_postfix) \ static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ { \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ if ((cpu_state.npxc >> 10) & 3) \ fesetround(rounding_modes[(cpu_state.npxc >> 10) & 3]); \ ST(0) += use_var; \ if ((cpu_state.npxc >> 10) & 3) \ fesetround(FE_TONEAREST); \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ - CLOCK_CYCLES(8); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix); \ return 0; \ } \ static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -19,10 +20,11 @@ static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ cpu_state.npxs &= ~(C0|C2|C3); \ cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ - CLOCK_CYCLES(4); \ + CLOCK_CYCLES(x87_timings.fcom ## cycle_postfix); \ return 0; \ } \ static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -30,11 +32,12 @@ static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ cpu_state.npxs &= ~(C0|C2|C3); \ cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ x87_pop(); \ - CLOCK_CYCLES(4); \ + CLOCK_CYCLES(x87_timings.fcom ## cycle_postfix); \ return 0; \ } \ static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -42,10 +45,11 @@ static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ x87_div(ST(0), ST(0), use_var); \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ - CLOCK_CYCLES(73); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(x87_timings.fdiv ## cycle_postfix); \ return 0; \ } \ static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -53,10 +57,11 @@ static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ x87_div(ST(0), use_var, ST(0)); \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ - CLOCK_CYCLES(73); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(x87_timings.fdiv ## cycle_postfix); \ return 0; \ } \ static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -64,10 +69,11 @@ static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) *= use_var; \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ - CLOCK_CYCLES(11); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(x87_timings.fmul ## cycle_postfix); \ return 0; \ } \ static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -75,10 +81,11 @@ static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) -= use_var; \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ - CLOCK_CYCLES(8); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix); \ return 0; \ } \ static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ @@ -86,23 +93,24 @@ static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ optype t; \ FP_ENTER(); \ fetch_ea_ ## a_size(fetchdat); \ + SEG_CHECK_READ(cpu_state.ea_seg); \ load_var = get(); if (cpu_state.abrt) return 1; \ ST(0) = use_var - ST(0); \ - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ - CLOCK_CYCLES(8); \ + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; \ + CLOCK_CYCLES(x87_timings.fadd ## cycle_postfix); \ 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(s, x87_ts, 16, t.i, geteal, t.s, _32) +opFPU(s, x87_ts, 32, t.i, geteal, t.s, _32) +opFPU(d, x87_td, 16, t.i, geteaq, t.d, _64) +opFPU(d, x87_td, 32, t.i, geteaq, t.d, _64) -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) +opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t, _i16) +opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t, _i16) +opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t, _i32) +opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t, _i32) @@ -113,8 +121,8 @@ static int opFADD(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FADD\n"); ST(0) = ST(0) + ST(fetchdat & 7); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(8); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fadd); return 0; } static int opFADDr(uint32_t fetchdat) @@ -123,8 +131,8 @@ static int opFADDr(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FADD\n"); ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; - CLOCK_CYCLES(8); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fadd); return 0; } static int opFADDP(uint32_t fetchdat) @@ -133,9 +141,9 @@ static int opFADDP(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FADDP\n"); ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fadd); return 0; } @@ -147,7 +155,7 @@ static int opFCOM(uint32_t fetchdat) cpu_state.npxs &= ~(C0|C2|C3); if (ST(0) == ST(fetchdat & 7)) cpu_state.npxs |= C3; else if (ST(0) < ST(fetchdat & 7)) cpu_state.npxs |= C0; - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fadd); return 0; } @@ -159,7 +167,7 @@ static int opFCOMP(uint32_t fetchdat) cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7)); x87_pop(); - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fadd); return 0; } @@ -176,7 +184,7 @@ static int opFCOMPP(uint32_t fetchdat) x87_pop(); x87_pop(); - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fadd); return 0; } static int opFUCOMPP(uint32_t fetchdat) @@ -188,7 +196,7 @@ static int opFUCOMPP(uint32_t fetchdat) cpu_state.npxs |= x87_ucompare(ST(0), ST(1)); x87_pop(); x87_pop(); - CLOCK_CYCLES(5); + CLOCK_CYCLES(x87_timings.fucom); return 0; } @@ -198,10 +206,10 @@ static int opFCOMI(uint32_t fetchdat) 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); + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; + CLOCK_CYCLES(x87_timings.fcom); return 0; } static int opFCOMIP(uint32_t fetchdat) @@ -210,11 +218,11 @@ static int opFCOMIP(uint32_t fetchdat) 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; + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; x87_pop(); - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fcom); return 0; } @@ -224,8 +232,8 @@ static int opFDIV(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FDIV\n"); x87_div(ST(0), ST(0), ST(fetchdat & 7)); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(73); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fdiv); return 0; } static int opFDIVr(uint32_t fetchdat) @@ -234,8 +242,8 @@ static int opFDIVr(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FDIV\n"); x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; - CLOCK_CYCLES(73); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fdiv); return 0; } static int opFDIVP(uint32_t fetchdat) @@ -244,9 +252,9 @@ static int opFDIVP(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FDIVP\n"); x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(73); + CLOCK_CYCLES(x87_timings.fdiv); return 0; } @@ -256,8 +264,8 @@ static int opFDIVR(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FDIVR\n"); x87_div(ST(0), ST(fetchdat&7), ST(0)); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(73); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fdiv); return 0; } static int opFDIVRr(uint32_t fetchdat) @@ -266,8 +274,8 @@ static int opFDIVRr(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FDIVR\n"); x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; - CLOCK_CYCLES(73); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fdiv); return 0; } static int opFDIVRP(uint32_t fetchdat) @@ -276,9 +284,9 @@ static int opFDIVRP(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FDIVR\n"); x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(73); + CLOCK_CYCLES(x87_timings.fdiv); return 0; } @@ -288,8 +296,8 @@ static int opFMUL(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FMUL\n"); ST(0) = ST(0) * ST(fetchdat & 7); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(16); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fmul); return 0; } static int opFMULr(uint32_t fetchdat) @@ -298,8 +306,8 @@ static int opFMULr(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FMUL\n"); ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; - CLOCK_CYCLES(16); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fmul); return 0; } static int opFMULP(uint32_t fetchdat) @@ -308,9 +316,9 @@ static int opFMULP(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FMULP\n"); ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(16); + CLOCK_CYCLES(x87_timings.fmul); return 0; } @@ -320,8 +328,8 @@ static int opFSUB(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSUB\n"); ST(0) = ST(0) - ST(fetchdat & 7); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(8); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fadd); return 0; } static int opFSUBr(uint32_t fetchdat) @@ -330,8 +338,8 @@ static int opFSUBr(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSUB\n"); ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; - CLOCK_CYCLES(8); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fadd); return 0; } static int opFSUBP(uint32_t fetchdat) @@ -340,9 +348,9 @@ static int opFSUBP(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSUBP\n"); ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fadd); return 0; } @@ -352,8 +360,8 @@ static int opFSUBR(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSUBR\n"); ST(0) = ST(fetchdat & 7) - ST(0); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(8); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fadd); return 0; } static int opFSUBRr(uint32_t fetchdat) @@ -362,8 +370,8 @@ static int opFSUBRr(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSUBR\n"); ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; - CLOCK_CYCLES(8); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fadd); return 0; } static int opFSUBRP(uint32_t fetchdat) @@ -372,9 +380,9 @@ static int opFSUBRP(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSUBRP\n"); ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fadd); return 0; } @@ -385,7 +393,7 @@ static int opFUCOM(uint32_t fetchdat) if (fplog) pclog("FUCOM\n"); cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fucom); return 0; } @@ -397,7 +405,7 @@ static int opFUCOMP(uint32_t fetchdat) cpu_state.npxs &= ~(C0|C2|C3); cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); x87_pop(); - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fucom); return 0; } @@ -407,10 +415,10 @@ static int opFUCOMI(uint32_t fetchdat) 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); + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; + CLOCK_CYCLES(x87_timings.fucom); return 0; } static int opFUCOMIP(uint32_t fetchdat) @@ -419,10 +427,10 @@ static int opFUCOMIP(uint32_t fetchdat) 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; + cpu_state.flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) cpu_state.flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.flags |= C_FLAG; x87_pop(); - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fucom); return 0; } diff --git a/src/x87_ops_loadstore.h b/src/x87_ops_loadstore.h index 09bbf82..6c61b7f 100644 --- a/src/x87_ops_loadstore.h +++ b/src/x87_ops_loadstore.h @@ -3,11 +3,12 @@ static int opFILDiw_a16(uint32_t fetchdat) int16_t temp; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr); temp = geteaw(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f\n", (double)temp); x87_push((double)temp); - CLOCK_CYCLES(13); + CLOCK_CYCLES(x87_timings.fild_16); return 0; } static int opFILDiw_a32(uint32_t fetchdat) @@ -15,11 +16,12 @@ static int opFILDiw_a32(uint32_t fetchdat) int16_t temp; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr); temp = geteaw(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f\n", (double)temp); x87_push((double)temp); - CLOCK_CYCLES(13); + CLOCK_CYCLES(x87_timings.fild_16); return 0; } @@ -28,12 +30,13 @@ static int opFISTiw_a16(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); temp64 = x87_fround(ST(0)); /* if (temp64 > 32767 || temp64 < -32768) fatal("FISTw overflow %i\n", temp64);*/ seteaw((int16_t)temp64); - CLOCK_CYCLES(29); + CLOCK_CYCLES(x87_timings.fist_16); return cpu_state.abrt; } static int opFISTiw_a32(uint32_t fetchdat) @@ -41,12 +44,13 @@ static int opFISTiw_a32(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); temp64 = x87_fround(ST(0)); /* if (temp64 > 32767 || temp64 < -32768) fatal("FISTw overflow %i\n", temp64);*/ seteaw((int16_t)temp64); - CLOCK_CYCLES(29); + CLOCK_CYCLES(x87_timings.fist_16); return cpu_state.abrt; } @@ -55,13 +59,14 @@ static int opFISTPiw_a16(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); temp64 = x87_fround(ST(0)); /* if (temp64 > 32767 || temp64 < -32768) fatal("FISTw overflow %i\n", temp64);*/ seteaw((int16_t)temp64); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(29); + CLOCK_CYCLES(x87_timings.fist_16); return 0; } static int opFISTPiw_a32(uint32_t fetchdat) @@ -69,13 +74,14 @@ static int opFISTPiw_a32(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); temp64 = x87_fround(ST(0)); /* if (temp64 > 32767 || temp64 < -32768) fatal("FISTw overflow %i\n", temp64);*/ seteaw((int16_t)temp64); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(29); + CLOCK_CYCLES(x87_timings.fist_16); return 0; } @@ -84,14 +90,15 @@ static int opFILDiq_a16(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr); temp64 = geteaq(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,cpu_state.eaaddr), readmeml(easeg,cpu_state.eaaddr+4)); x87_push((double)temp64); - cpu_state.MM[cpu_state.TOP].q = temp64; - cpu_state.tag[cpu_state.TOP] |= TAG_UINT64; + cpu_state.MM[cpu_state.TOP&7].q = temp64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID | TAG_UINT64; - CLOCK_CYCLES(10); + CLOCK_CYCLES(x87_timings.fild_64); return 0; } static int opFILDiq_a32(uint32_t fetchdat) @@ -99,14 +106,15 @@ static int opFILDiq_a32(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr); temp64 = geteaq(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,cpu_state.eaaddr), readmeml(easeg,cpu_state.eaaddr+4)); x87_push((double)temp64); - cpu_state.MM[cpu_state.TOP].q = temp64; - cpu_state.tag[cpu_state.TOP] |= TAG_UINT64; + cpu_state.MM[cpu_state.TOP&7].q = temp64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID | TAG_UINT64; - CLOCK_CYCLES(10); + CLOCK_CYCLES(x87_timings.fild_64); return 0; } @@ -116,6 +124,7 @@ static int FBSTP_a16(uint32_t fetchdat) int c; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr); tempd = ST(0); if (tempd < 0.0) @@ -134,6 +143,7 @@ static int FBSTP_a16(uint32_t fetchdat) if (ST(0) < 0.0) tempc |= 0x80; writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; x87_pop(); + CLOCK_CYCLES(x87_timings.fbstp); return 0; } static int FBSTP_a32(uint32_t fetchdat) @@ -142,6 +152,7 @@ static int FBSTP_a32(uint32_t fetchdat) int c; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr); tempd = ST(0); if (tempd < 0.0) @@ -160,6 +171,7 @@ static int FBSTP_a32(uint32_t fetchdat) if (ST(0) < 0.0) tempc |= 0x80; writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; x87_pop(); + CLOCK_CYCLES(x87_timings.fbstp); return 0; } @@ -168,14 +180,15 @@ static int FISTPiq_a16(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr); - if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64) - temp64 = cpu_state.MM[cpu_state.TOP].q; + if (cpu_state.tag[cpu_state.TOP&7] & TAG_UINT64) + temp64 = cpu_state.MM[cpu_state.TOP&7].q; else temp64 = x87_fround(ST(0)); seteaq(temp64); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(29); + CLOCK_CYCLES(x87_timings.fist_64); return 0; } static int FISTPiq_a32(uint32_t fetchdat) @@ -183,14 +196,15 @@ static int FISTPiq_a32(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr); - if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64) - temp64 = cpu_state.MM[cpu_state.TOP].q; + if (cpu_state.tag[cpu_state.TOP&7] & TAG_UINT64) + temp64 = cpu_state.MM[cpu_state.TOP&7].q; else temp64 = x87_fround(ST(0)); seteaq(temp64); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(29); + CLOCK_CYCLES(x87_timings.fist_64); return 0; } @@ -199,11 +213,12 @@ static int opFILDil_a16(uint32_t fetchdat) int32_t templ; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr); templ = geteal(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ); x87_push((double)templ); - CLOCK_CYCLES(9); + CLOCK_CYCLES(x87_timings.fild_32); return 0; } static int opFILDil_a32(uint32_t fetchdat) @@ -211,11 +226,12 @@ static int opFILDil_a32(uint32_t fetchdat) int32_t templ; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr); templ = geteal(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ); x87_push((double)templ); - CLOCK_CYCLES(9); + CLOCK_CYCLES(x87_timings.fild_32); return 0; } @@ -224,12 +240,13 @@ static int opFISTil_a16(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.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); + CLOCK_CYCLES(x87_timings.fist_32); return cpu_state.abrt; } static int opFISTil_a32(uint32_t fetchdat) @@ -237,12 +254,13 @@ static int opFISTil_a32(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.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); + CLOCK_CYCLES(x87_timings.fist_32); return cpu_state.abrt; } @@ -251,13 +269,14 @@ static int opFISTPil_a16(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); temp64 = x87_fround(ST(0)); /* if (temp64 > 2147483647 || temp64 < -2147483647) fatal("FISTl out of range! %i\n", temp64);*/ seteal((int32_t)temp64); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(28); + CLOCK_CYCLES(x87_timings.fist_32); return 0; } static int opFISTPil_a32(uint32_t fetchdat) @@ -265,13 +284,14 @@ static int opFISTPil_a32(uint32_t fetchdat) int64_t temp64; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); temp64 = x87_fround(ST(0)); /* if (temp64 > 2147483647 || temp64 < -2147483647) fatal("FISTl out of range! %i\n", temp64);*/ seteal((int32_t)temp64); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(28); + CLOCK_CYCLES(x87_timings.fist_32); return 0; } @@ -280,11 +300,12 @@ static int opFLDe_a16(uint32_t fetchdat) double t; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr); t=x87_ld80(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f\n", t); x87_push(t); - CLOCK_CYCLES(6); + CLOCK_CYCLES(x87_timings.fld_80); return 0; } static int opFLDe_a32(uint32_t fetchdat) @@ -292,11 +313,12 @@ static int opFLDe_a32(uint32_t fetchdat) double t; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr); t=x87_ld80(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f\n", t); x87_push(t); - CLOCK_CYCLES(6); + CLOCK_CYCLES(x87_timings.fld_80); return 0; } @@ -304,20 +326,22 @@ static int opFSTPe_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr); x87_st80(ST(0)); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(6); + CLOCK_CYCLES(x87_timings.fst_80); return 0; } static int opFSTPe_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr); x87_st80(ST(0)); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(6); + CLOCK_CYCLES(x87_timings.fst_80); return 0; } @@ -326,11 +350,12 @@ static int opFLDd_a16(uint32_t fetchdat) x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr); t.i = geteaq(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f\n", t.d); x87_push(t.d); - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fld_64); return 0; } static int opFLDd_a32(uint32_t fetchdat) @@ -338,11 +363,12 @@ static int opFLDd_a32(uint32_t fetchdat) x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr); t.i = geteaq(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f\n", t.d); x87_push(t.d); - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fld_64); return 0; } @@ -351,10 +377,11 @@ static int opFSTd_a16(uint32_t fetchdat) x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); t.d = ST(0); seteaq(t.i); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fst_64); return cpu_state.abrt; } static int opFSTd_a32(uint32_t fetchdat) @@ -362,10 +389,11 @@ static int opFSTd_a32(uint32_t fetchdat) x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); t.d = ST(0); seteaq(t.i); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fst_64); return cpu_state.abrt; } @@ -374,12 +402,13 @@ static int opFSTPd_a16(uint32_t fetchdat) x87_td t; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); t.d = ST(0); seteaq(t.i); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fst_64); return 0; } static int opFSTPd_a32(uint32_t fetchdat) @@ -387,12 +416,13 @@ static int opFSTPd_a32(uint32_t fetchdat) x87_td t; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); t.d = ST(0); seteaq(t.i); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fst_64); return 0; } @@ -401,11 +431,12 @@ static int opFLDs_a16(uint32_t fetchdat) x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr); ts.i = geteal(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f\n", ts.s); x87_push((double)ts.s); - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fld_32); return 0; } static int opFLDs_a32(uint32_t fetchdat) @@ -413,11 +444,12 @@ static int opFLDs_a32(uint32_t fetchdat) x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr); ts.i = geteal(); if (cpu_state.abrt) return 1; if (fplog) pclog(" %f\n", ts.s); x87_push((double)ts.s); - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fld_32); return 0; } @@ -426,10 +458,11 @@ static int opFSTs_a16(uint32_t fetchdat) x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); ts.s = (float)ST(0); seteal(ts.i); - CLOCK_CYCLES(7); + CLOCK_CYCLES(x87_timings.fst_32); return cpu_state.abrt; } static int opFSTs_a32(uint32_t fetchdat) @@ -437,10 +470,11 @@ static int opFSTs_a32(uint32_t fetchdat) x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); ts.s = (float)ST(0); seteal(ts.i); - CLOCK_CYCLES(7); + CLOCK_CYCLES(x87_timings.fst_32); return cpu_state.abrt; } @@ -449,11 +483,12 @@ static int opFSTPs_a16(uint32_t fetchdat) x87_ts ts; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); ts.s = (float)ST(0); seteal(ts.i); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(7); + CLOCK_CYCLES(x87_timings.fst_32); return 0; } static int opFSTPs_a32(uint32_t fetchdat) @@ -461,10 +496,11 @@ static int opFSTPs_a32(uint32_t fetchdat) x87_ts ts; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); ts.s = (float)ST(0); seteal(ts.i); if (cpu_state.abrt) return 1; x87_pop(); - CLOCK_CYCLES(7); + CLOCK_CYCLES(x87_timings.fst_32); return 0; } diff --git a/src/x87_ops_misc.h b/src/x87_ops_misc.h index 806c4a6..8abb544 100644 --- a/src/x87_ops_misc.h +++ b/src/x87_ops_misc.h @@ -1,10 +1,37 @@ +static int opFDISI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fpu_type == FPU_8087) + { + cpu_state.npxc |= FPCW_DISI; + CLOCK_CYCLES(x87_timings.fdisi_eni); + } + else + CLOCK_CYCLES(x87_timings.fnop); + return 0; +} +static int opFENI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fpu_type == FPU_8087) + { + cpu_state.npxc &= ~FPCW_DISI; + CLOCK_CYCLES(x87_timings.fdisi_eni); + } + else + CLOCK_CYCLES(x87_timings.fnop); + return 0; +} + static int opFSTSW_AX(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; if (fplog) pclog("FSTSW\n"); AX = cpu_state.npxs; - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fstcw_sw); return 0; } @@ -14,7 +41,7 @@ static int opFNOP(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fnop); return 0; } @@ -23,7 +50,7 @@ static int opFCLEX(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; cpu_state.npxs &= 0xff00; - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fclex); return 0; } @@ -31,13 +58,17 @@ static int opFINIT(uint32_t fetchdat) { FP_ENTER(); cpu_state.pc++; - cpu_state.npxc = 0x37F; - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + if (fpu_type == FPU_8087) + cpu_state.npxc = 0x3ff; + else + cpu_state.npxc = 0x37f; + codegen_set_rounding_mode(X87_ROUNDING_NEAREST); cpu_state.npxs = 0; - *(uint64_t *)cpu_state.tag = 0x0303030303030303ll; + *(uint64_t *)cpu_state.tag = 0; cpu_state.TOP = 0; cpu_state.ismmx = 0; - CLOCK_CYCLES(17); + CLOCK_CYCLES(x87_timings.finit); + CPU_BLOCK_END(); return 0; } @@ -47,8 +78,8 @@ static int opFFREE(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; if (fplog) pclog("FFREE\n"); - cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; - CLOCK_CYCLES(3); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = TAG_EMPTY; + CLOCK_CYCLES(x87_timings.ffree); return 0; } @@ -59,7 +90,7 @@ static int opFST(uint32_t fetchdat) if (fplog) pclog("FST\n"); ST(fetchdat & 7) = ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fst); return 0; } @@ -71,7 +102,7 @@ static int opFSTP(uint32_t fetchdat) ST(fetchdat & 7) = ST(0); cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; x87_pop(); - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fst); return 0; } @@ -86,7 +117,7 @@ static int FSTOR() case 0x000: /*16-bit real mode*/ case 0x001: /*16-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -95,7 +126,7 @@ static int FSTOR() case 0x100: /*32-bit real mode*/ case 0x101: /*32-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -116,10 +147,10 @@ static int FSTOR() something like this is needed*/ if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && - !cpu_state.TOP && !(*(uint64_t *)cpu_state.tag)) - cpu_state.ismmx = 1; + !cpu_state.TOP && (*(uint64_t *)cpu_state.tag == 0x0101010101010101ull)) + cpu_state.ismmx = 1; - CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + CLOCK_CYCLES(x87_timings.frstor); if (fplog) pclog("FRSTOR %08X:%08X %i %i %04X\n", easeg, cpu_state.eaaddr, cpu_state.ismmx, cpu_state.TOP, x87_gettag()); return cpu_state.abrt; } @@ -127,6 +158,7 @@ static int opFSTOR_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); FSTOR(); return cpu_state.abrt; } @@ -134,6 +166,7 @@ static int opFSTOR_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); FSTOR(); return cpu_state.abrt; } @@ -142,7 +175,7 @@ static int FSAVE() { FP_ENTER(); if (fplog) pclog("FSAVE %08X:%08X %i\n", easeg, cpu_state.eaaddr, cpu_state.ismmx); - cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | (cpu_state.TOP << 11); + cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | ((cpu_state.TOP & 7) << 11); switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { @@ -274,19 +307,20 @@ static int FSAVE() } cpu_state.npxc = 0x37F; - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + codegen_set_rounding_mode(X87_ROUNDING_NEAREST); cpu_state.npxs = 0; - *(uint64_t *)cpu_state.tag = 0x0303030303030303ll; + *(uint64_t *)cpu_state.tag = 0; cpu_state.TOP = 0; cpu_state.ismmx = 0; - CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + CLOCK_CYCLES(x87_timings.fsave); return cpu_state.abrt; } static int opFSAVE_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); FSAVE(); return cpu_state.abrt; } @@ -294,6 +328,7 @@ static int opFSAVE_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); FSAVE(); return cpu_state.abrt; } @@ -302,18 +337,20 @@ static int opFSTSW_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr); - seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11)); - CLOCK_CYCLES(3); + seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11)); + CLOCK_CYCLES(x87_timings.fstcw_sw); return cpu_state.abrt; } static int opFSTSW_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr); - seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11)); - CLOCK_CYCLES(3); + seteaw((cpu_state.npxs & 0xC7FF) | ((cpu_state.TOP & 7) << 11)); + CLOCK_CYCLES(x87_timings.fstcw_sw); return cpu_state.abrt; } @@ -329,9 +366,9 @@ static int opFLD(uint32_t fetchdat) old_tag = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; old_i64 = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; x87_push(ST(fetchdat&7)); - cpu_state.tag[cpu_state.TOP] = old_tag; - cpu_state.MM[cpu_state.TOP].q = old_i64; - CLOCK_CYCLES(4); + cpu_state.tag[cpu_state.TOP&7] = old_tag; + cpu_state.MM[cpu_state.TOP&7].q = old_i64; + CLOCK_CYCLES(x87_timings.fld); return 0; } @@ -346,14 +383,14 @@ static int opFXCH(uint32_t fetchdat) td = ST(0); ST(0) = ST(fetchdat&7); ST(fetchdat&7) = td; - old_tag = cpu_state.tag[cpu_state.TOP]; - cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; + old_tag = cpu_state.tag[cpu_state.TOP&7]; + cpu_state.tag[cpu_state.TOP&7] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = old_tag; - old_i64 = cpu_state.MM[cpu_state.TOP].q; - cpu_state.MM[cpu_state.TOP].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; + old_i64 = cpu_state.MM[cpu_state.TOP&7].q; + cpu_state.MM[cpu_state.TOP&7].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q = old_i64; - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fxch); return 0; } @@ -363,8 +400,8 @@ static int opFCHS(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FCHS\n"); ST(0) = -ST(0); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(6); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fchs); return 0; } @@ -374,8 +411,8 @@ static int opFABS(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FABS %f\n", ST(0)); ST(0) = fabs(ST(0)); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(3); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fabs); return 0; } @@ -387,7 +424,7 @@ static int opFTST(uint32_t fetchdat) cpu_state.npxs &= ~(C0|C2|C3); if (ST(0) == 0.0) cpu_state.npxs |= C3; else if (ST(0) < 0.0) cpu_state.npxs |= C0; - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.ftst); return 0; } @@ -397,11 +434,11 @@ static int opFXAM(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FXAM %i %f\n", cpu_state.tag[cpu_state.TOP&7], ST(0)); cpu_state.npxs &= ~(C0|C1|C2|C3); - if (cpu_state.tag[cpu_state.TOP&7] == 3) cpu_state.npxs |= (C0|C3); + if (cpu_state.tag[cpu_state.TOP&7] == TAG_EMPTY) cpu_state.npxs |= (C0|C3); else if (ST(0) == 0.0) cpu_state.npxs |= C3; else cpu_state.npxs |= C2; if (ST(0) < 0.0) cpu_state.npxs |= C1; - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fxam); return 0; } @@ -411,7 +448,7 @@ static int opFLD1(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FLD1\n"); x87_push(1.0); - CLOCK_CYCLES(4); + CLOCK_CYCLES(x87_timings.fld_z1); return 0; } @@ -421,7 +458,7 @@ static int opFLDL2T(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FLDL2T\n"); x87_push(3.3219280948873623); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fld_const); return 0; } @@ -431,7 +468,7 @@ static int opFLDL2E(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FLDL2E\n"); x87_push(1.4426950408889634); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fld_const); return 0; } @@ -441,7 +478,7 @@ static int opFLDPI(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FLDPI\n"); x87_push(3.141592653589793); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fld_const); return 0; } @@ -451,7 +488,7 @@ static int opFLDEG2(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FLDEG2\n"); x87_push(0.3010299956639812); - CLOCK_CYCLES(8); + CLOCK_CYCLES(x87_timings.fld_const); return 0; } @@ -460,8 +497,8 @@ static int opFLDLN2(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; if (fplog) pclog("FLDLN2\n"); - x87_push(0.693147180559945); - CLOCK_CYCLES(8); + x87_push_u64(0x3fe62e42fefa39f0ull); + CLOCK_CYCLES(x87_timings.fld_const); return 0; } @@ -471,8 +508,8 @@ static int opFLDZ(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FLDZ\n"); x87_push(0.0); - cpu_state.tag[cpu_state.TOP&7] = 1; - CLOCK_CYCLES(4); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fld_z1); return 0; } @@ -482,8 +519,8 @@ static int opF2XM1(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("F2XM1\n"); ST(0) = pow(2.0, ST(0)) - 1.0; - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(200); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.f2xm1); return 0; } @@ -493,9 +530,9 @@ static int opFYL2X(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FYL2X\n"); ST(1) = ST(1) * (log(ST(0)) / log(2.0)); - cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(250); + CLOCK_CYCLES(x87_timings.fyl2x); return 0; } @@ -505,9 +542,9 @@ static int opFYL2XP1(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FYL2XP1\n"); ST(1) = ST(1) * (log(ST(0)+1.0) / log(2.0)); - cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(250); + CLOCK_CYCLES(x87_timings.fyl2xp1); return 0; } @@ -517,10 +554,10 @@ static int opFPTAN(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FPTAN\n"); ST(0) = tan(ST(0)); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; x87_push(1.0); cpu_state.npxs &= ~C2; - CLOCK_CYCLES(235); + CLOCK_CYCLES(x87_timings.fptan); return 0; } @@ -530,9 +567,9 @@ static int opFPATAN(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FPATAN\n"); ST(1) = atan2(ST(1), ST(0)); - cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; + cpu_state.tag[(cpu_state.TOP + 1) & 7] = TAG_VALID; x87_pop(); - CLOCK_CYCLES(250); + CLOCK_CYCLES(x87_timings.fpatan); return 0; } @@ -541,8 +578,8 @@ static int opFDECSTP(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; if (fplog) pclog("FDECSTP\n"); - cpu_state.TOP = (cpu_state.TOP - 1) & 7; - CLOCK_CYCLES(4); + cpu_state.TOP--; + CLOCK_CYCLES(x87_timings.fincdecstp); return 0; } @@ -551,8 +588,8 @@ static int opFINCSTP(uint32_t fetchdat) FP_ENTER(); cpu_state.pc++; if (fplog) pclog("FDECSTP\n"); - cpu_state.TOP = (cpu_state.TOP + 1) & 7; - CLOCK_CYCLES(4); + cpu_state.TOP++; + CLOCK_CYCLES(x87_timings.fincdecstp); return 0; } @@ -564,13 +601,13 @@ static int opFPREM(uint32_t fetchdat) 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); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; if (fplog) pclog("%f\n", ST(0)); cpu_state.npxs &= ~(C0|C1|C2|C3); if (temp64 & 4) cpu_state.npxs|=C0; if (temp64 & 2) cpu_state.npxs|=C3; if (temp64 & 1) cpu_state.npxs|=C1; - CLOCK_CYCLES(100); + CLOCK_CYCLES(x87_timings.fprem); return 0; } static int opFPREM1(uint32_t fetchdat) @@ -581,13 +618,13 @@ static int opFPREM1(uint32_t fetchdat) 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); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; if (fplog) pclog("%f\n", ST(0)); cpu_state.npxs &= ~(C0|C1|C2|C3); if (temp64 & 4) cpu_state.npxs|=C0; if (temp64 & 2) cpu_state.npxs|=C3; if (temp64 & 1) cpu_state.npxs|=C1; - CLOCK_CYCLES(100); + CLOCK_CYCLES(x87_timings.fprem1); return 0; } @@ -597,8 +634,8 @@ static int opFSQRT(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSQRT\n"); ST(0) = sqrt(ST(0)); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(83); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fsqrt); return 0; } @@ -610,10 +647,10 @@ static int opFSINCOS(uint32_t fetchdat) if (fplog) pclog("FSINCOS\n"); td = ST(0); ST(0) = sin(td); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; x87_push(cos(td)); cpu_state.npxs &= ~C2; - CLOCK_CYCLES(330); + CLOCK_CYCLES(x87_timings.fsincos); return 0; } @@ -623,9 +660,9 @@ static int opFRNDINT(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FRNDINT %g ", ST(0)); ST(0) = (double)x87_fround(ST(0)); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; if (fplog) pclog("%g\n", ST(0)); - CLOCK_CYCLES(21); + CLOCK_CYCLES(x87_timings.frndint); return 0; } @@ -636,9 +673,10 @@ static int opFSCALE(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSCALE\n"); temp64 = (int64_t)ST(1); - ST(0) = ST(0) * pow(2.0, (double)temp64); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; - CLOCK_CYCLES(30); + if (ST(0) != 0.0) + ST(0) = ST(0) * pow(2.0, (double)temp64); + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; + CLOCK_CYCLES(x87_timings.fscale); return 0; } @@ -648,9 +686,9 @@ static int opFSIN(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FSIN\n"); ST(0) = sin(ST(0)); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; cpu_state.npxs &= ~C2; - CLOCK_CYCLES(300); + CLOCK_CYCLES(x87_timings.fsin_cos); return 0; } @@ -660,9 +698,9 @@ static int opFCOS(uint32_t fetchdat) cpu_state.pc++; if (fplog) pclog("FCOS\n"); ST(0) = cos(ST(0)); - cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.tag[cpu_state.TOP&7] = TAG_VALID; cpu_state.npxs &= ~C2; - CLOCK_CYCLES(300); + CLOCK_CYCLES(x87_timings.fsin_cos); return 0; } @@ -676,7 +714,7 @@ static int FLDENV() case 0x000: /*16-bit real mode*/ case 0x001: /*16-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; @@ -684,13 +722,13 @@ static int FLDENV() case 0x100: /*32-bit real mode*/ case 0x101: /*32-bit protected mode*/ cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); cpu_state.TOP = (cpu_state.npxs >> 11) & 7; break; } - CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + CLOCK_CYCLES(x87_timings.fldenv); return cpu_state.abrt; } @@ -698,6 +736,7 @@ static int opFLDENV_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); FLDENV(); return cpu_state.abrt; } @@ -705,6 +744,7 @@ static int opFLDENV_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); FLDENV(); return cpu_state.abrt; } @@ -714,12 +754,13 @@ static int opFLDCW_a16(uint32_t fetchdat) uint16_t tempw; FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr); tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); - CLOCK_CYCLES(4); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + CLOCK_CYCLES(x87_timings.fldcw); return 0; } static int opFLDCW_a32(uint32_t fetchdat) @@ -727,12 +768,13 @@ static int opFLDCW_a32(uint32_t fetchdat) uint16_t tempw; FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_READ(cpu_state.ea_seg); if (fplog) pclog("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr); tempw = geteaw(); if (cpu_state.abrt) return 1; cpu_state.npxc = tempw; - cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); - CLOCK_CYCLES(4); + codegen_set_rounding_mode((cpu_state.npxc >> 10) & 3); + CLOCK_CYCLES(x87_timings.fldcw); return 0; } @@ -740,6 +782,8 @@ static int FSTENV() { FP_ENTER(); if (fplog) pclog("FSTENV %08X:%08X\n", easeg, cpu_state.eaaddr); + cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | ((cpu_state.TOP & 7) << 11); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) { case 0x000: /*16-bit real mode*/ @@ -776,7 +820,7 @@ static int FSTENV() writememl(easeg,cpu_state.eaaddr+24,x87_op_seg); break; } - CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + CLOCK_CYCLES(x87_timings.fstenv); return cpu_state.abrt; } @@ -784,6 +828,7 @@ static int opFSTENV_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); FSTENV(); return cpu_state.abrt; } @@ -791,6 +836,7 @@ static int opFSTENV_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); FSTENV(); return cpu_state.abrt; } @@ -799,18 +845,20 @@ static int opFSTCW_a16(uint32_t fetchdat) { FP_ENTER(); fetch_ea_16(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr); seteaw(cpu_state.npxc); - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fstcw_sw); return cpu_state.abrt; } static int opFSTCW_a32(uint32_t fetchdat) { FP_ENTER(); fetch_ea_32(fetchdat); + SEG_CHECK_WRITE(cpu_state.ea_seg); if (fplog) pclog("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr); seteaw(cpu_state.npxc); - CLOCK_CYCLES(3); + CLOCK_CYCLES(x87_timings.fstcw_sw); return cpu_state.abrt; } @@ -822,8 +870,8 @@ static int opFSTCW_a32(uint32_t fetchdat) if (fplog) pclog("FCMOV %f\n", ST(fetchdat & 7)); \ if (cond_ ## condition) \ { \ - cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; \ - cpu_state.MM[cpu_state.TOP].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; \ + cpu_state.tag[cpu_state.TOP&7] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; \ + cpu_state.MM[cpu_state.TOP&7].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; \ ST(0) = ST(fetchdat & 7); \ } \ CLOCK_CYCLES(4); \ diff --git a/src/x87_timings.c b/src/x87_timings.c new file mode 100644 index 0000000..757f05c --- /dev/null +++ b/src/x87_timings.c @@ -0,0 +1,309 @@ +#include "ibm.h" +#include "x87_timings.h" + +x87_timings_t x87_timings; + +const x87_timings_t x87_timings_8087 = +{ + .f2xm1 = (310 + 630) / 2, + .fabs = (10 + 17) / 2, + .fadd = (70 + 100) / 2, + .fadd_32 = (90 + 120) / 2, + .fadd_64 = (95 + 125) / 2, + .fbld = (290 + 310) / 2, + .fbstp = (520 + 540) / 2, + .fchs = (10 + 17) / 2, + .fclex = (2 + 8) / 2, + .fcom = (40 + 50) / 2, + .fcom_32 = (60 + 70) / 2, + .fcom_64 = (65 + 75) / 2, + .fcos = 0, /*387+*/ + .fincdecstp = (6 + 12) / 2, + .fdisi_eni = (6 + 12) / 2, + .fdiv = (193 + 203) / 2, + .fdiv_32 = (215 + 225) / 2, + .fdiv_64 = (220 + 230) / 2, + .ffree = (9 + 16) / 2, + .fadd_i16 = (102 + 137) / 2, + .fadd_i32 = (108 + 143) / 2, + .fcom_i16 = (72 + 86) / 2, + .fcom_i32 = (78 + 91) / 2, + .fdiv_i16 = (224 + 238) / 2, + .fdiv_i32 = (230 + 243) / 2, + .fild_16 = (46 + 54) / 2, + .fild_32 = (50 + 60) / 2, + .fild_64 = (60 + 68) / 2, + .fmul_i16 = (124 + 138) / 2, + .fmul_i32 = (130 + 144) / 2, + .finit = (2 + 8) / 2, + .fist_16 = (80 + 90) / 2, + .fist_32 = (82 + 92) / 2, + .fist_64 = (94 + 105) / 2, + .fld = (17 + 22) / 2, + .fld_32 = (38 + 56) / 2, + .fld_64 = (40 + 60) / 2, + .fld_80 = (53 + 65) / 2, + .fld_z1 = (11 + 21) / 2, + .fld_const = (15 + 24) / 2, + .fldcw = (7 + 14) / 2, + .fldenv = (35 + 45) / 2, + .fmul = (90 + 145) / 2, + .fmul_32 = (110 + 125) / 2, + .fmul_64 = (154 + 168) / 2, + .fnop = (10 + 16) / 2, + .fpatan = (250 + 800) / 2, + .fprem = (15 + 190) / 2, + .fprem1 = 0, /*387+*/ + .fptan = (30 + 540) / 2, + .frndint = (16 + 50) / 2, + .frstor = (197 + 207) / 2, + .fsave = (197 + 207) / 2, + .fscale = (32 + 38) / 2, + .fsetpm = 0, /*287+*/ + .fsin_cos = 0, /*387+*/ + .fsincos = 0, /*387+*/ + .fsqrt = (180 + 186) / 2, + .fst = (15 + 22) / 2, + .fst_32 = (84 + 90) / 2, + .fst_64 = (96 + 104) / 2, + .fst_80 = (52 + 58) / 2, + .fstcw_sw = (12 + 18) / 2, + .fstenv = (40 + 50) / 2, + .ftst = (38 + 48) / 2, + .fucom = 0, /*387+*/ + .fwait = 4, + .fxam = (12 + 23) / 2, + .fxch = (10 + 15) / 2, + .fxtract = (27 + 55) / 2, + .fyl2x = (900 + 1100) / 2, + .fyl2xp1 = (700 + 1000) / 2 +}; + +/*Mostly the same as 8087*/ +const x87_timings_t x87_timings_287 = +{ + .f2xm1 = (310 + 630) / 2, + .fabs = (10 + 17) / 2, + .fadd = (70 + 100) / 2, + .fadd_32 = (90 + 120) / 2, + .fadd_64 = (95 + 125) / 2, + .fbld = (290 + 310) / 2, + .fbstp = (520 + 540) / 2, + .fchs = (10 + 17) / 2, + .fclex = (2 + 8) / 2, + .fcom = (40 + 50) / 2, + .fcom_32 = (60 + 70) / 2, + .fcom_64 = (65 + 75) / 2, + .fcos = 0, /*387+*/ + .fincdecstp = (6 + 12) / 2, + .fdisi_eni = 2, + .fdiv = (193 + 203) / 2, + .fdiv_32 = (215 + 225) / 2, + .fdiv_64 = (220 + 230) / 2, + .ffree = (9 + 16) / 2, + .fadd_i16 = (102 + 137) / 2, + .fadd_i32 = (108 + 143) / 2, + .fcom_i16 = (72 + 86) / 2, + .fcom_i32 = (78 + 91) / 2, + .fdiv_i16 = (224 + 238) / 2, + .fdiv_i32 = (230 + 243) / 2, + .fild_16 = (46 + 54) / 2, + .fild_32 = (50 + 60) / 2, + .fild_64 = (60 + 68) / 2, + .fmul_i16 = (124 + 138) / 2, + .fmul_i32 = (130 + 144) / 2, + .finit = (2 + 8) / 2, + .fist_16 = (80 + 90) / 2, + .fist_32 = (82 + 92) / 2, + .fist_64 = (94 + 105) / 2, + .fld = (17 + 22) / 2, + .fld_32 = (38 + 56) / 2, + .fld_64 = (40 + 60) / 2, + .fld_80 = (53 + 65) / 2, + .fld_z1 = (11 + 21) / 2, + .fld_const = (15 + 24) / 2, + .fldcw = (7 + 14) / 2, + .fldenv = (35 + 45) / 2, + .fmul = (90 + 145) / 2, + .fmul_32 = (110 + 125) / 2, + .fmul_64 = (154 + 168) / 2, + .fnop = (10 + 16) / 2, + .fpatan = (250 + 800) / 2, + .fprem = (15 + 190) / 2, + .fprem1 = 0, /*387+*/ + .fptan = (30 + 540) / 2, + .frndint = (16 + 50) / 2, + .frstor = (197 + 207) / 2, + .fsave = (197 + 207) / 2, + .fscale = (32 + 38) / 2, + .fsetpm = (2 + 8) / 2, /*287+*/ + .fsin_cos = 0, /*387+*/ + .fsincos = 0, /*387+*/ + .fsqrt = (180 + 186) / 2, + .fst = (15 + 22) / 2, + .fst_32 = (84 + 90) / 2, + .fst_64 = (96 + 104) / 2, + .fst_80 = (52 + 58) / 2, + .fstcw_sw = (12 + 18) / 2, + .fstenv = (40 + 50) / 2, + .ftst = (38 + 48) / 2, + .fucom = 0, /*387+*/ + .fwait = 3, + .fxam = (12 + 23) / 2, + .fxch = (10 + 15) / 2, + .fxtract = (27 + 55) / 2, + .fyl2x = (900 + 1100) / 2, + .fyl2xp1 = (700 + 1000) / 2 +}; + +const x87_timings_t x87_timings_387 = +{ + .f2xm1 = (211 + 476) / 2, + .fabs = 22, + .fadd = (23 + 34) / 2, + .fadd_32 = (24 + 32) / 2, + .fadd_64 = (29 + 37) / 2, + .fbld = (266 + 275) / 2, + .fbstp = (512 + 534) / 2, + .fchs = (24 + 25) / 2, + .fclex = 11, + .fcom = 24, + .fcom_32 = 26, + .fcom_64 = 31, + .fcos = (122 + 772) / 2, + .fincdecstp = 22, + .fdisi_eni = 2, + .fdiv = (88 + 91) / 2, + .fdiv_32 = 89, + .fdiv_64 = 94, + .ffree = 18, + .fadd_i16 = (71 + 85) / 2, + .fadd_i32 = (57 + 72) / 2, + .fcom_i16 = (71 + 75) / 2, + .fcom_i32 = (56 + 63) / 2, + .fdiv_i16 = (136 + 140) / 2, + .fdiv_i32 = (120 + 127) / 2, + .fild_16 = (61 + 65) / 2, + .fild_32 = (45 + 52) / 2, + .fild_64 = (56 + 67) / 2, + .fmul_i16 = (76 + 87) / 2, + .fmul_i32 = (61 + 82) / 2, + .finit = 33, + .fist_16 = (82 + 95) / 2, + .fist_32 = (79 + 93) / 2, + .fist_64 = (80 + 97) / 2, + .fld = 14, + .fld_32 = 20, + .fld_64 = 25, + .fld_80 = 44, + .fld_z1 = (20 + 24) / 2, + .fld_const = 40, + .fldcw = 19, + .fldenv = 71, + .fmul = (29 + 57) / 2, + .fmul_32 = (27 + 35) / 2, + .fmul_64 = (32 + 57) / 2, + .fnop = 12, + .fpatan = (314 + 487) / 2, + .fprem = (74 + 155) / 2, + .fprem1 = (95 + 185) / 2, + .fptan = (191 + 497) / 2, + .frndint = (66 + 80) / 2, + .frstor = 308, + .fsave = 375, + .fscale = (67 + 86) / 2, + .fsetpm = 12, + .fsin_cos = (122 + 771) / 2, + .fsincos = (194 + 809) / 2, + .fsqrt = (122 + 129) / 2, + .fst = 11, + .fst_32 = 44, + .fst_64 = 45, + .fst_80 = 53, + .fstcw_sw = 15, + .fstenv = 103, + .ftst = 28, + .fucom = 24, + .fwait = 6, + .fxam = (30 + 38) / 2, + .fxch = 18, + .fxtract = (70 + 76) / 2, + .fyl2x = (120 + 538) / 2, + .fyl2xp1 = (257 + 547) / 2 +}; + +const x87_timings_t x87_timings_486 = +{ + .f2xm1 = (140 + 270) / 2, + .fabs = 3, + .fadd = (8 + 20) / 2, + .fadd_32 = (8 + 20) / 2, + .fadd_64 = (8 + 20) / 2, + .fbld = (70 + 103) / 2, + .fbstp = (172 + 176) / 2, + .fchs = 6, + .fclex = 7, + .fcom = 4, + .fcom_32 = 4, + .fcom_64 = 4, + .fcos = (257 + 354) / 2, + .fincdecstp = 3, + .fdisi_eni = 3, + .fdiv = 73, + .fdiv_32 = 73, + .fdiv_64 = 73, + .ffree = 3, + .fadd_i16 = (20 + 35) / 2, + .fadd_i32 = (19 + 32) / 2, + .fcom_i16 = (16 + 20) / 2, + .fcom_i32 = (15 + 17) / 2, + .fdiv_i16 = (85 + 89) / 2, + .fdiv_i32 = (84 + 86) / 2, + .fild_16 = (13 + 16) / 2, + .fild_32 = (9 + 12) / 2, + .fild_64 = (10 + 18) / 2, + .fmul_i16 = (23 + 27) / 2, + .fmul_i32 = (22 + 24) / 2, + .finit = 17, + .fist_16 = (29 + 34) / 2, + .fist_32 = (28 + 34) / 2, + .fist_64 = (29 + 34) / 2, + .fld = 4, + .fld_32 = 3, + .fld_64 = 3, + .fld_80 = 6, + .fld_z1 = 4, + .fld_const = 8, + .fldcw = 4, + .fldenv = 34, + .fmul = 16, + .fmul_32 = 11, + .fmul_64 = 14, + .fnop = 3, + .fpatan = (218 + 303) / 2, + .fprem = (70 + 138) / 2, + .fprem1 = (72 + 167) / 2, + .fptan = (200 + 273) / 2, + .frndint = (21 + 30) / 2, + .frstor = 120, + .fsave = 143, + .fscale = (30 + 32) / 2, + .fsetpm = 3, + .fsin_cos = (257 + 354) / 2, + .fsincos = (292 + 365) / 2, + .fsqrt = (83 + 87) / 2, + .fst = 3, + .fst_32 = 7, + .fst_64 = 8, + .fst_80 = 6, + .fstcw_sw = 3, + .fstenv = 56, + .ftst = 4, + .fucom = 4, + .fwait = (1 + 3) / 2, + .fxam = 8, + .fxch = 4, + .fxtract = (16 + 20) / 2, + .fyl2x = (196 + 329) / 2, + .fyl2xp1 = (171 + 326) / 2 +}; diff --git a/src/x87_timings.h b/src/x87_timings.h new file mode 100644 index 0000000..14ab7dd --- /dev/null +++ b/src/x87_timings.h @@ -0,0 +1,56 @@ +typedef struct +{ + int f2xm1; + int fabs; + int fadd, fadd_32, fadd_64; + int fbld; + int fbstp; + int fchs; + int fclex; + int fcom, fcom_32, fcom_64; + int fcos; + int fincdecstp; + int fdisi_eni; + int fdiv, fdiv_32, fdiv_64; + int ffree; + int fadd_i16, fadd_i32; + int fcom_i16, fcom_i32; + int fdiv_i16, fdiv_i32; + int fild_16, fild_32, fild_64; + int fmul_i16, fmul_i32; + int finit; + int fist_16, fist_32, fist_64; + int fld, fld_32, fld_64, fld_80; + int fld_z1, fld_const; + int fldcw; + int fldenv; + int fmul, fmul_32, fmul_64; + int fnop; + int fpatan; + int fprem, fprem1; + int fptan; + int frndint; + int frstor; + int fsave; + int fscale; + int fsetpm; + int fsin_cos, fsincos; + int fsqrt; + int fst, fst_32, fst_64, fst_80; + int fstcw_sw; + int fstenv; + int ftst; + int fucom; + int fwait; + int fxam; + int fxch; + int fxtract; + int fyl2x, fyl2xp1; +} x87_timings_t; + +extern const x87_timings_t x87_timings_8087; +extern const x87_timings_t x87_timings_287; +extern const x87_timings_t x87_timings_387; +extern const x87_timings_t x87_timings_486; + +extern x87_timings_t x87_timings; diff --git a/src/xi8088.c b/src/xi8088.c new file mode 100644 index 0000000..1c5a135 --- /dev/null +++ b/src/xi8088.c @@ -0,0 +1,144 @@ +#include "ibm.h" +#include "io.h" +#include "cpu.h" +#include "keyboard_at.h" + +#include "xi8088.h" + +typedef struct xi8088_t +{ + uint8_t turbo; + + int turbo_setting; + int bios_128kb; +} xi8088_t; + +static xi8088_t xi8088; + +uint8_t xi8088_turbo_get() +{ + return xi8088.turbo; +} + +void xi8088_turbo_set(uint8_t value) +{ + if (!xi8088.turbo_setting) + return; + + xi8088.turbo = value; + if (!value) + { +// pclog("Xi8088 turbo off\n"); + cpu_set_turbo(0); + } + else + { +// pclog("Xi8088 turbo on\n"); + cpu_set_turbo(1); + } +} + +int xi8088_bios_128kb() +{ + return xi8088.bios_128kb; +} + +static void *xi8088_init() +{ + xi8088.turbo = 1; + xi8088.turbo_setting = device_get_config_int("turbo_setting"); + xi8088.bios_128kb = device_get_config_int("bios_128kb"); + + return &xi8088; +} + +static device_config_t xi8088_config[] = +{ + { + .name = "turbo_setting", + .description = "Turbo", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Always at selected speed", + .value = 0 + }, + { + .description = "BIOS setting + Hotkeys (off during POST)", + .value = 1 + } + }, + .default_int = 0 + }, + { + .name = "bios_128kb", + .description = "BIOS size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "64KB starting from 0xF0000", + .value = 0 + }, + { + .description = "128KB starting from 0xE0000 (address MSB inverted, last 64KB first)", + .value = 1 + } + }, + .default_int = 1 + }, + { + .name = "umb_c0000h_c7fff", + .description = "Map 0xc0000-0xc7fff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_c8000h_cffff", + .description = "Map 0xc8000-0xcffff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_d0000h_d7fff", + .description = "Map 0xd0000-0xd7fff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_d8000h_dffff", + .description = "Map 0xd8000-0xdffff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_e0000h_e7fff", + .description = "Map 0xe0000-0xe7fff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "umb_e8000h_effff", + .description = "Map 0xe8000-0xeffff as UMB", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .type = -1 + } +}; + + +device_t xi8088_device = +{ + "Xi8088", + 0, + xi8088_init, + NULL, + NULL, + NULL, + NULL, + NULL, + xi8088_config +}; diff --git a/src/xi8088.h b/src/xi8088.h new file mode 100644 index 0000000..54178da --- /dev/null +++ b/src/xi8088.h @@ -0,0 +1,7 @@ +#include "device.h" + +extern device_t xi8088_device; + +uint8_t xi8088_turbo_get(); +void xi8088_turbo_set(uint8_t value); +int xi8088_bios_128kb(); diff --git a/src/xtide.c b/src/xtide.c index 15954ab..22058f5 100644 --- a/src/xtide.c +++ b/src/xtide.c @@ -70,8 +70,8 @@ static void *xtide_init() xtide_t *xtide = malloc(sizeof(xtide_t)); memset(xtide, 0, sizeof(xtide_t)); - rom_init(&xtide->bios_rom, "roms/ide_xt.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - ide_init(); + rom_init(&xtide->bios_rom, "ide_xt.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + device_add(&ide_device); ide_pri_disable(); ide_sec_disable(); io_sethandler(0x0300, 0x0010, xtide_read, NULL, NULL, xtide_write, NULL, NULL, xtide); @@ -84,8 +84,19 @@ static void *xtide_at_init() xtide_t *xtide = malloc(sizeof(xtide_t)); memset(xtide, 0, sizeof(xtide_t)); - rom_init(&xtide->bios_rom, "roms/ide_at.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); - ide_init(); + rom_init(&xtide->bios_rom, "ide_at.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + device_add(&ide_device); + + return xtide; +} + +static void *xtide_ps1_init() +{ + xtide_t *xtide = malloc(sizeof(xtide_t)); + memset(xtide, 0, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, "ide_at_1_1_5.bin", 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + device_add(&ide_device); return xtide; } @@ -99,12 +110,17 @@ static void xtide_close(void *p) static int xtide_available() { - return rom_present("roms/ide_xt.bin"); + return rom_present("ide_xt.bin"); } static int xtide_at_available() { - return rom_present("roms/ide_at.bin"); + return rom_present("ide_at.bin"); +} + +static int xtide_ps1_available() +{ + return rom_present("ide_at_1_1_5.bin"); } device_t xtide_device = @@ -131,3 +147,15 @@ device_t xtide_at_device = NULL, NULL }; +device_t xtide_ps1_device = +{ + "XTIDE (PS/1)", + DEVICE_PS1, + xtide_ps1_init, + xtide_close, + xtide_ps1_available, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/xtide.h b/src/xtide.h index 739c987..798c03c 100644 --- a/src/xtide.h +++ b/src/xtide.h @@ -1,2 +1,3 @@ extern device_t xtide_device; extern device_t xtide_at_device; +extern device_t xtide_ps1_device; diff --git a/src/zenith.c b/src/zenith.c new file mode 100644 index 0000000..f7f361b --- /dev/null +++ b/src/zenith.c @@ -0,0 +1,50 @@ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "zenith.h" + +static uint8_t *zenith_scratchpad_ram; +static mem_mapping_t zenith_scratchpad_mapping; + +static uint8_t zenith_scratchpad_read(uint32_t addr, void *p) +{ + return zenith_scratchpad_ram[addr & 0x3fff]; +} +static void zenith_scratchpad_write(uint32_t addr, uint8_t val, void *p) +{ + zenith_scratchpad_ram[addr & 0x3fff] = val; +} + +static void *zenith_scratchpad_init() +{ + zenith_scratchpad_ram = malloc(0x4000); + + mem_mapping_disable(&bios_mapping[4]); + mem_mapping_disable(&bios_mapping[5]); + + mem_mapping_add(&zenith_scratchpad_mapping, 0xf0000, 0x4000, + zenith_scratchpad_read, NULL, NULL, + zenith_scratchpad_write, NULL, NULL, + zenith_scratchpad_ram, MEM_MAPPING_EXTERNAL, NULL); + + return zenith_scratchpad_ram; +} + +static void zenith_scratchpad_close(void *p) +{ + free(p); +} + +device_t zenith_scratchpad_device = +{ + "Zenith scratchpad RAM", + 0, + zenith_scratchpad_init, + zenith_scratchpad_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/zenith.h b/src/zenith.h new file mode 100644 index 0000000..0e58f45 --- /dev/null +++ b/src/zenith.h @@ -0,0 +1 @@ +device_t zenith_scratchpad_device; diff --git a/tested.html b/tested.html new file mode 100644 index 0000000..0480f1d --- /dev/null +++ b/tested.html @@ -0,0 +1,493 @@ + + + + + + + tested + + + + +

Software tested (v17):

+

DOS

+
    +
  • PC-DOS 1.0
  • +
  • MS-DOS 2.11
  • +
  • MS-DOS 3.30
  • +
  • MS-DOS 4.01
  • +
  • MS-DOS 5.0
  • +
  • MS-DOS 6.0
  • +
  • MS-DOS 6.22
  • +
+

Windows

+
    +
  • Windows 1.04
  • +
  • Windows/286 2.11
  • +
  • Windows/386 2.11
  • +
  • Windows 3.0
  • +
  • Windows 3.1
  • +
  • Windows for Workgroups 3.11
  • +
  • Windows 95
  • +
  • Windows 95 OSR2
  • +
  • Windows 98SE
  • +
  • Windows ME
  • +
+

Windows NT

+
    +
  • Windows NT 3.1
  • +
  • Windows NT 3.51
  • +
  • Windows NT 4 Workstation (SP6a)
  • +
  • Windows 2000
  • +
  • Windows XP
  • +
+

OS/2

+
    +
  • OS/2 v1.0
  • +
  • OS/2 v1.1
  • +
  • OS/2 v1.2
  • +
  • OS/2 v1.3
  • +
  • OS/2 v2.1
  • +
  • OS/2 Warp 3
  • +
  • OS/2 Warp 4
  • +
+

Linux

+
    +
  • Corel Linux 1.2
  • +
  • Mandriva LE 2005
  • +
  • Red Hat Linux 7.1 (Seawolf)
  • +
+

BeOS

+
    +
  • BeOS 5.0 Professional Edition
  • +
+

Applications

+
    +
  • 3DMark 2000
  • +
  • 3DMark 2001SE
  • +
  • After Dark 3.06
  • +
  • Cinemania 1994
  • +
  • Creative Writer
  • +
  • Cubasis
  • +
  • Encarta 1994
  • +
  • Fasttracker v2.08
  • +
  • PageMaker 5.0
  • +
  • PC Paintbrush 1.05
  • +
  • Photoshop 3.0
  • +
  • Smartsuite 97
  • +
  • Visual Basic 3.0
  • +
  • Visual C++ 6.0
  • +
  • Word for Windows 2.0
  • +
  • Winzip 6.2
  • +
+

Games

+
    +
  • 1602 AD (demo)
  • +
  • 3D Ultra Pinball Thrillride
  • +
  • A-10 Tank Killer
  • +
  • Actua Soccer
  • +
  • Adventure Pinball Forgotten Island (demo)
  • +
  • Aladdin
  • +
  • Alien vs Predator
  • +
  • Alien vs Predator 2 (demo)
  • +
  • All New World of Lemmings
  • +
  • Alone in the Dark
  • +
  • Alone in the Dark : The New Nightmare (demo)
  • +
  • Anachronox
  • +
  • Arkanoid
  • +
  • Armoured Fist 3 (demo)
  • +
  • Asteroids (1998)
  • +
  • B-17 Flying Fortress
  • +
  • Battle Chess
  • +
  • Battlezone
  • +
  • Battlezone II
  • +
  • Bejeweled
  • +
  • Beyond Castle Wolfenstein
  • +
  • Big Red Racing
  • +
  • Bio Menace
  • +
  • Black & White
  • +
  • Brix
  • +
  • Bugs Bunny Lost In Time (demo)
  • +
  • Cannon Fodder 2
  • +
  • Carnivores 2
  • +
  • Civilization
  • +
  • Civilization for Windows
  • +
  • Claw
  • +
  • Clive Barker's Undying (demo)
  • +
  • Clockwiser
  • +
  • Command & Conquer : Red Alert
  • +
  • Command & Conquer : Red Alert 2
  • +
  • Command & Conquer : Tiberian Sun (demo)
  • +
  • Command & Conquer Renegade
  • +
  • Conquest
  • +
  • Corridor 7
  • +
  • Counter-Strike 2D
  • +
  • Crimson Skies (demo)
  • +
  • Croc
  • +
  • Curse of Monkey Island
  • +
  • Cutthroats (demo)
  • +
  • Daikatana
  • +
  • Dawn Patrol
  • +
  • Day of the Tentacle
  • +
  • Dance Dance Revolution
  • +
  • Dead Reckoning (demo)
  • +
  • Death Drome
  • +
  • Desert Strike
  • +
  • Digger
  • +
  • Dirt Track Racing (demo)
  • +
  • Disciples (demo)
  • +
  • Discworld II
  • +
  • Doom (v1.2)
  • +
  • Doom II (v1.666)
  • +
  • Double Dragon
  • +
  • Drakan (demo)
  • +
  • Duke Nukem 3D (v1.3D)
  • +
  • Dune
  • +
  • DX-Ball 2
  • +
  • Echelon
  • +
  • Ecstatica
  • +
  • Epic Pinball
  • +
  • Every Extend
  • +
  • Evolva (demo)
  • +
  • Expendable
  • +
  • Eye of the Beholder
  • +
  • Fallout Tactics (demo)
  • +
  • Final Fantasy VIII (demo)
  • +
  • Flashback
  • +
  • Flight Simulator 5
  • +
  • Frogger
  • +
  • Frontier : First Encounters
  • +
  • Gabriel Knight 3 (demo)
  • +
  • Giants : Citizen Kabuto
  • +
  • GLQuake
  • +
  • Grand Theft Auto 2
  • +
  • Half-Life
  • +
  • Halloween Harry
  • +
  • Heartlight
  • +
  • Hellbender
  • +
  • Hexen
  • +
  • High Heat Baseball 2002 (demo)
  • +
  • Hitch Hiker's Guide to the Galaxy
  • +
  • Hocus Pocus
  • +
  • Homeworld Cataclysm (demo)
  • +
  • Incoming
  • +
  • James Pond 2 : Robocod
  • +
  • Jazz Jackrabbit
  • +
  • Jazz Jackrabbit 2
  • +
  • Jill of the Jungle
  • +
  • King's Quest
  • +
  • King's Quest II
  • +
  • King's Quest III
  • +
  • Lemmings
  • +
  • Lemmings 2 : The Tribes
  • +
  • Lode Runner : The Legend Continues
  • +
  • Lotus III
  • +
  • Madden 2002 (demo)
  • +
  • Majesty (demo)
  • +
  • Maniac Mansion (enhanced)
  • +
  • Max Payne
  • +
  • MDK (Direct3D, USA release)
  • +
  • MechCommander 2
  • +
  • Mechwarrior 2
  • +
  • Mechwarrior 3
  • +
  • Megaman Legends
  • +
  • Metal Gear Solid
  • +
  • Microsoft Arcade
  • +
  • Microsoft Golf 99 (demo)
  • +
  • Midtown Madness 2 (demo)
  • +
  • Monaco Grand Prix (demo)
  • +
  • Monkey Island 2
  • +
  • Monster Bash
  • +
  • Monster Truck Madness
  • +
  • Mortal Kombat
  • +
  • Mortal Kombat 2
  • +
  • Mortal Kombat 3
  • +
  • Motorcross Madness (demo)
  • +
  • Mystic Towers
  • +
  • Nascar Heat
  • +
  • Need for Speed II SE
  • +
  • Need for Speed III
  • +
  • Need for Speed : High Stakes
  • +
  • NHL 2001 (demo)
  • +
  • No One Lives Forever
  • +
  • Oddworld : Abe's Exoddus
  • +
  • One Must Fall 2097
  • +
  • Oni
  • +
  • Outlaws
  • +
  • Pacific Strike
  • +
  • Pacman Adventures in Time (demo)
  • +
  • Pharoah (demo)
  • +
  • Pinball Fantasies
  • +
  • Pinball Illusions
  • +
  • Police Quest
  • +
  • Police Quest 2
  • +
  • Porrasturvat
  • +
  • Power Drive
  • +
  • Prince of Persia
  • +
  • Prince of Persia 3D (demo)
  • +
  • Pro Pinball : The Web
  • +
  • Psycho Pinball
  • +
  • Quake
  • +
  • Quake II
  • +
  • Quake III Arena
  • +
  • Rayman 2 (demo)
  • +
  • Red Faction
  • +
  • Redline Racer
  • +
  • Rise of the Triad (v1.2)
  • +
  • Screamer
  • +
  • Sega Rally 2 (demo)
  • +
  • Sensible World of Soccer
  • +
  • Settlers 3 (demo)
  • +
  • Severance : Blade of Darkness (demo)
  • +
  • Shadow Company (demo)
  • +
  • Shadow Warrior
  • +
  • Shadowman (demo)
  • +
  • Sid Meier's Alien Crossfire (demo)
  • +
  • SimCity 2000
  • +
  • SimCity Classic
  • +
  • SimTower
  • +
  • Sink or Swim
  • +
  • Soldat (1.0.5)
  • +
  • Sonic CD
  • +
  • Space Simulator
  • +
  • Space Strike
  • +
  • Spider-Man (demo)
  • +
  • Springy Madness
  • +
  • Star Trek Hidden Evil (demo)
  • +
  • Star Trek Voyager Elite Force
  • +
  • Star Wars Jedi Academy
  • +
  • Starfleet Command 2 (demo)
  • +
  • Stargunner
  • +
  • Starlancer (demo)
  • +
  • Steel Beasts (demo)
  • +
  • Stunt Island
  • +
  • SWAT 3 Elite Edition (demo)
  • +
  • Syndicate
  • +
  • System Shock
  • +
  • Tanktics (demo)
  • +
  • Terminal Velocity
  • +
  • The Dig
  • +
  • The Humans
  • +
  • The Labyrinth (RealArcade version)
  • +
  • The Lost Vikings
  • +
  • The Ultimate Doom (v1.9)
  • +
  • Theme Hospital
  • +
  • Theme Park
  • +
  • Tomb Raider
  • +
  • Tomb Raider II
  • +
  • Tomb Raider The Last Revelation (demo)
  • +
  • Tony Hawk's Pro Skater 2
  • +
  • Transport Tycoon
  • +
  • Transport Tycoon Deluxe
  • +
  • Tropico (demo)
  • +
  • Turrican 2
  • +
  • UFO : Enemy Unknown
  • +
  • Ultimate Ride (demo)
  • +
  • Unreal
  • +
  • Unreal Tournament
  • +
  • Unreal Tournament 2004 (Direct3D)
  • +
  • Wacky Wheels
  • +
  • Warlords Battlecry (demo)
  • +
  • Wheel of Time (demo)
  • +
  • Wing Commander
  • +
  • Wing Commander : Privateer
  • +
  • Wizkid
  • +
  • Wolfenstein 3D
  • +
  • World War III : Black Gold (demo)
  • +
  • Worms
  • +
  • Worms Armageddon
  • +
  • X-Com : Terror From The Deep
  • +
  • Xargon
  • +
  • Z : Steel Soldiers (demo)
  • +
  • Zak McKracken
  • +
  • Zone 66
  • +
+

Demos

+
    +
  • Cascada - Cronologia
  • +
  • Coma - Paimen
  • +
  • Complex - Cyboman 2
  • +
  • Complex - Dope
  • +
  • EMF - Verses
  • +
  • Exceed - Heaven 7
  • +
  • Future Crew - Second Reality
  • +
  • Gazebo - Cyboman
  • +
  • Halcyon - Lifeforms
  • +
  • Iguana - Heartquake
  • +
  • Impact Studios - Legend
  • +
  • Impact Studios - Project Angel
  • +
  • KFMF - Dance, Move, Shake
  • +
  • KFMF - Trip
  • +
  • Logic Design - Fashion
  • +
  • Majic 12 - Show
  • +
  • Majic 12 - Wish
  • +
  • Megabusters - Hellraiser
  • +
  • Orange - x14
  • +
  • Renaissance - Amnesia
  • +
  • Skull - Putre Faction
  • +
  • Tran - Ambience (flickery)
  • +
  • Tran - Luminati (flickery)
  • +
  • Tran - Timeless
  • +
  • Triton - Crystal Dream
  • +
  • Triton - Crystal Dream 2
  • +
  • Ultraforce - Coldcut
  • +
  • Ultraforce - Vector Demo
  • +
  • Valhalla - Solstice
  • +
  • Witan - Witan House
  • +
+

Emulators

+
    +
  • Beebem v1.02
  • +
  • BeebInC v0.99f
  • +
  • CPE v5.2i
  • +
  • DOSBox 0.74-3
  • +
  • Fellow 0.33
  • +
  • KGen98 v0.4b
  • +
  • PaCifiST v0.48
  • +
  • SNES9x v0.96
  • +
  • UltraHLE v1.0.0
  • +
  • vMac v0.1.9.1
  • +
  • ZSNES v0.800c
  • +
+ +